Whamcloud - gitweb
6fce8d54687783b91dcc18ba0e9bbd6783409bb9
[fs/lustre-release.git] / libcfs / libcfs / darwin / darwin-fs.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  * Author: Phil Schwan <phil@clusterfs.com>
6  *
7  * This file is part of Lustre, http://www.lustre.org.
8  *
9  * Lustre is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU General Public
11  * License as published by the Free Software Foundation.
12  *
13  * Lustre is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Lustre; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * Darwin porting library
23  * Make things easy to port
24  */
25 #include <mach/mach_types.h>
26 #include <string.h>
27 #include <sys/file.h>
28 #include <sys/malloc.h>
29 #include <sys/conf.h>
30 #include <sys/mount.h>
31 #include <sys/uio.h>
32 #include <sys/filedesc.h>
33 #include <sys/namei.h>
34
35 #define DEBUG_SUBSYSTEM S_LNET
36
37 #include <libcfs/libcfs.h>
38 #include <libcfs/kp30.h>
39
40 /*
41  * Kernel APIs for file system in xnu
42  *
43  * Public functions
44  */
45
46 #ifdef __DARWIN8__
47 #include <sys/vnode.h>
48
49 extern int vn_rdwr(enum uio_rw, vnode_t, caddr_t, int, off_t, enum uio_seg, int, kauth_cred_t, int *, proc_t);
50
51 /* vnode_size() is not exported */
52 static errno_t
53 vnode_size(vnode_t vp, off_t *sizep, vfs_context_t ctx)
54 {
55         struct vnode_attr       va;
56         int                     error; 
57         
58         VATTR_INIT(&va);
59         VATTR_WANTED(&va, va_data_size);
60         error = vnode_getattr(vp, &va, ctx);
61         if (!error)
62                 *sizep = va.va_data_size;
63         return(error);
64 }
65
66 /*
67  * XXX Liang:
68  *
69  * kern_file_*() are not safe for multi-threads now,
70  * however, we need them only for tracefiled, so it's
71  * not so important to implement for MT.
72  */
73 int
74 kern_file_size(struct cfs_kern_file *fp, off_t *psize) 
75 {
76         int     error;
77         off_t   size;
78
79         error = vnode_size(fp->f_vp, &size, fp->f_ctxt);
80         if (error) 
81                 return error;
82
83         if (psize)
84                 *psize = size;
85         return 0;
86 }
87
88 struct cfs_kern_file *
89 kern_file_open(const char * filename, int uflags, int mode, int *err)
90 {
91         struct cfs_kern_file    *fp;
92         vnode_t         vp;
93         int             error;
94
95         fp = (struct cfs_kern_file *)_MALLOC(sizeof(struct cfs_kern_file), M_TEMP, M_WAITOK);
96         if (fp == NULL) {
97                 if (err != NULL)
98                         *err = -ENOMEM;
99                 return NULL;
100         }
101         fp->f_flags = FFLAGS(uflags);
102         fp->f_ctxt = vfs_context_create(NULL);
103
104         if ((error = vnode_open(filename, fp->f_flags, 
105                                 mode, 0, &vp, fp->f_ctxt))){
106                 if (err != NULL)
107                         *err = -error;
108                 _FREE(fp, M_TEMP);
109         } else {
110                 if (err != NULL)
111                         *err = 0;
112                 fp->f_vp = vp;
113         }
114
115         return fp;
116 }
117
118 int
119 kern_file_close(struct cfs_kern_file *fp)
120 {
121         vnode_close(fp->f_vp, fp->f_flags, fp->f_ctxt);
122         vfs_context_rele(fp->f_ctxt);
123         _FREE(fp, M_TEMP);
124
125         return 0;
126 }
127
128 int
129 kern_file_read(struct cfs_kern_file *fp, void *buf, size_t nbytes, loff_t *pos)
130 {
131         struct proc *p = current_proc();
132         int     resid;
133         int     error;
134
135         assert(buf != NULL);
136         assert(fp != NULL && fp->f_vp != NULL);
137
138         error = vn_rdwr(UIO_READ, fp->f_vp, buf, nbytes, *pos, 
139                         UIO_SYSSPACE32, 0, vfs_context_ucred(fp->f_ctxt), &resid, p);
140         if ((error) || (nbytes == resid)) {
141                 if (!error)
142                         error = -EINVAL;
143                 return error;
144         }
145         *pos += nbytes - resid;
146
147         return (int)(nbytes - resid);
148 }
149
150 int
151 kern_file_write(struct cfs_kern_file *fp, void *buf, size_t nbytes, loff_t *pos)
152 {
153         struct proc *p = current_proc();
154         int     resid;
155         int     error;
156
157         assert(buf != NULL);
158         assert(fp != NULL && fp->f_vp != NULL);
159
160         error = vn_rdwr(UIO_WRITE, fp->f_vp, buf, nbytes, *pos, 
161                         UIO_SYSSPACE32, 0, vfs_context_ucred(fp->f_ctxt), &resid, p);
162         if ((error) || (nbytes == resid)) {
163                 if (!error)
164                         error = -EINVAL;
165                 return error;
166         }
167         *pos += nbytes - resid;
168
169         return (int)(nbytes - resid);
170
171 }
172
173 int
174 kern_file_sync (struct cfs_kern_file *fp)
175 {
176         return VNOP_FSYNC(fp->f_vp, MNT_WAIT, fp->f_ctxt);
177 }
178
179 #else  /* !__DARWIN8__ */
180
181 int
182 kern_file_size(struct file *fp, off_t *size)
183 {
184         struct vnode *vp = (struct vnode *)fp->f_data;
185         struct stat sb;
186         int     rc;
187
188         rc = vn_stat(vp, &sb, current_proc());
189         if (rc) {
190                 *size = 0;
191                 return rc;
192         }
193         *size = sb.st_size;
194         return 0;
195 }
196
197 cfs_file_t *
198 kern_file_open(const char * filename, int flags, int mode, int *err)
199 {
200         struct nameidata nd;
201         cfs_file_t      *fp;
202         register struct vnode   *vp;
203         int                     rc;
204         extern struct fileops   vnops;
205         extern int nfiles;
206         CFS_DECL_CONE_DATA;
207
208         CFS_CONE_IN;
209         nfiles++;
210         MALLOC_ZONE(fp, cfs_file_t *, sizeof(cfs_file_t), M_FILE, M_WAITOK|M_ZERO);
211         bzero(fp, sizeof(cfs_file_t));
212         fp->f_count = 1;
213         LIST_CIRCLE(fp, f_list);
214         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, (char *)filename, current_proc());
215         if ((rc = vn_open(&nd, flags, mode)) != 0){
216                 printf("filp_open failed at (%d)\n", rc);
217                 if (err != NULL)
218                         *err = rc;
219                 FREE_ZONE(fp, sizeof *fp, M_FILE);
220                 CFS_CONE_EX;
221                 return NULL;
222         }
223         vp = nd.ni_vp;
224         fp->f_flag = flags & FMASK;
225         fp->f_type = DTYPE_VNODE;
226         fp->f_ops = &vnops;
227         fp->f_data = (caddr_t)vp;
228         fp->f_cred = current_proc()->p_ucred;
229         /*
230          * Hold cred to increase reference
231          */
232         crhold(fp->f_cred);
233         /*
234          * vnode is locked inside vn_open for lookup,
235          * we should release the lock before return
236          */
237         VOP_UNLOCK(vp, 0, current_proc());
238         CFS_CONE_EX;
239
240         return fp;
241 }
242
243 static int
244 frele_internal(cfs_file_t *fp)
245 {
246         if (fp->f_count == (short)0xffff)
247                 panic("frele of lustre: stale");
248         if (--fp->f_count < 0)
249                 panic("frele of lustre: count < 0");
250         return ((int)fp->f_count);
251 }
252
253 int
254 kern_file_close (cfs_file_t *fp)
255 {
256         struct vnode    *vp;
257         CFS_DECL_CONE_DATA;
258         
259         if (fp == NULL)
260                 return 0;
261
262         CFS_CONE_IN;
263         if (frele_internal(fp) > 0)
264                 goto out;
265         vp = (struct vnode *)fp->f_data;
266         (void )vn_close(vp, fp->f_flag, fp->f_cred, current_proc());
267         /*
268          * ffree(fp);
269          * Dont use ffree to release fp!!!!
270          * ffree will call LIST_REMOVE(fp),
271          * but fp is not in any list, this will
272          * cause kernel panic
273          */
274         struct ucred *cred;
275         cred = fp->f_cred;
276         if (cred != NOCRED) {
277                 fp->f_cred = NOCRED;
278                 crfree(cred);
279         }
280         extern int nfiles;
281         nfiles--;
282         memset(fp, 0xff, sizeof *fp);
283         fp->f_count = (short)0xffff;
284         FREE_ZONE(fp, sizeof *fp, M_FILE);
285 out:
286         CFS_CONE_EX;
287         return 0;
288 }
289
290 extern void bwillwrite(void);
291
292 /*
293  * Write buffer to filp inside kernel
294  */
295 int
296 kern_file_write (cfs_file_t *fp, void *buf, size_t nbyte, loff_t *pos)
297 {
298         struct uio auio;
299         struct iovec aiov;
300         struct proc *p = current_proc();
301         long cnt, error = 0;
302         int flags = 0;
303         CFS_DECL_CONE_DATA;
304
305         aiov.iov_base = (void *)(uintptr_t)buf;
306         aiov.iov_len = nbyte;
307         auio.uio_iov = &aiov;
308         auio.uio_iovcnt = 1;
309         if (pos != NULL) {
310                 auio.uio_offset = *pos;
311                 /* 
312                  * Liang: If don't set FOF_OFFSET, vn_write()
313                  * will use fp->f_offset as the the real offset.
314                  * Same in vn_read()
315                  */
316                 flags |= FOF_OFFSET;
317         } else
318                 auio.uio_offset = (off_t)-1;
319         if (nbyte > INT_MAX)
320                 return (EINVAL);
321         auio.uio_resid = nbyte;
322         auio.uio_rw = UIO_WRITE;
323         auio.uio_segflg = UIO_SYSSPACE;
324         auio.uio_procp = p;
325
326         cnt = nbyte;
327         CFS_CONE_IN;
328         if (fp->f_type == DTYPE_VNODE)
329                 bwillwrite();   /* empty stuff now */
330         if ((error = fo_write(fp, &auio, fp->f_cred, flags, p))) {
331                 if (auio.uio_resid != cnt && (error == ERESTART ||\
332                     error == EINTR || error == EWOULDBLOCK))
333                         error = 0;
334                 /* The socket layer handles SIGPIPE */
335                 if (error == EPIPE && fp->f_type != DTYPE_SOCKET)
336                         psignal(p, SIGPIPE);
337         }
338         CFS_CONE_EX;
339         if (error != 0)
340                 cnt = -error;
341         else
342                 cnt -= auio.uio_resid;
343         if (pos != NULL)
344                 *pos += cnt;
345         return cnt;
346 }
347
348 /*
349  * Read from filp inside kernel
350  */
351 int
352 kern_file_read (cfs_file_t *fp, void *buf, size_t nbyte, loff_t *pos)
353 {
354         struct uio auio;
355         struct iovec aiov;
356         struct proc *p = current_proc();
357         long cnt, error = 0;
358         int  flags = 0;
359         CFS_DECL_CONE_DATA;
360
361         aiov.iov_base = (caddr_t)buf;
362         aiov.iov_len = nbyte;
363         auio.uio_iov = &aiov;
364         auio.uio_iovcnt = 1;
365         if (pos != NULL) {
366                 auio.uio_offset = *pos;
367                 flags |= FOF_OFFSET;
368         } else
369                 auio.uio_offset = (off_t)-1;
370         if (nbyte > INT_MAX)
371                 return (EINVAL);
372         auio.uio_resid = nbyte;
373         auio.uio_rw = UIO_READ;
374         auio.uio_segflg = UIO_SYSSPACE;
375         auio.uio_procp = p;
376
377         cnt = nbyte;
378         CFS_CONE_IN;
379         if ((error = fo_read(fp, &auio, fp->f_cred, flags, p)) != 0) {
380                 if (auio.uio_resid != cnt && (error == ERESTART ||
381                     error == EINTR || error == EWOULDBLOCK))
382                         error = 0;
383         }
384         CFS_CONE_EX;
385         if (error != 0)
386                 cnt = -error;
387         else
388                 cnt -= auio.uio_resid;
389         if (pos != NULL)
390                 *pos += cnt;
391
392         return cnt;
393 }
394
395 int
396 kern_file_sync (cfs_file_t *fp)
397 {
398         struct vnode *vp = (struct vnode *)fp->f_data;
399         struct proc *p = current_proc();
400         int error = 0;
401         CFS_DECL_CONE_DATA;
402         
403         CFS_CONE_IN;
404         if (fref(fp) == -1) {
405                 CFS_CONE_EX;
406                 return (-EBADF);
407         }
408         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
409         error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
410         VOP_UNLOCK(vp, 0, p);
411         frele(fp);
412         CFS_CONE_EX;
413
414         return error;
415 }
416
417 #endif /* !__DARWIN8__ */
418
419 struct posix_acl *posix_acl_alloc(int count, int flags)
420 {
421         static struct posix_acl acl;
422         return &acl;
423 }
424
425 /*
426  * XXX Liang: I've not converted all of them, 
427  * more is needed? 
428  */
429 int cfs_oflags2univ(int flags) 
430 {
431         int f;
432
433         f = flags & O_ACCMODE;
434         f |= (flags & O_CREAT) ? CFS_O_CREAT: 0;
435         f |= (flags & O_TRUNC) ? CFS_O_TRUNC: 0;
436         f |= (flags & O_EXCL) ? CFS_O_EXCL: 0;
437         f |= (flags & O_NONBLOCK) ? CFS_O_NONBLOCK: 0;
438         f |= (flags & O_APPEND) ? CFS_O_APPEND: 0;
439         f |= (flags & O_NOFOLLOW) ? CFS_O_NOFOLLOW: 0;
440         f |= (flags & O_SYNC)? CFS_O_SYNC: 0;
441         return f;
442 }
443
444 /*
445  * XXX Liang: we don't need it in OSX.
446  * But it should be implemented anyway.
447  */
448 int cfs_univ2oflags(int flags)
449 {
450         return flags;
451 }