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