Whamcloud - gitweb
LU-1347 build: remove the vim/emacs modelines
[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, int *err)
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), M_TEMP, M_WAITOK);
112         if (fp == NULL) {
113                 if (err != NULL)
114                         *err = -ENOMEM;
115                 return NULL;
116         }
117         fp->f_flags = FFLAGS(uflags);
118         fp->f_ctxt = vfs_context_create(NULL);
119
120         if ((error = vnode_open(filename, fp->f_flags, 
121                                 mode, 0, &vp, fp->f_ctxt))){
122                 if (err != NULL)
123                         *err = -error;
124                 _FREE(fp, M_TEMP);
125         } else {
126                 if (err != NULL)
127                         *err = 0;
128                 fp->f_vp = vp;
129         }
130
131         return fp;
132 }
133
134 int
135 kern_file_close(struct cfs_kern_file *fp)
136 {
137         vnode_close(fp->f_vp, fp->f_flags, fp->f_ctxt);
138         vfs_context_rele(fp->f_ctxt);
139         _FREE(fp, M_TEMP);
140
141         return 0;
142 }
143
144 int
145 kern_file_read(struct cfs_kern_file *fp, void *buf, size_t nbytes, loff_t *pos)
146 {
147         struct proc *p = current_proc();
148         int     resid;
149         int     error;
150
151         assert(buf != NULL);
152         assert(fp != NULL && fp->f_vp != NULL);
153
154         error = vn_rdwr(UIO_READ, fp->f_vp, buf, nbytes, *pos, 
155                         UIO_SYSSPACE32, 0, vfs_context_ucred(fp->f_ctxt), &resid, p);
156         if ((error) || (nbytes == resid)) {
157                 if (!error)
158                         error = -EINVAL;
159                 return error;
160         }
161         *pos += nbytes - resid;
162
163         return (int)(nbytes - resid);
164 }
165
166 int
167 kern_file_write(struct cfs_kern_file *fp, void *buf, size_t nbytes, loff_t *pos)
168 {
169         struct proc *p = current_proc();
170         int     resid;
171         int     error;
172
173         assert(buf != NULL);
174         assert(fp != NULL && fp->f_vp != NULL);
175
176         error = vn_rdwr(UIO_WRITE, fp->f_vp, buf, nbytes, *pos, 
177                         UIO_SYSSPACE32, 0, vfs_context_ucred(fp->f_ctxt), &resid, p);
178         if ((error) || (nbytes == resid)) {
179                 if (!error)
180                         error = -EINVAL;
181                 return error;
182         }
183         *pos += nbytes - resid;
184
185         return (int)(nbytes - resid);
186
187 }
188
189 int
190 kern_file_sync (struct cfs_kern_file *fp)
191 {
192         return VNOP_FSYNC(fp->f_vp, MNT_WAIT, fp->f_ctxt);
193 }
194
195 #else  /* !__DARWIN8__ */
196
197 int
198 kern_file_size(struct file *fp, off_t *size)
199 {
200         struct vnode *vp = (struct vnode *)fp->f_data;
201         struct stat sb;
202         int     rc;
203
204         rc = vn_stat(vp, &sb, current_proc());
205         if (rc) {
206                 *size = 0;
207                 return rc;
208         }
209         *size = sb.st_size;
210         return 0;
211 }
212
213 cfs_file_t *
214 kern_file_open(const char * filename, int flags, int mode, int *err)
215 {
216         struct nameidata nd;
217         cfs_file_t      *fp;
218         register struct vnode   *vp;
219         int                     rc;
220         extern struct fileops   vnops;
221         extern int nfiles;
222         CFS_DECL_CONE_DATA;
223
224         CFS_CONE_IN;
225         nfiles++;
226         MALLOC_ZONE(fp, cfs_file_t *, sizeof(cfs_file_t), M_FILE, M_WAITOK|M_ZERO);
227         bzero(fp, sizeof(cfs_file_t));
228         fp->f_count = 1;
229         LIST_CIRCLE(fp, f_list);
230         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, (char *)filename, current_proc());
231         if ((rc = vn_open(&nd, flags, mode)) != 0){
232                 printf("filp_open failed at (%d)\n", rc);
233                 if (err != NULL)
234                         *err = rc;
235                 FREE_ZONE(fp, sizeof *fp, M_FILE);
236                 CFS_CONE_EX;
237                 return NULL;
238         }
239         vp = nd.ni_vp;
240         fp->f_flag = flags & FMASK;
241         fp->f_type = DTYPE_VNODE;
242         fp->f_ops = &vnops;
243         fp->f_data = (caddr_t)vp;
244         fp->f_cred = current_proc()->p_ucred;
245         /*
246          * Hold cred to increase reference
247          */
248         crhold(fp->f_cred);
249         /*
250          * vnode is locked inside vn_open for lookup,
251          * we should release the lock before return
252          */
253         VOP_UNLOCK(vp, 0, current_proc());
254         CFS_CONE_EX;
255
256         return fp;
257 }
258
259 static int
260 frele_internal(cfs_file_t *fp)
261 {
262         if (fp->f_count == (short)0xffff)
263                 panic("frele of lustre: stale");
264         if (--fp->f_count < 0)
265                 panic("frele of lustre: count < 0");
266         return ((int)fp->f_count);
267 }
268
269 int
270 kern_file_close (cfs_file_t *fp)
271 {
272         struct vnode    *vp;
273         CFS_DECL_CONE_DATA;
274         
275         if (fp == NULL)
276                 return 0;
277
278         CFS_CONE_IN;
279         if (frele_internal(fp) > 0)
280                 goto out;
281         vp = (struct vnode *)fp->f_data;
282         (void )vn_close(vp, fp->f_flag, fp->f_cred, current_proc());
283         /*
284          * ffree(fp);
285          * Dont use ffree to release fp!!!!
286          * ffree will call LIST_REMOVE(fp),
287          * but fp is not in any list, this will
288          * cause kernel panic
289          */
290         struct ucred *cred;
291         cred = fp->f_cred;
292         if (cred != NOCRED) {
293                 fp->f_cred = NOCRED;
294                 crfree(cred);
295         }
296         extern int nfiles;
297         nfiles--;
298         memset(fp, 0xff, sizeof *fp);
299         fp->f_count = (short)0xffff;
300         FREE_ZONE(fp, sizeof *fp, M_FILE);
301 out:
302         CFS_CONE_EX;
303         return 0;
304 }
305
306 extern void bwillwrite(void);
307
308 /*
309  * Write buffer to filp inside kernel
310  */
311 int
312 kern_file_write (cfs_file_t *fp, void *buf, size_t nbyte, loff_t *pos)
313 {
314         struct uio auio;
315         struct iovec aiov;
316         struct proc *p = current_proc();
317         long cnt, error = 0;
318         int flags = 0;
319         CFS_DECL_CONE_DATA;
320
321         aiov.iov_base = (void *)(uintptr_t)buf;
322         aiov.iov_len = nbyte;
323         auio.uio_iov = &aiov;
324         auio.uio_iovcnt = 1;
325         if (pos != NULL) {
326                 auio.uio_offset = *pos;
327                 /* 
328                  * Liang: If don't set FOF_OFFSET, vn_write()
329                  * will use fp->f_offset as the the real offset.
330                  * Same in vn_read()
331                  */
332                 flags |= FOF_OFFSET;
333         } else
334                 auio.uio_offset = (off_t)-1;
335         if (nbyte > INT_MAX)
336                 return (EINVAL);
337         auio.uio_resid = nbyte;
338         auio.uio_rw = UIO_WRITE;
339         auio.uio_segflg = UIO_SYSSPACE;
340         auio.uio_procp = p;
341
342         cnt = nbyte;
343         CFS_CONE_IN;
344         if (fp->f_type == DTYPE_VNODE)
345                 bwillwrite();   /* empty stuff now */
346         if ((error = fo_write(fp, &auio, fp->f_cred, flags, p))) {
347                 if (auio.uio_resid != cnt && (error == ERESTART ||\
348                     error == EINTR || error == EWOULDBLOCK))
349                         error = 0;
350                 /* The socket layer handles SIGPIPE */
351                 if (error == EPIPE && fp->f_type != DTYPE_SOCKET)
352                         psignal(p, SIGPIPE);
353         }
354         CFS_CONE_EX;
355         if (error != 0)
356                 cnt = -error;
357         else
358                 cnt -= auio.uio_resid;
359         if (pos != NULL)
360                 *pos += cnt;
361         return cnt;
362 }
363
364 /*
365  * Read from filp inside kernel
366  */
367 int
368 kern_file_read (cfs_file_t *fp, void *buf, size_t nbyte, loff_t *pos)
369 {
370         struct uio auio;
371         struct iovec aiov;
372         struct proc *p = current_proc();
373         long cnt, error = 0;
374         int  flags = 0;
375         CFS_DECL_CONE_DATA;
376
377         aiov.iov_base = (caddr_t)buf;
378         aiov.iov_len = nbyte;
379         auio.uio_iov = &aiov;
380         auio.uio_iovcnt = 1;
381         if (pos != NULL) {
382                 auio.uio_offset = *pos;
383                 flags |= FOF_OFFSET;
384         } else
385                 auio.uio_offset = (off_t)-1;
386         if (nbyte > INT_MAX)
387                 return (EINVAL);
388         auio.uio_resid = nbyte;
389         auio.uio_rw = UIO_READ;
390         auio.uio_segflg = UIO_SYSSPACE;
391         auio.uio_procp = p;
392
393         cnt = nbyte;
394         CFS_CONE_IN;
395         if ((error = fo_read(fp, &auio, fp->f_cred, flags, p)) != 0) {
396                 if (auio.uio_resid != cnt && (error == ERESTART ||
397                     error == EINTR || error == EWOULDBLOCK))
398                         error = 0;
399         }
400         CFS_CONE_EX;
401         if (error != 0)
402                 cnt = -error;
403         else
404                 cnt -= auio.uio_resid;
405         if (pos != NULL)
406                 *pos += cnt;
407
408         return cnt;
409 }
410
411 int
412 kern_file_sync (cfs_file_t *fp)
413 {
414         struct vnode *vp = (struct vnode *)fp->f_data;
415         struct proc *p = current_proc();
416         int error = 0;
417         CFS_DECL_CONE_DATA;
418         
419         CFS_CONE_IN;
420         if (fref(fp) == -1) {
421                 CFS_CONE_EX;
422                 return (-EBADF);
423         }
424         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
425         error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
426         VOP_UNLOCK(vp, 0, p);
427         frele(fp);
428         CFS_CONE_EX;
429
430         return error;
431 }
432
433 #endif /* !__DARWIN8__ */
434
435 struct posix_acl *posix_acl_alloc(int count, int flags)
436 {
437         static struct posix_acl acl;
438         return &acl;
439 }
440
441 /*
442  * XXX Liang: I've not converted all of them, 
443  * more is needed? 
444  */
445 int cfs_oflags2univ(int flags) 
446 {
447         int f;
448
449         f = flags & O_NOACCESS;
450         f |= (flags & O_CREAT) ? CFS_O_CREAT: 0;
451         f |= (flags & O_TRUNC) ? CFS_O_TRUNC: 0;
452         f |= (flags & O_EXCL) ? CFS_O_EXCL: 0;
453         f |= (flags & O_NONBLOCK) ? CFS_O_NONBLOCK: 0;
454         f |= (flags & O_APPEND) ? CFS_O_APPEND: 0;
455         f |= (flags & O_NOFOLLOW) ? CFS_O_NOFOLLOW: 0;
456         f |= (flags & O_SYNC)? CFS_O_SYNC: 0;
457         return f;
458 }
459
460 /*
461  * XXX Liang: we don't need it in OSX.
462  * But it should be implemented anyway.
463  */
464 int cfs_univ2oflags(int flags)
465 {
466         return flags;
467 }