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