macos bulkstat support
[openafs.git] / src / afs / DARWIN / osi_vfsops.c
1 /*
2  * Portions Copyright (c) 2003 Apple Computer, Inc.  All rights reserved.
3  */
4 #include <afsconfig.h>
5 #include <afs/param.h>
6
7
8 #include <afs/sysincludes.h>    /* Standard vendor system headers */
9 #include <afsincludes.h>        /* Afs-based standard headers */
10 #include <afs/afs_stats.h>      /* statistics */
11 #include <sys/malloc.h>
12 #include <sys/namei.h>
13 #include <sys/conf.h>
14 #ifndef AFS_DARWIN80_ENV
15 #include <sys/syscall.h>
16 #endif
17 #include <sys/sysctl.h>
18 #include "../afs/sysctl.h"
19
20 #ifndef M_UFSMNT
21 #define M_UFSMNT M_TEMP /* DARWIN80 MALLOC doesn't look at the type anyway */
22 #endif
23
24 struct vcache *afs_globalVp = 0;
25 struct mount *afs_globalVFS = 0;
26 int afs_vfs_typenum;
27
28 int
29 afs_quotactl()
30 {
31     return EOPNOTSUPP;
32 }
33
34 int
35 afs_fhtovp(mp, fhp, vpp)
36      struct mount *mp;
37      struct fid *fhp;
38      struct vnode **vpp;
39 {
40
41     return (EINVAL);
42 }
43
44 int
45 afs_vptofh(vp, fhp)
46      struct vnode *vp;
47      struct fid *fhp;
48 {
49
50     return (EINVAL);
51 }
52
53 #ifdef AFS_DARWIN80_ENV
54 #define CTX_TYPE vfs_context_t
55 #define CTX_PROC_CONVERT(C) vfs_context_proc((C))
56 #define STATFS_TYPE struct vfsstatfs
57 #else
58 #define CTX_TYPE struct proc *
59 #define CTX_PROC_CONVERT(C) (C)
60 #define STATFS_TYPE struct statfs
61 #define vfs_statfs(VFS) &(VFS)->mnt_stat
62 #endif
63 #define PROC_DECL(out,in) struct proc *out = CTX_PROC_CONVERT(in)
64
65 int
66 afs_start(mp, flags, p)
67      struct mount *mp;
68      int flags;
69      CTX_TYPE p;
70 {
71     return (0);                 /* nothing to do. ? */
72 }
73
74 int
75 afs_statfs(struct mount *mp, STATFS_TYPE *abp, CTX_TYPE ctx);
76 #ifdef AFS_DARWIN80_ENV
77 int
78 afs_mount(mp, devvp, data, ctx)
79      register struct mount *mp;
80      vnode_t *devvp;
81      user_addr_t data;
82      vfs_context_t ctx;
83 #else
84 int
85 afs_mount(mp, path, data, ndp, ctx)
86      register struct mount *mp;
87      char *path;
88      caddr_t data;
89      struct nameidata *ndp;
90      CTX_TYPE ctx;
91 #endif
92 {
93     /* ndp contains the mounted-from device.  Just ignore it.
94      * we also don't care about our proc struct. */
95     size_t size;
96     int error;
97 #ifdef AFS_DARWIN80_ENV
98     struct vfsioattr ioattr;
99     /* vfs_statfs advertised as RO, but isn't */
100     /* new api will be needed to initialize this information (nfs needs to
101        set mntfromname too) */
102 #endif
103     STATFS_TYPE *mnt_stat = vfs_statfs(mp); 
104
105     if (vfs_isupdate(mp))
106         return EINVAL;
107
108     AFS_GLOCK();
109     AFS_STATCNT(afs_mount);
110
111     if (data == 0 && afs_globalVFS) {   /* Don't allow remounts. */
112         AFS_GUNLOCK();
113         return (EBUSY);
114     }
115
116     afs_globalVFS = mp;
117 #ifdef AFS_DARWIN80_ENV
118     vfs_ioattr(mp, &ioattr);
119     ioattr.io_devblocksize = (16 * 32768);
120     vfs_setioattr(mp, &ioattr);
121     /* f_iosize is handled in VFS_GETATTR */
122 #else
123     mp->vfs_bsize = 8192;
124     mp->mnt_stat.f_iosize = 8192;
125 #endif
126     vfs_getnewfsid(mp);
127
128 #ifndef AFS_DARWIN80_ENV
129     (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
130     memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
131 #endif
132     memset(mnt_stat->f_mntfromname, 0, MNAMELEN);
133
134     if (data == 0) {
135         strcpy(mnt_stat->f_mntfromname, "AFS");
136         /* null terminated string "AFS" will fit, just leave it be. */
137         vfs_setfsprivate(mp, NULL);
138     } else {
139         struct VenusFid *rootFid = NULL;
140         struct volume *tvp;
141         char volName[MNAMELEN];
142
143         (void)copyinstr(data, volName, MNAMELEN - 1, &size);
144         memset(volName + size, 0, MNAMELEN - size);
145
146         if (volName[0] == 0) {
147             strcpy(mnt_stat->f_mntfromname, "AFS");
148             vfs_setfsprivate(mp, &afs_rootFid);
149         } else {
150             struct cell *localcell = afs_GetPrimaryCell(READ_LOCK);
151             if (localcell == NULL) {
152                 AFS_GUNLOCK();
153                 return ENODEV;
154             }
155
156             /* Set the volume identifier to "AFS:volume.name" */
157             snprintf(mnt_stat->f_mntfromname, MNAMELEN - 1, "AFS:%s",
158                      volName);
159             tvp =
160                 afs_GetVolumeByName(volName, localcell->cellNum, 1,
161                                     (struct vrequest *)0, READ_LOCK);
162
163             if (tvp) {
164                 int volid = (tvp->roVol ? tvp->roVol : tvp->volume);
165                 MALLOC(rootFid, struct VenusFid *, sizeof(*rootFid), M_UFSMNT,
166                        M_WAITOK);
167                 rootFid->Cell = localcell->cellNum;
168                 rootFid->Fid.Volume = volid;
169                 rootFid->Fid.Vnode = 1;
170                 rootFid->Fid.Unique = 1;
171             } else {
172                 AFS_GUNLOCK();
173                 return ENODEV;
174             }
175
176             vfs_setfsprivate(mp, &rootFid);
177         }
178     }
179 #ifdef AFS_DARWIN80_ENV
180     afs_vfs_typenum=vfs_typenum(mp);
181     vfs_setauthopaque(mp);
182     vfs_setauthopaqueaccess(mp);
183 #else
184     strcpy(mp->mnt_stat.f_fstypename, "afs");
185 #endif
186     AFS_GUNLOCK();
187     (void)afs_statfs(mp, mnt_stat, ctx);
188     return 0;
189 }
190
191 int
192 afs_unmount(mp, flags, ctx)
193      struct mount *mp;
194      int flags;
195      CTX_TYPE ctx;
196 {
197     void *mdata = vfs_fsprivate(mp);
198     AFS_GLOCK();
199     AFS_STATCNT(afs_unmount);
200
201     if (mdata != (qaddr_t) - 1) {
202         if (mdata != NULL) {
203             vfs_setfsprivate(mp, (qaddr_t) - 1);
204             FREE(mdata, M_UFSMNT);
205         } else {
206             if (flags & MNT_FORCE) {
207                 if (afs_globalVp) {
208 #ifdef AFS_DARWIN80_ENV
209                     afs_PutVCache(afs_globalVp);
210 #else
211                     AFS_GUNLOCK();
212                     vrele(AFSTOV(afs_globalVp));
213                     AFS_GLOCK();
214 #endif
215                 }
216                 afs_globalVp = NULL;
217                 AFS_GUNLOCK();
218                 vflush(mp, NULLVP, FORCECLOSE/*0*/);
219                 AFS_GLOCK();
220                 afs_globalVFS = 0;
221                 afs_shutdown();
222             } else {
223                 AFS_GUNLOCK();
224                 return EBUSY;
225             }
226         }
227         vfs_clearflags(mp, MNT_LOCAL);
228     }
229
230     AFS_GUNLOCK();
231
232     return 0;
233 }
234
235 #ifdef AFS_DARWIN80_ENV
236 int
237 afs_root(struct mount *mp, struct vnode **vpp, vfs_context_t ctx)
238 #else
239 int
240 afs_root(struct mount *mp, struct vnode **vpp)
241 #endif
242 {
243     void *mdata = vfs_fsprivate(mp);
244     int error;
245     struct vrequest treq;
246     register struct vcache *tvp = 0;
247 #ifdef AFS_DARWIN80_ENV
248     struct ucred *cr = vfs_context_ucred(ctx);
249     int needref=0;
250 #else
251     struct proc *p = current_proc();
252     struct ucred _cr;
253     struct ucred *cr = &_cr;
254
255     pcred_readlock(p);
256     _cr = *p->p_cred->pc_ucred;
257     pcred_unlock(p);
258 #endif
259     AFS_GLOCK();
260     AFS_STATCNT(afs_root);
261     if (mdata == NULL && afs_globalVp
262         && (afs_globalVp->f.states & CStatd)) {
263         tvp = afs_globalVp;
264         error = 0;
265 #ifdef AFS_DARWIN80_ENV
266         needref=1;
267 #endif
268     } else if (mdata == (qaddr_t) - 1) {
269         error = ENOENT;
270     } else {
271         struct VenusFid *rootFid = (mdata == NULL)
272             ? &afs_rootFid : (struct VenusFid *)mdata;
273
274         if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
275             tvp = afs_GetVCache(rootFid, &treq, NULL, NULL);
276 #ifdef AFS_DARWIN80_ENV
277             if (tvp) {
278                 AFS_GUNLOCK();
279                 error = afs_darwin_finalizevnode(tvp, NULL, NULL, 1, 0);
280                 AFS_GLOCK();
281                 if (error)
282                    tvp = NULL;
283                 else 
284                    /* re-acquire the usecount that finalizevnode disposed of */
285                    vnode_ref(AFSTOV(tvp));
286             }
287 #endif
288             /* we really want this to stay around */
289             if (tvp) {
290                 if (mdata == NULL) {
291                     if (afs_globalVp) {
292                         afs_PutVCache(afs_globalVp);
293                         afs_globalVp = NULL;
294                     }
295                     afs_globalVp = tvp;
296 #ifdef AFS_DARWIN80_ENV
297                     needref=1;
298 #endif
299                 }
300             } else
301                 error = ENOENT;
302         }
303     }
304     if (tvp) {
305 #ifndef AFS_DARWIN80_ENV /* DARWIN80 caller does not need a usecount reference */
306         osi_vnhold(tvp, 0);
307         AFS_GUNLOCK();
308         vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, p);
309         AFS_GLOCK();
310 #endif
311 #ifdef AFS_DARWIN80_ENV
312         if (needref) /* this iocount is for the caller. the initial iocount
313                         is for the eventual afs_PutVCache. for mdata != null,
314                         there will not be a PutVCache, so the caller gets the
315                         initial (from GetVCache or finalizevnode) iocount*/
316            vnode_get(AFSTOV(tvp));
317 #endif
318         if (mdata == NULL) {
319             afs_globalVFS = mp;
320         }
321         *vpp = AFSTOV(tvp);
322 #ifndef AFS_DARWIN80_ENV 
323         AFSTOV(tvp)->v_flag |= VROOT;
324         AFSTOV(tvp)->v_vfsp = mp;
325 #endif
326     }
327
328     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
329                ICL_TYPE_INT32, error);
330     AFS_GUNLOCK();
331     return error;
332 }
333
334 #ifndef AFS_DARWIN80_ENV /* vget vfsop never had this prototype AFAIK */
335 int
336 afs_vget(mp, lfl, vp)
337      struct mount *mp;
338      struct vnode *vp;
339      int lfl;
340 {
341     int error;
342     //printf("vget called. help!\n");
343     if (vp->v_usecount < 0) {
344         vprint("bad usecount", vp);
345         panic("afs_vget");
346     }
347     error = vget(vp, lfl, current_proc());
348     if (!error)
349         insmntque(vp, mp);      /* take off free list */
350     return error;
351 }
352
353 int afs_vfs_vget(struct mount *mp, void *ino, struct vnode **vpp)
354 {
355    return ENOENT; /* cannot implement */
356 }
357
358 #endif
359
360 int
361 afs_statfs(struct mount *mp, STATFS_TYPE *abp, CTX_TYPE ctx)
362 {
363     STATFS_TYPE *sysstat = vfs_statfs(mp);
364     AFS_GLOCK();
365     AFS_STATCNT(afs_statfs);
366
367 #ifdef AFS_DARWIN80_ENV
368     abp->f_iosize = (256 * 1024);
369     abp->f_bsize = vfs_devblocksize(mp);
370 #else
371     abp->f_bsize = mp->vfs_bsize;
372     abp->f_iosize = mp->vfs_bsize;
373 #endif
374 #if 0
375     abp->f_type = MOUNT_AFS;
376 #endif
377
378     /* Fake a high number below to satisfy programs that use the statfs call
379      * to make sure that there's enough space in the device partition before
380      * storing something there.
381      */
382     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
383       abp->f_ffree = 0x7fffffff;
384
385     if (abp != sysstat) {
386         abp->f_fsid.val[0] = sysstat->f_fsid.val[0];
387         abp->f_fsid.val[1] = sysstat->f_fsid.val[1];
388 #ifndef AFS_DARWIN80_ENV
389         abp->f_type = vfs_typenum(mp);
390 #endif
391         memcpy((caddr_t) & abp->f_mntonname[0],
392                (caddr_t) sysstat->f_mntonname, MNAMELEN);
393         memcpy((caddr_t) & abp->f_mntfromname[0],
394                (caddr_t) sysstat->f_mntfromname, MNAMELEN);
395     }
396
397     AFS_GUNLOCK();
398     return 0;
399 }
400
401 #ifdef AFS_DARWIN80_ENV
402 int
403 afs_vfs_getattr(struct mount *mp, struct vfs_attr *outattrs,
404                 vfs_context_t context)
405 {
406     VFSATTR_RETURN(outattrs, f_bsize, vfs_devblocksize(mp));
407     VFSATTR_RETURN(outattrs, f_iosize, vfs_devblocksize(mp));
408     VFSATTR_RETURN(outattrs, f_blocks, 2000000);
409     VFSATTR_RETURN(outattrs, f_bfree, 2000000);
410     VFSATTR_RETURN(outattrs, f_bavail, 2000000);
411     VFSATTR_RETURN(outattrs, f_files, 2000000);
412     VFSATTR_RETURN(outattrs, f_ffree, 2000000);
413     if ( VFSATTR_IS_ACTIVE(outattrs, f_capabilities) )
414     {
415          vol_capabilities_attr_t *vcapattrptr;
416          vcapattrptr = &outattrs->f_capabilities;
417          vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
418                    VOL_CAP_FMT_SYMBOLICLINKS |
419                    VOL_CAP_FMT_HARDLINKS |
420                    VOL_CAP_FMT_ZERO_RUNS |
421                    VOL_CAP_FMT_CASE_SENSITIVE |
422                    VOL_CAP_FMT_CASE_PRESERVING |
423                    VOL_CAP_FMT_FAST_STATFS;
424          vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] = 
425                    VOL_CAP_INT_ADVLOCK | 
426                    VOL_CAP_INT_FLOCK;
427          vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
428          vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
429
430          /* Capabilities we know about: */
431          vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] =
432                  VOL_CAP_FMT_PERSISTENTOBJECTIDS |
433                  VOL_CAP_FMT_SYMBOLICLINKS |
434                  VOL_CAP_FMT_HARDLINKS |
435                  VOL_CAP_FMT_JOURNAL |
436                  VOL_CAP_FMT_JOURNAL_ACTIVE |
437                  VOL_CAP_FMT_NO_ROOT_TIMES |
438                  VOL_CAP_FMT_SPARSE_FILES |
439                  VOL_CAP_FMT_ZERO_RUNS |
440                  VOL_CAP_FMT_CASE_SENSITIVE |
441                  VOL_CAP_FMT_CASE_PRESERVING |
442                  VOL_CAP_FMT_FAST_STATFS;
443          vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] =
444                  VOL_CAP_INT_SEARCHFS |
445                  VOL_CAP_INT_ATTRLIST |
446                  VOL_CAP_INT_NFSEXPORT |
447                  VOL_CAP_INT_READDIRATTR |
448                  VOL_CAP_INT_EXCHANGEDATA |
449                  VOL_CAP_INT_COPYFILE |
450                  VOL_CAP_INT_ALLOCATE |
451                  VOL_CAP_INT_VOL_RENAME |
452                  VOL_CAP_INT_ADVLOCK |
453                  VOL_CAP_INT_FLOCK;
454          vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0;
455          vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0;
456              
457          VFSATTR_SET_SUPPORTED(outattrs, f_capabilities);
458     }
459     return 0;
460 }
461 #endif
462
463 #ifdef AFS_DARWIN80_ENV
464 int
465 afs_sync(mp, waitfor, ctx)
466      struct mount *mp;
467      int waitfor;
468      CTX_TYPE ctx;
469 #else
470 int
471 afs_sync(mp, waitfor, cred, p)
472      struct mount *mp;
473      int waitfor;
474      struct ucred *cred;
475      struct proc *p;
476 #endif
477 {
478     return 0;
479 }
480
481 u_int32_t afs_darwin_realmodes = 0;
482
483 #ifdef AFS_DARWIN80_ENV
484 int afs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, 
485                user_addr_t newp, size_t newlen, vfs_context_t context)
486 #else
487 int afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 
488                void *newp, size_t newlen, struct proc *p)
489 #endif
490 {
491     int error;
492
493     switch (name[0]) {
494     case AFS_SC_ALL:
495         /* nothing defined */
496         break;
497     case AFS_SC_DARWIN:
498         if (namelen < 3)
499             return ENOENT;
500         switch (name[1]) {
501         case AFS_SC_DARWIN_ALL:
502             switch (name[2]) {
503             case AFS_SC_DARWIN_ALL_REALMODES:
504 #ifdef AFS_DARWIN80_ENV
505                 if (oldp != USER_ADDR_NULL && oldlenp == NULL)
506                     return (EFAULT);
507                 if (oldp && *oldlenp < sizeof(u_int32_t))
508                     return (ENOMEM);
509                 if (newp && newlen != sizeof(u_int32_t))
510                     return (EINVAL);
511                 *oldlenp = sizeof(u_int32_t);
512                 if (oldp) {
513                     if ((error = copyout(&afs_darwin_realmodes,
514                                          oldp, sizeof(u_int32_t)))) {
515                         return error;
516                     }
517                 }
518                 if (newp)
519                     return copyin(newp, &afs_darwin_realmodes,
520                                   sizeof(u_int32_t));
521                 return 0;
522 #else
523                 return sysctl_int(oldp, oldlenp, newp, newlen,
524                                   &afs_darwin_realmodes);
525 #endif
526             }
527             break;
528             /* darwin version specific sysctl's goes here */
529         }
530         break;
531     }
532     return EOPNOTSUPP;
533 }
534
535 typedef (*PFI) ();
536 extern int vfs_opv_numops;      /* The total number of defined vnode operations */
537 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
538 int
539 afs_init(struct vfsconf *vfc)
540 {
541 #ifndef AFS_DARWIN80_ENV /* vfs_fsadd does all this junk */
542     int j;
543     int (**opv_desc_vector) ();
544     struct vnodeopv_entry_desc *opve_descp;
545
546
547
548     MALLOC(afs_vnodeop_p, PFI *, vfs_opv_numops * sizeof(PFI), M_TEMP,
549            M_WAITOK);
550
551     memset(afs_vnodeop_p, 0, vfs_opv_numops * sizeof(PFI));
552
553     opv_desc_vector = afs_vnodeop_p;
554     for (j = 0; afs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
555         opve_descp = &(afs_vnodeop_opv_desc.opv_desc_ops[j]);
556
557         /*
558          * Sanity check:  is this operation listed
559          * in the list of operations?  We check this
560          * by seeing if its offest is zero.  Since
561          * the default routine should always be listed
562          * first, it should be the only one with a zero
563          * offset.  Any other operation with a zero
564          * offset is probably not listed in
565          * vfs_op_descs, and so is probably an error.
566          *
567          * A panic here means the layer programmer
568          * has committed the all-too common bug
569          * of adding a new operation to the layer's
570          * list of vnode operations but
571          * not adding the operation to the system-wide
572          * list of supported operations.
573          */
574         if (opve_descp->opve_op->vdesc_offset == 0
575             && opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
576             printf("afs_init: operation %s not listed in %s.\n",
577                    opve_descp->opve_op->vdesc_name, "vfs_op_descs");
578             panic("load_afs: bad operation");
579         }
580         /*
581          * Fill in this entry.
582          */
583         opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
584             opve_descp->opve_impl;
585     }
586
587     /*
588      * Finally, go back and replace unfilled routines
589      * with their default.  (Sigh, an O(n^3) algorithm.  I
590      * could make it better, but that'd be work, and n is small.)
591      */
592
593     /*
594      * Force every operations vector to have a default routine.
595      */
596     opv_desc_vector = afs_vnodeop_p;
597     if (opv_desc_vector[VOFFSET(vop_default)] == NULL) {
598         panic("afs_init: operation vector without default routine.");
599     }
600     for (j = 0; j < vfs_opv_numops; j++)
601         if (opv_desc_vector[j] == NULL)
602             opv_desc_vector[j] = opv_desc_vector[VOFFSET(vop_default)];
603 #endif
604     return 0;
605 }
606
607 struct vfsops afs_vfsops = {
608    afs_mount,
609    afs_start,
610    afs_unmount,
611    afs_root,
612 #ifdef AFS_DARWIN80_ENV
613    0,
614    afs_vfs_getattr,
615 #else
616    afs_quotactl,
617    afs_statfs,
618 #endif
619    afs_sync,
620 #ifdef AFS_DARWIN80_ENV
621    0,0,0,
622 #else
623    afs_vfs_vget,
624    afs_fhtovp,
625    afs_vptofh,
626 #endif
627    afs_init,
628    afs_sysctl, 
629 #ifdef AFS_DARWIN80_ENV
630    0 /*setattr */,
631    {0}
632 #endif
633 };