macos: fix race in afs_root
[openafs.git] / src / afs / DARWIN / osi_vfsops.c
index 846bf24..d0efb8c 100644 (file)
@@ -4,8 +4,6 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #include <afs/sysincludes.h>   /* Standard vendor system headers */
 #include <afsincludes.h>       /* Afs-based standard headers */
@@ -13,95 +11,122 @@ RCSID
 #include <sys/malloc.h>
 #include <sys/namei.h>
 #include <sys/conf.h>
+#ifndef AFS_DARWIN80_ENV
 #include <sys/syscall.h>
+#endif
 #include <sys/sysctl.h>
 #include "../afs/sysctl.h"
 
+#ifndef M_UFSMNT
+#define M_UFSMNT M_TEMP /* DARWIN80 MALLOC doesn't look at the type anyway */
+#endif
+
 struct vcache *afs_globalVp = 0;
 struct mount *afs_globalVFS = 0;
+int afs_vfs_typenum;
 
 int
 afs_quotactl()
 {
-    return EOPNOTSUPP;
+    return ENOTSUP;
 }
 
 int
-afs_fhtovp(mp, fhp, vpp)
-     struct mount *mp;
-     struct fid *fhp;
-     struct vnode **vpp;
+afs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
 {
-
     return (EINVAL);
 }
 
 int
-afs_vptofh(vp, fhp)
-     struct vnode *vp;
-     struct fid *fhp;
+afs_vptofh(struct vnode *vp, struct fid *fhp)
 {
-
     return (EINVAL);
 }
 
+#ifdef AFS_DARWIN80_ENV
+#define CTX_TYPE vfs_context_t
+#define CTX_PROC_CONVERT(C) vfs_context_proc((C))
+#define STATFS_TYPE struct vfsstatfs
+#else
+#define CTX_TYPE struct proc *
+#define CTX_PROC_CONVERT(C) (C)
+#define STATFS_TYPE struct statfs
+#define vfs_statfs(VFS) &(VFS)->mnt_stat
+#endif
+#define PROC_DECL(out,in) struct proc *out = CTX_PROC_CONVERT(in)
+
 int
-afs_start(mp, flags, p)
-     struct mount *mp;
-     int flags;
-     struct proc *p;
+afs_start(struct mount *mp, int flags, CTX_TYPE p)
 {
     return (0);                        /* nothing to do. ? */
 }
 
 int
