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