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