-afs_mount(mp, path, data, ndp, p)
-     register struct mount *mp;
-     char *path;
-     caddr_t data;
-     struct nameidata *ndp;
-     struct proc *p;
+afs_statfs(struct mount *mp, STATFS_TYPE *abp, CTX_TYPE ctx);
+#ifdef AFS_DARWIN80_ENV
+int
+afs_mount(struct mount *mp, vnode_t *devvp, user_addr_t data, vfs_context_t ctx)
+#else
+int
+afs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, CTX_TYPE ctx)
+#endif
 {
     /* ndp contains the mounted-from device.  Just ignore it.
      * we also don't care about our proc struct. */
     size_t size;
     int error;
+#ifdef AFS_DARWIN80_ENV
+    struct vfsioattr ioattr;
+    /* vfs_statfs advertised as RO, but isn't */
+    /* new api will be needed to initialize this information (nfs needs to
+       set mntfromname too) */
+#endif
+    STATFS_TYPE *mnt_stat = vfs_statfs(mp); 
 
-    if (mp->mnt_flag & MNT_UPDATE)
+    if (vfs_isupdate(mp))
        return EINVAL;
 
     AFS_GLOCK();
     AFS_STATCNT(afs_mount);
 
-    if (data == NULL && afs_globalVFS) {       /* Don't allow remounts. */
+    if (data == 0 && afs_globalVFS) {  /* Don't allow remounts. */
        AFS_GUNLOCK();
        return (EBUSY);
     }
 
     afs_globalVFS = mp;
+#ifdef AFS_DARWIN80_ENV
+    vfs_ioattr(mp, &ioattr);
+    ioattr.io_devblocksize = (16 * 32768);
+    vfs_setioattr(mp, &ioattr);
+    /* f_iosize is handled in VFS_GETATTR */
+#else
     mp->vfs_bsize = 8192;
-    vfs_getnewfsid(mp);
     mp->mnt_stat.f_iosize = 8192;
+#endif
+    vfs_getnewfsid(mp);
 
+#ifndef AFS_DARWIN80_ENV
     (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
     memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
-    memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
+#endif
+    memset(mnt_stat->f_mntfromname, 0, MNAMELEN);
 
-    if (data == NULL) {
-       strcpy(mp->mnt_stat.f_mntfromname, "AFS");
+    if (data == 0) {
+       strcpy(mnt_stat->f_mntfromname, "AFS");
        /* null terminated string "AFS" will fit, just leave it be. */
-       mp->mnt_data = (qaddr_t) NULL;
+       vfs_setfsprivate(mp, NULL);
     } else {
        struct VenusFid *rootFid = NULL;
        struct volume *tvp;
        char volName[MNAMELEN];
 
-       (void)copyinstr((char *)data, volName, MNAMELEN - 1, &size);
+       (void)copyinstr(data, volName, MNAMELEN - 1, &size);
        memset(volName + size, 0, MNAMELEN - size);
 
        if (volName[0] == 0) {
-           strcpy(mp->mnt_stat.f_mntfromname, "AFS");
-           mp->mnt_data = (qaddr_t) & afs_rootFid;
+           strcpy(mnt_stat->f_mntfromname, "AFS");
+           vfs_setfsprivate(mp, &afs_rootFid);
        } else {
            struct cell *localcell = afs_GetPrimaryCell(READ_LOCK);
            if (localcell == NULL) {
@@ -110,7 +135,7 @@ afs_mount(mp, path, data, ndp, p)
            }
 
            /* Set the volume identifier to "AFS:volume.name" */
-           snprintf(mp->mnt_stat.f_mntfromname, MNAMELEN - 1, "AFS:%s",
+           snprintf(mnt_stat->f_mntfromname, MNAMELEN - 1, "AFS:%s",
                     volName);
            tvp =
                afs_GetVolumeByName(volName, localcell->cellNum, 1,
@@ -129,31 +154,47 @@ afs_mount(mp, path, data, ndp, p)
                return ENODEV;
            }
 
-           mp->mnt_data = (qaddr_t) rootFid;
+           vfs_setfsprivate(mp, &rootFid);
        }
     }
+#ifdef AFS_DARWIN80_ENV
+    afs_vfs_typenum=vfs_typenum(mp);
+    vfs_setauthopaque(mp);
+    vfs_setauthopaqueaccess(mp);
+#else
     strcpy(mp->mnt_stat.f_fstypename, "afs");
+#endif
     AFS_GUNLOCK();
-    (void)afs_statfs(mp, &mp->mnt_stat, p);
+    (void)afs_statfs(mp, mnt_stat, ctx);
     return 0;
 }
 
 int
-afs_unmount(mp, flags, p)
-     struct mount *mp;
-     int flags;
-     struct proc *p;
+afs_unmount(struct mount *mp, int flags, CTX_TYPE ctx)
 {
-
+    void *mdata = vfs_fsprivate(mp);
     AFS_GLOCK();
     AFS_STATCNT(afs_unmount);
 
-    if (mp->mnt_data != (qaddr_t) - 1) {
-       if (mp->mnt_data != NULL) {
-           FREE(mp->mnt_data, M_UFSMNT);
-           mp->mnt_data = (qaddr_t) - 1;
+    if (mdata != (qaddr_t) - 1) {
+       if (mdata != NULL) {
+           vfs_setfsprivate(mp, (qaddr_t) - 1);
+           FREE(mdata, M_UFSMNT);
        } else {
            if (flags & MNT_FORCE) {
+                if (afs_globalVp) {
+#ifdef AFS_DARWIN80_ENV
+                    afs_PutVCache(afs_globalVp);
+#else
+                    AFS_GUNLOCK();
+                    vrele(AFSTOV(afs_globalVp));
+                    AFS_GLOCK();
+#endif
+                }
+               afs_globalVp = NULL;
+               AFS_GUNLOCK();
+               vflush(mp, NULLVP, FORCECLOSE/*0*/);
+               AFS_GLOCK();
                afs_globalVFS = 0;
                afs_shutdown();
            } else {
@@ -161,7 +202,7 @@ afs_unmount(mp, flags, p)
                return EBUSY;
            }
        }
-       mp->mnt_flag &= ~MNT_LOCAL;
+       vfs_clearflags(mp, MNT_LOCAL);
     }
 
     AFS_GUNLOCK();
@@ -169,56 +210,108 @@ afs_unmount(mp, flags, p)
     return 0;
 }
 
+#ifdef AFS_DARWIN80_ENV
+int
+afs_root(struct mount *mp, struct vnode **vpp, vfs_context_t ctx)
+#else
 int
 afs_root(struct mount *mp, struct vnode **vpp)
+#endif
 {
+    void *mdata = vfs_fsprivate(mp);
     int error;
     struct vrequest treq;
-    register struct vcache *tvp = 0;
+    struct vcache *tvp = 0;
+    struct vcache *gvp;
+    int needref=0;
+#ifdef AFS_DARWIN80_ENV
+    struct ucred *cr = vfs_context_ucred(ctx);
+#else
     struct proc *p = current_proc();
-    struct ucred cr;
+    struct ucred _cr;
+    struct ucred *cr = &_cr;
 
     pcred_readlock(p);
-    cr = *p->p_cred->pc_ucred;
+    _cr = *p->p_cred->pc_ucred;
     pcred_unlock(p);
+#endif
     AFS_GLOCK();
     AFS_STATCNT(afs_root);
-    if (mp->mnt_data == NULL && afs_globalVp
-       && (afs_globalVp->states & CStatd)) {
+
+again:
+    if (mdata == NULL && afs_globalVp
+       && (afs_globalVp->f.states & CStatd)) {
        tvp = afs_globalVp;
        error = 0;
-    } else if (mp->mnt_data == (qaddr_t) - 1) {
+        needref=1;
+    } else if (mdata == (qaddr_t) - 1) {
        error = ENOENT;
     } else {
-       struct VenusFid *rootFid = (mp->mnt_data == NULL)
-           ? &afs_rootFid : (struct VenusFid *)mp->mnt_data;
+       struct VenusFid *rootFid = (mdata == NULL)
+           ? &afs_rootFid : (struct VenusFid *)mdata;
 
-       if (afs_globalVp) {
-           afs_PutVCache(afs_globalVp);
-           afs_globalVp = NULL;
-       }
-
-       if (!(error = afs_InitReq(&treq, &cr)) && !(error = afs_CheckInit())) {
+       if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
            tvp = afs_GetVCache(rootFid, &treq, NULL, NULL);
+#ifdef AFS_DARWIN80_ENV
+            if (tvp) {
+               AFS_GUNLOCK();
+                error = afs_darwin_finalizevnode(tvp, NULL, NULL, 1, 0);
+               AFS_GLOCK();
+                if (error)
+                   tvp = NULL;
+                else
+                   /* re-acquire the usecount that finalizevnode disposed of */
+                   vnode_ref(AFSTOV(tvp));
+            }
+#endif
            /* we really want this to stay around */
            if (tvp) {
-               if (mp->mnt_data == NULL)
+               if (mdata == NULL) {
+                   gvp = afs_globalVp;
                    afs_globalVp = tvp;
+                   if (gvp) {
+                       afs_PutVCache(gvp);
+                       if (tvp != afs_globalVp) {
+                           /* someone else got there before us! */
+                           afs_PutVCache(tvp);
+                           tvp = 0;
+                           goto again;
+                       }
+                   }
+                    needref=1;
+                }
            } else
                error = ENOENT;
        }
     }
     if (tvp) {
+#ifndef AFS_DARWIN80_ENV /* KPI callers don't need a usecount reference */
        osi_vnhold(tvp, 0);
        AFS_GUNLOCK();
        vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, p);
        AFS_GLOCK();
-       if (mp->mnt_data == NULL) {
+#endif
+
+        if (needref)
+#ifdef AFS_DARWIN80_ENV
+           /* This iocount is for the caller. the initial iocount
+            * is for the eventual afs_PutVCache. for mdata != null,
+            * there will not be a PutVCache, so the caller gets the
+            * initial (from GetVCache or finalizevnode) iocount
+            */
+           vnode_get(AFSTOV(tvp));
+#else
+           ;
+#endif
+
+       if (mdata == NULL)
            afs_globalVFS = mp;
-       }
+
        *vpp = AFSTOV(tvp);
+#ifndef AFS_DARWIN80_ENV 
        AFSTOV(tvp)->v_flag |= VROOT;
        AFSTOV(tvp)->v_vfsp = mp;
+#endif
     }
 
     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
@@ -227,14 +320,12 @@ afs_root(struct mount *mp, struct vnode **vpp)
     return error;
 }
 
+#ifndef AFS_DARWIN80_ENV /* vget vfsop never had this prototype AFAIK */
 int
-afs_vget(mp, lfl, vp)
-     struct mount *mp;
-     struct vnode *vp;
-     int lfl;
+afs_vget(struct mount *mp, int lfl, struct vnode *vp)
 {
     int error;
-    printf("vget called. help!\n");
+    //printf("vget called. help!\n");
     if (vp->v_usecount < 0) {
        vprint("bad usecount", vp);
        panic("afs_vget");
@@ -245,56 +336,174 @@ afs_vget(mp, lfl, vp)
     return error;
 }
 
+int afs_vfs_vget(struct mount *mp, void *ino, struct vnode **vpp)
+{
+   return ENOENT; /* cannot implement */
+}
+
+#endif
+
 int
-afs_statfs(struct mount *mp, struct statfs *abp, struct proc *p)
+afs_statfs(struct mount *mp, STATFS_TYPE *abp, CTX_TYPE ctx)
 {
+    STATFS_TYPE *sysstat = vfs_statfs(mp);
     AFS_GLOCK();
     AFS_STATCNT(afs_statfs);
 
+#ifdef AFS_DARWIN80_ENV
+    abp->f_iosize = (256 * 1024);
+    abp->f_bsize = vfs_devblocksize(mp);
+#else
+    abp->f_bsize = mp->vfs_bsize;
+    abp->f_iosize = mp->vfs_bsize;
+#endif
 #if 0
     abp->f_type = MOUNT_AFS;
 #endif
-    abp->f_bsize = mp->vfs_bsize;
-    abp->f_iosize = mp->vfs_bsize;
 
     /* Fake a high number below to satisfy programs that use the statfs call
      * to make sure that there's enough space in the device partition before
      * storing something there.
      */
     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
-       abp->f_ffree = 2000000;
+      abp->f_ffree = 0x7fffffff;
 
-    abp->f_fsid.val[0] = mp->mnt_stat.f_fsid.val[0];
-    abp->f_fsid.val[1] = mp->mnt_stat.f_fsid.val[1];
-    if (abp != &mp->mnt_stat) {
-       abp->f_type = mp->mnt_vfc->vfc_typenum;
+    if (abp != sysstat) {
+        abp->f_fsid.val[0] = sysstat->f_fsid.val[0];
+        abp->f_fsid.val[1] = sysstat->f_fsid.val[1];
+#ifndef AFS_DARWIN80_ENV
+       abp->f_type = vfs_typenum(mp);
+#endif
        memcpy((caddr_t) & abp->f_mntonname[0],
-              (caddr_t) mp->mnt_stat.f_mntonname, MNAMELEN);
+              (caddr_t) sysstat->f_mntonname, MNAMELEN);
        memcpy((caddr_t) & abp->f_mntfromname[0],
-              (caddr_t) mp->mnt_stat.f_mntfromname, MNAMELEN);
+              (caddr_t) sysstat->f_mntfromname, MNAMELEN);
     }
 
     AFS_GUNLOCK();
     return 0;
 }
 
+#ifdef AFS_DARWIN80_ENV
+int
+afs_vfs_getattr(struct mount *mp, struct vfs_attr *outattrs,
+                vfs_context_t context)
+{
+    VFSATTR_RETURN(outattrs, f_bsize, vfs_devblocksize(mp));
+    VFSATTR_RETURN(outattrs, f_iosize, vfs_devblocksize(mp));
+    VFSATTR_RETURN(outattrs, f_blocks, 2000000);
+    VFSATTR_RETURN(outattrs, f_bfree, 2000000);
+    VFSATTR_RETURN(outattrs, f_bavail, 2000000);
+    VFSATTR_RETURN(outattrs, f_files, 2000000);
+    VFSATTR_RETURN(outattrs, f_ffree, 2000000);
+    if ( VFSATTR_IS_ACTIVE(outattrs, f_capabilities) )
+    {
+         vol_capabilities_attr_t *vcapattrptr;
+         vcapattrptr = &outattrs->f_capabilities;
+         vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
+                   VOL_CAP_FMT_SYMBOLICLINKS |
+                   VOL_CAP_FMT_HARDLINKS |
+                   VOL_CAP_FMT_ZERO_RUNS |
+                   VOL_CAP_FMT_CASE_SENSITIVE |
+                   VOL_CAP_FMT_CASE_PRESERVING |
+                  VOL_CAP_FMT_PERSISTENTOBJECTIDS |
+                  VOL_CAP_FMT_2TB_FILESIZE |
+                   VOL_CAP_FMT_FAST_STATFS;
+         vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] = 
+                   VOL_CAP_INT_ADVLOCK | 
+                   VOL_CAP_INT_FLOCK;
+         vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
+         vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
+
+         /* Capabilities we know about: */
+         vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] =
+                 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
+                 VOL_CAP_FMT_SYMBOLICLINKS |
+                 VOL_CAP_FMT_HARDLINKS |
+                 VOL_CAP_FMT_JOURNAL |
+                 VOL_CAP_FMT_JOURNAL_ACTIVE |
+                 VOL_CAP_FMT_NO_ROOT_TIMES |
+                 VOL_CAP_FMT_SPARSE_FILES |
+                 VOL_CAP_FMT_ZERO_RUNS |
+                 VOL_CAP_FMT_CASE_SENSITIVE |
+                 VOL_CAP_FMT_CASE_PRESERVING |
+                VOL_CAP_FMT_PERSISTENTOBJECTIDS |
+                VOL_CAP_FMT_2TB_FILESIZE |
+                 VOL_CAP_FMT_FAST_STATFS;
+         vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] =
+                 VOL_CAP_INT_SEARCHFS |
+                 VOL_CAP_INT_ATTRLIST |
+                 VOL_CAP_INT_NFSEXPORT |
+                 VOL_CAP_INT_READDIRATTR |
+                 VOL_CAP_INT_EXCHANGEDATA |
+                 VOL_CAP_INT_COPYFILE |
+                 VOL_CAP_INT_ALLOCATE |
+                 VOL_CAP_INT_VOL_RENAME |
+                 VOL_CAP_INT_ADVLOCK |
+                 VOL_CAP_INT_FLOCK;
+         vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0;
+         vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0;
+             
+         VFSATTR_SET_SUPPORTED(outattrs, f_capabilities);
+    }
+    return 0;
+}
+#endif
+
+#ifdef AFS_DARWIN80_ENV
+int
+afs_sync(struct mount *mp, int waitfor, CTX_TYPE ctx)
+#else
 int
-afs_sync(mp, waitfor, cred, p)
-     struct mount *mp;
-     int waitfor;
-     struct ucred *cred;
-     struct prioc *p;
+afs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
+#endif
 {
     return 0;
 }
 
 u_int32_t afs_darwin_realmodes = 0;
+u_int32_t afs_darwin_fsevents = 0;
+extern int AFSDOBULK;
 
-int afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 
-              void *newp, size_t newlen, struct proc *p)
+int
+afs_sysctl_int(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
+              user_addr_t newp, size_t newlen, u_int32_t *object)
 {
+#ifdef AFS_DARWIN80_ENV
     int error;
 
+    if (oldp != USER_ADDR_NULL && oldlenp == NULL)
+       return (EFAULT);
+    if (oldp && *oldlenp < sizeof(u_int32_t))
+       return (ENOMEM);
+    if (newp && newlen != sizeof(u_int32_t))
+       return (EINVAL);
+    *oldlenp = sizeof(u_int32_t);
+    if (oldp) {
+       if ((error = copyout(object,
+                            oldp, sizeof(u_int32_t)))) {
+           return error;
+       }
+    }
+    if (newp)
+       return copyin(newp, object, sizeof(u_int32_t));
+    return 0;
+#else
+    return sysctl_int(oldp, oldlenp, newp, newlen,
+                     object);
+#endif
+}
+
+#ifdef AFS_DARWIN80_ENV
+int
+afs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
+              user_addr_t newp, size_t newlen, vfs_context_t context)
+#else
+int
+afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+              void *newp, size_t newlen, struct proc *p)
+#endif
+{
     switch (name[0]) {
     case AFS_SC_ALL:
         /* nothing defined */
@@ -306,15 +515,21 @@ int afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
        case AFS_SC_DARWIN_ALL:
            switch (name[2]) {
            case AFS_SC_DARWIN_ALL_REALMODES:
-               return sysctl_int(oldp, oldlenp, newp, newlen,
-                                 &afs_darwin_realmodes);
+               return afs_sysctl_int(name, namelen, oldp, oldlenp,
+                                     newp, newlen, &afs_darwin_realmodes);
+           case AFS_SC_DARWIN_ALL_FSEVENTS:
+               return afs_sysctl_int(name, namelen, oldp, oldlenp,
+                                     newp, newlen, &afs_darwin_fsevents);
+           case AFS_SC_DARWIN_ALL_BULKSTAT:
+               return afs_sysctl_int(name, namelen, oldp, oldlenp,
+                                     newp, newlen, &AFSDOBULK);
            }
            break;
            /* darwin version specific sysctl's goes here */
        }
        break;
     }
-    return EOPNOTSUPP;
+    return ENOTSUP;
 }
 
 typedef (*PFI) ();
@@ -323,6 +538,7 @@ extern struct vnodeopv_desc afs_vnodeop_opv_desc;
 int
 afs_init(struct vfsconf *vfc)
 {
+#ifndef AFS_DARWIN80_ENV /* vfs_fsadd does all this junk */
     int j;
     int (**opv_desc_vector) ();
     struct vnodeopv_entry_desc *opve_descp;
@@ -384,19 +600,34 @@ afs_init(struct vfsconf *vfc)
     for (j = 0; j < vfs_opv_numops; j++)
        if (opv_desc_vector[j] == NULL)
            opv_desc_vector[j] = opv_desc_vector[VOFFSET(vop_default)];
+#endif
+    return 0;
 }
 
 struct vfsops afs_vfsops = {
-    afs_mount,
-    afs_start,
-    afs_unmount,
-    afs_root,
-    afs_quotactl,
-    afs_statfs,
-    afs_sync,
-    afs_vget,
-    afs_fhtovp,
-    afs_vptofh,
-    afs_init,
-    afs_sysctl
+   afs_mount,
+   afs_start,
+   afs_unmount,
+   afs_root,
+#ifdef AFS_DARWIN80_ENV
+   0,
+   afs_vfs_getattr,
+#else
+   afs_quotactl,
+   afs_statfs,
+#endif
+   afs_sync,
+#ifdef AFS_DARWIN80_ENV
+   0,0,0,
+#else
+   afs_vfs_vget,
+   afs_fhtovp,
+   afs_vptofh,
+#endif
+   afs_init,
+   afs_sysctl, 
+#ifdef AFS_DARWIN80_ENV
+   0 /*setattr */,
+   {0}
+#endif
 };