afs: refactor PNewStatMount and PFlushMount
[openafs.git] / src / afs / afs_pioctl.c
index fced77b..66c7f12 100644 (file)
@@ -29,6 +29,7 @@
 #include "rx/rx_globals.h"
 #include "token.h"
 
+extern int afs_rmtsys_enable;
 struct VenusFid afs_rootFid;
 afs_int32 afs_waitForever = 0;
 short afs_waitForeverCount = 0;
@@ -54,8 +55,9 @@ struct afs_pdata {
 static_inline int
 afs_pd_alloc(struct afs_pdata *apd, size_t size)
 {
-
-    if (size > AFS_LRALLOCSIZ)
+    /* Ensure that we give caller at least one trailing guard byte
+     * for the NUL terminator. */
+    if (size >= AFS_LRALLOCSIZ)
        apd->ptr = osi_Alloc(size + 1);
     else
        apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
@@ -63,6 +65,13 @@ afs_pd_alloc(struct afs_pdata *apd, size_t size)
     if (apd->ptr == NULL)
        return ENOMEM;
 
+    /* Clear it all now, including the guard byte. */
+    if (size >= AFS_LRALLOCSIZ)
+       memset(apd->ptr, 0, size + 1);
+    else
+       memset(apd->ptr, 0, AFS_LRALLOCSIZ);
+
+    /* Don't tell the caller about the guard byte. */
     apd->remaining = size;
 
     return 0;
@@ -74,7 +83,7 @@ afs_pd_free(struct afs_pdata *apd)
     if (apd->ptr == NULL)
        return;
 
-    if (apd->remaining > AFS_LRALLOCSIZ)
+    if (apd->remaining >= AFS_LRALLOCSIZ)
        osi_Free(apd->ptr, apd->remaining + 1);
     else
        osi_FreeLargeSpace(apd->ptr);
@@ -277,6 +286,7 @@ DECL_PIOCTL(PRemoveMount);
 DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
+DECL_PIOCTL(PFlushAllVolumeData);
 DECL_PIOCTL(PGetVnodeXStatus);
 DECL_PIOCTL(PGetVnodeXStatus2);
 DECL_PIOCTL(PSetSysName);
@@ -302,7 +312,7 @@ DECL_PIOCTL(PNFSNukeCreds);
 DECL_PIOCTL(PNewUuid);
 DECL_PIOCTL(PPrecache);
 DECL_PIOCTL(PGetPAG);
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
 DECL_PIOCTL(PSetCachingThreshold);
 #endif
 
@@ -420,12 +430,13 @@ static pioctlFunction CpioctlSw[] = {
     PBogus,                     /* 11 */
     PPrecache,                  /* 12 */
     PGetPAG,                    /* 13 */
+    PFlushAllVolumeData,        /* 14 */
 };
 
 static pioctlFunction OpioctlSw[]  = {
     PBogus,                    /* 0 */
     PNFSNukeCreds,             /* 1 -- nuke all creds for NFS client */
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
 #else
     PNoop                       /* 2 -- get/set cache-bypass size threshold */
@@ -568,8 +579,7 @@ kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
            if (((uap->com >> 8) & 0xff) == 'V') {
                struct afs_ioctl *datap;
                AFS_GLOCK();
-               datap =
-                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
                code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
@@ -667,19 +677,9 @@ afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
     int ioctlDone = 0, code = 0;
 
     AFS_STATCNT(afs_xioctl);
-# if defined(AFS_SUN57_ENV)
     fd = getf(uap->fd);
     if (!fd)
        return (EBADF);
-# elif defined(AFS_SUN54_ENV)
-    fd = GETF(uap->fd);
-    if (!fd)
-       return (EBADF);
-# else
-    if (code = getf(uap->fd, &fd)) {
-       return (code);
-    }
-# endif
     if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
        tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
@@ -687,17 +687,12 @@ afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
            if (((uap->com >> 8) & 0xff) == 'V') {
                struct afs_ioctl *datap;
                AFS_GLOCK();
-               datap =
-                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
                code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
                    AFS_GUNLOCK();
-# if defined(AFS_SUN54_ENV)
                    releasef(uap->fd);
-# else
-                   releasef(fd);
-# endif
                    return (EFAULT);
                }
                code = HandleIoctl(tvc, uap->com, datap);
@@ -707,19 +702,13 @@ afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
            }
        }
     }
-# if defined(AFS_SUN57_ENV)
     releasef(uap->fd);
-# elif defined(AFS_SUN54_ENV)
-    RELEASEF(uap->fd);
-# else
-    releasef(fd);
-# endif
     if (!ioctlDone)
        code = ioctl(uap, rvp);
 
     return (code);
 }
-#elif defined(AFS_LINUX22_ENV)
+#elif defined(AFS_LINUX_ENV)
 struct afs_ioctl_sys {
     unsigned int com;
     unsigned long arg;
@@ -810,6 +799,10 @@ afs_xioctl(struct thread *td, struct ioctl_args *uap,
           register_t *retval)
 {
     afs_proc_t *p = td->td_proc;
+# elif defined(AFS_NBSD_ENV)
+int
+afs_xioctl(afs_proc_t *p, const struct sys_ioctl_args *uap, register_t *retval)
+{
 # else
 struct ioctl_args {
     int fd;
@@ -818,7 +811,7 @@ struct ioctl_args {
 };
 
 int
-afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
+afs_xioctl(afs_proc_t *p, const struct ioctl_args *uap, register_t *retval)
 {
 # endif
     struct filedesc *fdp;
@@ -827,14 +820,23 @@ afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
     struct file *fd;
 
     AFS_STATCNT(afs_xioctl);
-#   if defined(AFS_NBSD40_ENV)
-     fdp = p->l_proc->p_fd;
-#   else
+#if defined(AFS_NBSD40_ENV)
+    fdp = p->l_proc->p_fd;
+#else
     fdp = p->p_fd;
 #endif
-    if ((u_int) uap->fd >= fdp->fd_nfiles
-       || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
+#if defined(AFS_NBSD50_ENV)
+    if ((fd = fd_getfile(SCARG(uap, fd))) == NULL)
+       return (EBADF);
+#elif defined(AFS_FBSD_ENV)
+    if ((uap->fd >= fdp->fd_nfiles)
+       || ((fd = fdp->fd_ofiles[uap->fd].fde_file) == NULL))
+       return EBADF;
+#else
+    if ((uap->fd >= fdp->fd_nfiles)
+       || ((fd = fdp->fd_ofiles[uap->fd]) == NULL))
        return EBADF;
+#endif
     if ((fd->f_flag & (FREAD | FWRITE)) == 0)
        return EBADF;
     /* first determine whether this is any sort of vnode */
@@ -847,19 +849,31 @@ afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
 # else
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
 # endif
-       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+       if (tvc && IsAfsVnode((struct vnode *)fd->f_data)) {
            /* This is an AFS vnode */
-           if (((uap->com >> 8) & 0xff) == 'V') {
+#if defined(AFS_NBSD50_ENV)
+           if (((SCARG(uap, com) >> 8) & 0xff) == 'V') {
+#else
+            if (((uap->com >> 8) & 0xff) == 'V') {
+#endif
                struct afs_ioctl *datap;
                AFS_GLOCK();
                datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+#if defined(AFS_NBSD50_ENV)
+               code = copyin_afs_ioctl(SCARG(uap, data), datap);
+#else
                code = copyin_afs_ioctl((char *)uap->arg, datap);
+#endif
                if (code) {
                    osi_FreeSmallSpace(datap);
                    AFS_GUNLOCK();
                    return code;
                }
+#if defined(AFS_NBSD50_ENV)
+               code = HandleIoctl(tvc, SCARG(uap, com), datap);
+#else
                code = HandleIoctl(tvc, uap->com, datap);
+#endif
                osi_FreeSmallSpace(datap);
                AFS_GUNLOCK();
                ioctlDone = 1;
@@ -867,14 +881,17 @@ afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
        }
     }
 
+#if defined(AFS_NBSD50_ENV)
+    fd_putfile(SCARG(uap, fd));
+#endif
+
     if (!ioctlDone) {
 # if defined(AFS_FBSD_ENV)
-       return ioctl(td, uap);
+       return sys_ioctl(td, uap);
 # elif defined(AFS_OBSD_ENV)
        code = sys_ioctl(p, uap, retval);
 # elif defined(AFS_NBSD_ENV)
-           struct lwp *l = osi_curproc();
-           code = sys_ioctl(l, uap, retval);
+        code = sys_ioctl(p, uap, retval);
 # endif
     }
 
@@ -1002,7 +1019,7 @@ afs_pioctl(afs_proc_t *p, void *args, int *retval)
 #endif
 
 /* macro to avoid adding any more #ifdef's to pioctl code. */
-#if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
+#if defined(AFS_LINUX_ENV) || defined(AFS_AIX41_ENV)
 #define PIOCTL_FREE_CRED() crfree(credp)
 #else
 #define PIOCTL_FREE_CRED()
@@ -1028,7 +1045,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #ifdef AFS_NEED_CLIENTCONTEXT
     afs_ucred_t *tmpcred = NULL;
 #endif
-#if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     afs_ucred_t *foreigncreds = NULL;
 #endif
     afs_int32 code = 0;
@@ -1036,7 +1053,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #ifdef AFS_AIX41_ENV
     struct ucred *credp = crref();     /* don't free until done! */
 #endif
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
     cred_t *credp = crref();   /* don't free until done! */
     struct dentry *dp;
 #endif
@@ -1054,7 +1071,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
     }
     if ((com & 0xff) == PSetClientContext) {
 #ifdef AFS_NEED_CLIENTCONTEXT
-#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV)
        code = HandleClientContext(&data, &com, &foreigncreds, credp);
 #else
        code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
@@ -1084,7 +1101,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
         * like afs_osi_suser(cred) which, I think, is better since it
         * generalizes and supports multi cred environments...
         */
-#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV)
        tmpcred = credp;
        credp = foreigncreds;
 #elif defined(AFS_AIX41_ENV)
@@ -1102,10 +1119,12 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #endif
     }
 #endif /* AFS_NEED_CLIENTCONTEXT */
-    if ((com & 0xff) == 15) {
+
+    /* VIOCPREFETCH */
+    if ((com & 0xff00) >> 8 == 'V' && (com & 0xff) == 15) {
        /* special case prefetch so entire pathname eval occurs in helper process.
         * otherwise, the pioctl call is essentially useless */
-#if    defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if    defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
        code =
            Prefetch(path, &data, follow,
                     foreigncreds ? foreigncreds : credp);
@@ -1125,17 +1144,13 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
            lookupname(path, USR, follow, NULL, &vp,
                       foreigncreds ? foreigncreds : credp);
 #else
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
        code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
        if (!code)
            vp = (struct vnode *)dp->d_inode;
 #else
        code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
-#if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
-       if (vp != NULL)
-               VN_HOLD(vp);
-#endif /* AFS_FBSD80_ENV */
-#endif /* AFS_LINUX22_ENV */
+#endif /* AFS_LINUX_ENV */
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
        if (code) {
@@ -1196,7 +1211,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
            credp = OSI_GET_CURRENT_CRED();
            code = afs_HandlePioctl(vp, com, &data, follow, &credp);
        }
-#elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#elif defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 #elif defined(UKERNEL)
        code = afs_HandlePioctl(vp, com, &data, follow,
@@ -1222,7 +1237,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
        set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
 #elif  defined(AFS_SGI_ENV)
        OSI_SET_CURRENT_CRED(tmpcred);  /* restore original credentials */
-#elif  defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+#elif  defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV)
        credp = tmpcred;                /* restore original credentials */
 #else
        osi_curcred() = tmpcred;        /* restore original credentials */
@@ -1232,13 +1247,19 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
     }
 #endif /* AFS_NEED_CLIENTCONTEXT */
     if (vp) {
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
+       /*
+        * Holding the global lock when calling dput can cause a deadlock
+        * when the kernel calls back into afs_dentry_iput
+        */
+       AFS_GUNLOCK();
        dput(dp);
+       AFS_GLOCK();
 #else
-#if defined(AFS_FBSD80_ENV)
+#if defined(AFS_FBSD_ENV)
     if (VOP_ISLOCKED(vp))
        VOP_UNLOCK(vp, 0);
-#endif /* AFS_FBSD80_ENV */
+#endif /* AFS_FBSD_ENV */
        AFS_RELE(vp);           /* put vnode back */
 #endif
     }
@@ -1272,7 +1293,7 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
                 afs_ucred_t **acred)
 {
     struct vcache *avc;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     afs_int32 code;
     afs_int32 function, device;
     struct afs_pdata input, output;
@@ -1290,13 +1311,13 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
 
-    code = afs_InitReq(&treq, *acred);
+    code = afs_CreateReq(&treq, *acred);
     if (code)
        return code;
 
     afs_InitFakeStat(&fakestate);
     if (avc) {
-       code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+       code = afs_EvalFakeStat(&avc, &fakestate, treq);
        if (code)
            goto out;
     }
@@ -1355,7 +1376,7 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     copyOutput = output;
 
     code =
-       (*pioctlSw[function]) (avc, function, &treq, &copyInput,
+       (*pioctlSw[function]) (avc, function, treq, &copyInput,
                               &copyOutput, acred);
 
     outSize = copyOutput.ptr - output.ptr;
@@ -1373,7 +1394,9 @@ out:
     afs_pd_free(&output);
 
     afs_PutFakeStat(&fakestate);
-    return afs_CheckCode(code, &treq, 41);
+    code = afs_CheckCode(code, treq, 41);
+    afs_DestroyReq(treq);
+    return code;
 }
 
 /*!
@@ -1453,15 +1476,10 @@ DECL_PIOCTL(PSetAcl)
              SHARED_LOCK, NULL));
 
     /* now we've forgotten all of the access info */
-    ObtainWriteLock(&afs_xcbhash, 455);
-    avc->callback = 0;
-    afs_DequeueCallback(avc);
-    avc->f.states &= ~(CStatd | CUnique);
-    ReleaseWriteLock(&afs_xcbhash);
-    if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
-       osi_dnlc_purgedp(avc);
+    afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique);
 
     /* SXW - Should we flush metadata here? */
+
     return code;
 }
 
@@ -1761,12 +1779,13 @@ DECL_PIOCTL(PGetUserCell)
        if (tu->uid == areq->uid && (tu->states & UPrimary)) {
            tu->refCount++;
            ReleaseWriteLock(&afs_xuser);
+           afs_LockUser(tu, READ_LOCK, 0);
            break;
        }
     }
     if (tu) {
        tcell = afs_GetCell(tu->cell, READ_LOCK);
-       afs_PutUser(tu, WRITE_LOCK);
+       afs_PutUser(tu, READ_LOCK);
        if (!tcell)
            return ESRCH;
        else {
@@ -1811,19 +1830,40 @@ _settok_tokenCell(char *cellName, int *cellNum, int *primary) {
 }
 
 
+#if defined(AFS_LINUX_ENV)
 static_inline int
-_settok_setParentPag(afs_ucred_t **cred) {
+_settok_setParentPag(afs_ucred_t **cred)
+{
+    afs_uint32 pag;
+    int code;
+    afs_ucred_t *old_cred = *cred;
+    code = setpag(cred, -1, &pag, 1);
+    if (code == 0) {
+       /* setpag() may have changed our credentials */
+       *cred = crref();
+       crfree(old_cred);
+    }
+    return code;
+}
+#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+static_inline int
+_settok_setParentPag(afs_ucred_t **cred)
+{
     afs_uint32 pag;
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     char procname[256];
     osi_procname(procname, 256);
     afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
                 MyPidxx2Pid(MyPidxx), procname);
     return setpag(osi_curproc(), cred, -1, &pag, 1);
+}
 #else
+static_inline int
+_settok_setParentPag(afs_ucred_t **cred)
+{
+    afs_uint32 pag;
     return setpag(cred, -1, &pag, 1);
-#endif
 }
+#endif
 
 /*!
  * VIOCSETTOK (3) - Set authentication tokens
@@ -1855,7 +1895,7 @@ DECL_PIOCTL(PSetTokens)
     char *stp;
     char *cellName;
     int stLen;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     afs_int32 flag, set_parent_pag = 0;
 
     AFS_STATCNT(PSetTokens);
@@ -1912,8 +1952,11 @@ DECL_PIOCTL(PSetTokens)
 
     if (set_parent_pag) {
        if (_settok_setParentPag(acred) == 0) {
-           afs_InitReq(&treq, *acred);
-           areq = &treq;
+           code = afs_CreateReq(&treq, *acred);
+           if (code) {
+               return code;
+           }
+           areq = treq;
        }
     }
 
@@ -1933,6 +1976,7 @@ DECL_PIOCTL(PSetTokens)
     afs_ResetUserConns(tu);
     afs_NotifyUser(tu, UTokensObtained);
     afs_PutUser(tu, WRITE_LOCK);
+    afs_DestroyReq(treq);
 
     return 0;
 }
@@ -2044,6 +2088,7 @@ DECL_PIOCTL(PSetVolumeStatus)
     AFS_STATCNT(PSetVolumeStatus);
     if (!avc)
        return EINVAL;
+    memset(&storeStat, 0, sizeof(storeStat));
 
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
@@ -2136,19 +2181,80 @@ DECL_PIOCTL(PFlush)
     AFS_STATCNT(PFlush);
     if (!avc)
        return EINVAL;
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
     ObtainWriteLock(&avc->lock, 225);
-    afs_ResetVCache(avc, *acred);
+    afs_ResetVCache(avc, *acred, 0);
     ReleaseWriteLock(&avc->lock);
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonUnlock(&avc->pvnLock, avc);
-#endif
     return 0;
 }
 
 /*!
+ * Lookup name in the directory associated with given vcache.
+ *
+ * \param[in]  avc     vcache associated with directory
+ * \param[in]  areq    request to be passed on
+ * \param[in]  aname   name to be searched
+ * \param[out] asys    resolved name (replace @sys by system type)
+ * \param[out] afid    fid associated with aname
+ *
+ * \return 0 on success; non-zero otherwise.
+ *
+ * \notes  The caller must free asys->name (checking if asys->allocked == 1).
+ */
+static int
+afs_LookupName(struct vcache *avc, struct vrequest *areq, char *aname,
+              struct sysname_info *asys, struct VenusFid *afid)
+{
+    int code;
+    struct dcache *tdc;
+    afs_size_t offset, len;
+
+    memset(asys, 0, sizeof(*asys));
+    memset(afid, 0, sizeof(*afid));
+
+    if (!avc || !areq || !aname || !asys || !afid) {
+       afs_warn("afs: Internal error, bad args to afs_LookupName: %p, %p, %p, "
+                "%p, %p.\n", avc, areq, aname, asys, afid);
+       code = EIO;
+       goto done;
+    }
+
+    /* check if vcache is up to date */
+    code = afs_VerifyVCache(avc, areq);
+    if (code != 0) {
+       goto done;
+    }
+
+    /* must be a directory */
+    if (vType(avc) != VDIR) {
+       code = ENOTDIR;
+       goto done;
+    }
+
+    tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
+    if (!tdc) {
+       code = EIO;
+       goto done;
+    }
+
+    /* if @sys is present, replace it by the machine's system type */
+    Check_AtSys(avc, aname, asys, areq);
+    ObtainReadLock(&tdc->lock);
+
+    do {
+       /*
+        * Lookup name in the appropriate directory. If name is not found, try
+        * again with the next sysname from the @sys list.
+        */
+       code = afs_dir_Lookup(tdc, asys->name, &afid->Fid);
+    } while (code == ENOENT && Next_AtSys(avc, areq, asys));
+
+    ReleaseReadLock(&tdc->lock);
+    afs_PutDCache(tdc);
+ done:
+    return code;
+}
+
+/*!
  * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
  *
  * \ingroup pioctl
@@ -2169,52 +2275,38 @@ DECL_PIOCTL(PNewStatMount)
 {
     afs_int32 code;
     struct vcache *tvc;
-    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
     char *name;
     struct sysname_info sysState;
-    afs_size_t offset, len;
 
     AFS_STATCNT(PNewStatMount);
+    memset(&sysState, 0, sizeof(sysState));
+
     if (!avc)
        return EINVAL;
 
     if (afs_pd_getStringPtr(ain, &name) != 0)
        return EINVAL;
 
-    code = afs_VerifyVCache(avc, areq);
-    if (code)
-       return code;
-    if (vType(avc) != VDIR) {
-       return ENOTDIR;
-    }
-    tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
-    if (!tdc)
-       return ENOENT;
-    Check_AtSys(avc, name, &sysState, areq);
-    ObtainReadLock(&tdc->lock);
-    do {
-       code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
-    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
-    ReleaseReadLock(&tdc->lock);
-    afs_PutDCache(tdc);                /* we're done with the data */
-    bufp = sysState.name;
+    code = afs_LookupName(avc, areq, name, &sysState, &tfid);
     if (code) {
        goto out;
     }
+
+    bufp = sysState.name;
     tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
-       tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+       tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
     } else {
-       tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+       tvc = afs_GetVCache(&tfid, areq);
     }
     if (!tvc) {
-       code = ENOENT;
+       code = EIO;
        goto out;
     }
-    if (tvc->mvstat != 1) {
+    if (tvc->mvstat != AFS_MVSTAT_MTPT) {
        afs_PutVCache(tvc);
        code = EINVAL;
        goto out;
@@ -2237,7 +2329,7 @@ DECL_PIOCTL(PNewStatMount)
     afs_PutVCache(tvc);
   out:
     if (sysState.allocked)
-       osi_FreeLargeSpace(bufp);
+       osi_FreeLargeSpace(sysState.name);
     return code;
 }
 
@@ -2254,6 +2346,9 @@ getNthCell(afs_int32 uid, afs_int32 iterator) {
     int i;
     struct unixuser *tu = NULL;
 
+    if (iterator > afs_cellindex)
+       return NULL;            /* no point in looking */
+
     i = UHash(uid);
     ObtainReadLock(&afs_xuser);
     for (tu = afs_users[i]; tu; tu = tu->next) {
@@ -2266,6 +2361,10 @@ getNthCell(afs_int32 uid, afs_int32 iterator) {
        tu->refCount++;
     }
     ReleaseReadLock(&afs_xuser);
+    if (tu) {
+       afs_LockUser(tu, READ_LOCK, 0);
+    }
+
 
     return tu;
 }
@@ -2416,10 +2515,13 @@ DECL_PIOCTL(PUnlog)
     ObtainWriteLock(&afs_xuser, 227);
     for (tu = afs_users[i]; tu; tu = tu->next) {
        if (tu->uid == areq->uid) {
-           tu->states &= ~UHasTokens;
-           afs_FreeTokens(&tu->tokens);
            tu->refCount++;
            ReleaseWriteLock(&afs_xuser);
+
+           afs_LockUser(tu, WRITE_LOCK, 366);
+
+           tu->states &= ~UHasTokens;
+           afs_FreeTokens(&tu->tokens);
            afs_NotifyUser(tu, UTokensDropped);
            /* We have to drop the lock over the call to afs_ResetUserConns,
             * since it obtains the afs_xvcache lock.  We could also keep
@@ -2430,7 +2532,7 @@ DECL_PIOCTL(PUnlog)
             * every user conn that existed when we began this call.
             */
            afs_ResetUserConns(tu);
-           tu->refCount--;
+           afs_PutUser(tu, WRITE_LOCK);
            ObtainWriteLock(&afs_xuser, 228);
 #ifdef UKERNEL
            /* set the expire times to 0, causes
@@ -2682,7 +2784,7 @@ Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
 {
     char *tp;
     afs_int32 code;
-#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     size_t bufferSize;
 #else
     u_int bufferSize;
@@ -2892,7 +2994,7 @@ DECL_PIOCTL(PGetCacheSize)
     afs_int32 results[MAXGCSTATS];
     afs_int32 flags;
     struct dcache * tdc;
-    int i, size;
+    int i;
 
     AFS_STATCNT(PGetCacheSize);
 
@@ -2924,9 +3026,10 @@ DECL_PIOCTL(PGetCacheSize)
 
            tdc = afs_indexTable[i];
            if (tdc){
+               afs_size_t size = tdc->validPos;
+
                results[9]++;
-               size = tdc->validPos;
-               if ( 0 < size && size < (1<<12) ) results[10]++;
+               if ( 0 <= size && size < (1<<12) ) results[10]++;
                else if (size < (1<<14) ) results[11]++;
                else if (size < (1<<16) ) results[12]++;
                else if (size < (1<<18) ) results[13]++;
@@ -2990,13 +3093,7 @@ DECL_PIOCTL(PRemoveCallBack)
                 (tc, rxconn, code, &avc->f.fid, areq,
                  AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
 
-       ObtainWriteLock(&afs_xcbhash, 457);
-       afs_DequeueCallback(avc);
-       avc->callback = 0;
-       avc->f.states &= ~(CStatd | CUnique);
-       ReleaseWriteLock(&afs_xcbhash);
-       if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
-           osi_dnlc_purgedp(avc);
+       afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique);
     }
     ReleaseWriteLock(&avc->lock);
     return 0;
@@ -3050,7 +3147,7 @@ DECL_PIOCTL(PNewCell)
      * This whole logic is bogus, because it relies on the newer command
      * sending its 12th address as 0.
      */
-    if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
+    if (afs_pd_remaining(ain) < (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32))
        return EINVAL;
 
     newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
@@ -3247,7 +3344,7 @@ DECL_PIOCTL(PRemoveMount)
 
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);  /* test for error below */
     if (!tdc)
-       return ENOENT;
+       return EIO;
     Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
@@ -3262,16 +3359,16 @@ DECL_PIOCTL(PRemoveMount)
     tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
-       tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+       tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
     } else {
-       tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+       tvc = afs_GetVCache(&tfid, areq);
     }
     if (!tvc) {
-       code = ENOENT;
+       code = EIO;
        afs_PutDCache(tdc);
        goto out;
     }
-    if (tvc->mvstat != 1) {
+    if (tvc->mvstat != AFS_MVSTAT_MTPT) {
        afs_PutDCache(tdc);
        afs_PutVCache(tvc);
        code = EINVAL;
@@ -3422,46 +3519,28 @@ DECL_PIOCTL(PSetCellStatus)
     return 0;
 }
 
-/*!
- * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
- *
- * \ingroup pioctl
- *
- * \param[in] ain      not in use (args in avc)
- * \param[out] aout    not in use
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval EIO         Error if the afs daemon hasn't started yet
- *
- * \post
- *     Flush all cached contents of a volume.  Exactly what stays and what
- *     goes depends on the platform.
- *
- * \notes
- *     Does not flush a file that a user has open and is using, because
- *     it will be re-created on next write.  Also purges the dnlc,
- *     because things are screwed up.
- */
-DECL_PIOCTL(PFlushVolumeData)
+static int
+FlushVolumeData(struct VenusFid *afid, afs_ucred_t * acred)
 {
     afs_int32 i;
     struct dcache *tdc;
     struct vcache *tvc;
     struct volume *tv;
-    afs_int32 cell, volume;
+    afs_int32 all = 0;
+    afs_int32 cell = 0;
+    afs_int32 volume = 0;
     struct afs_q *tq, *uq;
+    int code = 0;
 #ifdef AFS_DARWIN80_ENV
     vnode_t vp;
 #endif
 
-    AFS_STATCNT(PFlushVolumeData);
-    if (!avc)
-       return EINVAL;
-    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
-       return EIO;             /* Inappropriate ioctl for device */
-
-    volume = avc->f.fid.Fid.Volume;    /* who to zap */
-    cell = avc->f.fid.Cell;
+    if (!afid) {
+       all = 1;
+    } else {
+       volume = afid->Fid.Volume;      /* who to zap */
+       cell = afid->Cell;
+    }
 
     /*
      * Clear stat'd flag from all vnodes from this volume; this will
@@ -3469,11 +3548,11 @@ DECL_PIOCTL(PFlushVolumeData)
      */
  loop:
     ObtainReadLock(&afs_xvcache);
-    i = VCHashV(&avc->f.fid);
-    for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
+    for (i = (afid ? VCHashV(afid) : 0); i < VCSIZE; i = (afid ? VCSIZE : i+1)) {
+       for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
            uq = QPrev(tq);
            tvc = QTOVH(tq);
-           if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
+           if (all || (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell)) {
                if (tvc->f.states & CVInit) {
                    ReleaseReadLock(&afs_xvcache);
                    afs_osi_Sleep(&tvc->f.states);
@@ -3481,11 +3560,9 @@ DECL_PIOCTL(PFlushVolumeData)
                }
 #ifdef AFS_DARWIN80_ENV
                if (tvc->f.states & CDeadVnode) {
-                   if (!(tvc->f.states & CBulkFetching)) {
-                       ReleaseReadLock(&afs_xvcache);
-                       afs_osi_Sleep(&tvc->f.states);
-                       goto loop;
-                   }
+                   ReleaseReadLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->f.states);
+                   goto loop;
                }
                vp = AFSTOV(tvc);
                if (vnode_get(vp))
@@ -3496,31 +3573,15 @@ DECL_PIOCTL(PFlushVolumeData)
                    AFS_GLOCK();
                    continue;
                }
-               if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
-                   AFS_GUNLOCK();
-                   vnode_recycle(AFSTOV(tvc));
-                   AFS_GLOCK();
-               }
 #else
-               AFS_FAST_HOLD(tvc);
+               if (osi_vnhold(tvc) != 0) {
+                   continue;
+               }
 #endif
                ReleaseReadLock(&afs_xvcache);
-#ifdef AFS_BOZONLOCK_ENV
-               afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
                ObtainWriteLock(&tvc->lock, 232);
-
-               ObtainWriteLock(&afs_xcbhash, 458);
-               afs_DequeueCallback(tvc);
-               tvc->f.states &= ~(CStatd | CDirty);
-               ReleaseWriteLock(&afs_xcbhash);
-               if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
-                   osi_dnlc_purgedp(tvc);
-               afs_TryToSmush(tvc, *acred, 1);
+               afs_ResetVCache(tvc, acred, 1);
                ReleaseWriteLock(&tvc->lock);
-#ifdef AFS_BOZONLOCK_ENV
-               afs_BozonUnlock(&tvc->pvnLock, tvc);
-#endif
 #ifdef AFS_DARWIN80_ENV
                vnode_put(AFSTOV(tvc));
 #endif
@@ -3530,6 +3591,7 @@ DECL_PIOCTL(PFlushVolumeData)
                AFS_FAST_RELE(tvc);
            }
        }
+    }
     ReleaseReadLock(&afs_xvcache);
 
 
@@ -3537,16 +3599,22 @@ DECL_PIOCTL(PFlushVolumeData)
     for (i = 0; i < afs_cacheFiles; i++) {
        if (!(afs_indexFlags[i] & IFEverUsed))
            continue;           /* never had any data */
-       tdc = afs_GetDSlot(i, NULL);
+       tdc = afs_GetValidDSlot(i);
+       if (!tdc) {
+            code = EIO;
+            break;
+       }
        if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
            ReleaseReadLock(&tdc->tlock);
-           if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
-               if (!(afs_indexFlags[i] & IFDataMod)) {
+           if (all || (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell)) {
+               if (!(afs_indexFlags[i] & (IFDataMod | IFFree | IFDiscarded))) {
                    /* if the file is modified, but has a ref cnt of only 1,
                     * then someone probably has the file open and is writing
                     * into it. Better to skip flushing such a file, it will be
                     * brought back immediately on the next write anyway.
                     *
+                    * Skip if already freed.
+                    *
                     * If we *must* flush, then this code has to be rearranged
                     * to call afs_storeAllSegments() first */
                    afs_FlushDCache(tdc);
@@ -3560,22 +3628,84 @@ DECL_PIOCTL(PFlushVolumeData)
     ReleaseWriteLock(&afs_xdcache);
 
     ObtainReadLock(&afs_xvolume);
-    for (i = 0; i < NVOLS; i++) {
+    for (i = all ? 0 : VHash(volume); i < NVOLS; i++) {
        for (tv = afs_volumes[i]; tv; tv = tv->next) {
-           if (tv->volume == volume) {
+           if (all || tv->volume == volume) {
                afs_ResetVolumeInfo(tv);
-               break;
+               if (!all)
+                   goto last;
            }
        }
     }
+ last:
     ReleaseReadLock(&afs_xvolume);
 
     /* probably, a user is doing this, probably, because things are screwed up.
      * maybe it's the dnlc's fault? */
     osi_dnlc_purge();
-    return 0;
+    return code;
 }
 
+/*!
+ * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use (args in avc)
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ *
+ * \post
+ *     Flush all cached contents of a volume.  Exactly what stays and what
+ *     goes depends on the platform.
+ *
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
+ */
+DECL_PIOCTL(PFlushVolumeData)
+{
+    AFS_STATCNT(PFlushVolumeData);
+    if (!avc)
+       return EINVAL;
+    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    return FlushVolumeData(&avc->f.fid, *acred);
+}
+
+/*!
+ * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ *
+ * \post
+ *     Flush all cached contents.  Exactly what stays and what
+ *     goes depends on the platform.
+ *
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
+ */
+DECL_PIOCTL(PFlushAllVolumeData)
+{
+    AFS_STATCNT(PFlushAllVolumeData);
+
+    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    return FlushVolumeData(NULL, *acred);
+}
 
 /*!
  * VIOCGETVCXSTATUS (41) - gets vnode x status
@@ -3753,8 +3883,8 @@ DECL_PIOCTL(PSetSysName)
            return EINVAL;
        num = count;
     }
-    if (afs_cr_gid(*acred) == RMTUSER_REQ ||
-       afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) {   /* Handles all exporters */
+    if (afs_rmtsys_enable && (afs_cr_gid(*acred) == RMTUSER_REQ ||
+       afs_cr_gid(*acred) == RMTUSER_REQ_PRIV)) {   /* Handles all exporters */
        if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
            return EPERM;
        }
@@ -3967,7 +4097,7 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
            afs_uint32 temp = sp->host.s_addr;
            srvr =
                afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
-                             WRITE_LOCK, (afsUUID *) 0, 0);
+                             WRITE_LOCK, (afsUUID *) 0, 0, NULL);
            srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
            afs_PutServer(srvr, WRITE_LOCK);
        }
@@ -4017,7 +4147,7 @@ DECL_PIOCTL(PSetSPrefs)
 
     ssp = (struct setspref *)ainPtr;
     if (ainSize < (sizeof(struct setspref)
-                  + sizeof(struct spref) * ssp->num_servers-1))
+                  + sizeof(struct spref) * (ssp->num_servers-1)))
        return EINVAL;
 
     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
@@ -4537,8 +4667,8 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
 #ifdef AFS_AIX51_ENV
     newcred->cr_groupset.gs_union.un_groups[0] = g0;
     newcred->cr_groupset.gs_union.un_groups[1] = g1;
-#elif defined(AFS_LINUX26_ENV)
-# ifdef AFS_LINUX26_ONEGROUP_ENV
+#elif defined(AFS_LINUX_ENV)
+# ifdef AFS_PAG_ONEGROUP_ENV
     afs_set_cr_group_info(newcred, groups_alloc(1)); /* nothing sets this */
     l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
     h = ((g0-0x3f00) >> 14);
@@ -4550,17 +4680,22 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
 # endif
 #elif defined(AFS_SUN510_ENV)
+# ifdef AFS_PAG_ONEGROUP_ENV
+    gids[0] = afs_get_pag_from_groups(g0, g1);
+    crsetgroups(newcred, 1, gids);
+# else
     gids[0] = g0;
     gids[1] = g1;
     crsetgroups(newcred, 2, gids);
+# endif /* !AFS_PAG_ONEGROUP_ENV */
 #else
     newcred->cr_groups[0] = g0;
     newcred->cr_groups[1] = g1;
 #endif
 #ifdef AFS_AIX_ENV
     newcred->cr_ngrps = 2;
-#elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
-# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
+#elif !defined(AFS_LINUX_ENV) && !defined(AFS_SUN510_ENV)
+# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_FBSD_ENV)
     newcred->cr_ngroups = 2;
 # else
     for (i = 2; i < NGROUPS; i++)
@@ -4705,10 +4840,6 @@ DECL_PIOCTL(PSetCPrefs)
 
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
-#if 0                          /* num_servers is unsigned */
-    if (sin->num_servers < 0)
-       return EINVAL;
-#endif
     if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
        return ENOMEM;
 
@@ -4746,79 +4877,56 @@ DECL_PIOCTL(PFlushMount)
 {
     afs_int32 code;
     struct vcache *tvc;
-    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
     char *mount;
     struct sysname_info sysState;
-    afs_size_t offset, len;
 
     AFS_STATCNT(PFlushMount);
+    memset(&sysState, 0, sizeof(sysState));
+
     if (!avc)
        return EINVAL;
 
     if (afs_pd_getStringPtr(ain, &mount) != 0)
        return EINVAL;
 
-    code = afs_VerifyVCache(avc, areq);
-    if (code)
-       return code;
-    if (vType(avc) != VDIR) {
-       return ENOTDIR;
-    }
-    tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
-    if (!tdc)
-       return ENOENT;
-    Check_AtSys(avc, mount, &sysState, areq);
-    ObtainReadLock(&tdc->lock);
-    do {
-       code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
-    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
-    ReleaseReadLock(&tdc->lock);
-    afs_PutDCache(tdc);                /* we're done with the data */
-    bufp = sysState.name;
+    code = afs_LookupName(avc, areq, mount, &sysState, &tfid);
     if (code) {
        goto out;
     }
+
+    bufp = sysState.name;
     tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = avc->f.fid.Fid.Volume;
     if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
-       tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+       tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
     } else {
-       tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+       tvc = afs_GetVCache(&tfid, areq);
     }
     if (!tvc) {
-       code = ENOENT;
+       code = EIO;
        goto out;
     }
-    if (tvc->mvstat != 1) {
+    if (tvc->mvstat != AFS_MVSTAT_MTPT) {
        afs_PutVCache(tvc);
        code = EINVAL;
        goto out;
     }
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
     ObtainWriteLock(&tvc->lock, 649);
-    ObtainWriteLock(&afs_xcbhash, 650);
-    afs_DequeueCallback(tvc);
-    tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
-    ReleaseWriteLock(&afs_xcbhash);
+    /* next reference will re-stat cache entry */
+    afs_StaleVCacheFlags(tvc, 0, CDirty);
     /* now find the disk cache entries */
     afs_TryToSmush(tvc, *acred, 1);
-    osi_dnlc_purgedp(tvc);
     if (tvc->linkData && !(tvc->f.states & CCore)) {
        afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
        tvc->linkData = NULL;
     }
     ReleaseWriteLock(&tvc->lock);
-#ifdef AFS_BOZONLOCK_ENV
-    afs_BozonUnlock(&tvc->pvnLock, tvc);
-#endif
     afs_PutVCache(tvc);
   out:
     if (sysState.allocked)
-       osi_FreeLargeSpace(bufp);
+       osi_FreeLargeSpace(sysState.name);
     return code;
 }
 
@@ -4905,8 +5013,8 @@ DECL_PIOCTL(PRxStatPeer)
 
 DECL_PIOCTL(PPrefetchFromTape)
 {
-    afs_int32 code, code1;
-    afs_int32 bytes, outval;
+    afs_int32 code;
+    afs_int32 outval;
     struct afs_conn *tc;
     struct rx_call *tcall;
     struct AFSVolSync tsync;
@@ -4917,7 +5025,7 @@ DECL_PIOCTL(PPrefetchFromTape)
     struct vcache *tvc;
     struct rx_connection *rxconn;
 
-    AFS_STATCNT(PSetAcl);
+    AFS_STATCNT(PPrefetchFromTape);
     if (!avc)
        return EINVAL;
 
@@ -4930,7 +5038,7 @@ DECL_PIOCTL(PPrefetchFromTape)
     tfid.Fid.Vnode = Fid->Vnode;
     tfid.Fid.Unique = Fid->Unique;
 
-    tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+    tvc = afs_GetVCache(&tfid, areq);
     if (!tvc) {
        afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
                   ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
@@ -4949,11 +5057,11 @@ DECL_PIOCTL(PPrefetchFromTape)
                StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
                                     0);
            if (!code) {
-               bytes = rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
+               rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
                code =
                    EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
            }
-           code1 = rx_EndCall(tcall, code);
+           code = rx_EndCall(tcall, code);
            RX_AFS_GLOCK();
        } else
            code = -1;
@@ -5001,7 +5109,7 @@ DECL_PIOCTL(PFsCmd)
     tfid.Fid.Vnode = Fid->Vnode;
     tfid.Fid.Unique = Fid->Unique;
 
-    tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+    tvc = afs_GetVCache(&tfid, areq);
     afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
               ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
     if (!tvc)
@@ -5013,8 +5121,7 @@ DECL_PIOCTL(PFsCmd)
            if (tc) {
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_FsCmd(rxconn, Fid, Inputs,
-                                       (struct FsCmdOutputs *)aout);
+                   RXAFS_FsCmd(rxconn, Fid, Inputs, Outputs);
                RX_AFS_GLOCK();
            } else
                code = -1;
@@ -5056,7 +5163,7 @@ DECL_PIOCTL(PNewUuid)
     return 0;
 }
 
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
 
 DECL_PIOCTL(PSetCachingThreshold)
 {
@@ -5082,7 +5189,12 @@ DECL_PIOCTL(PSetCachingThreshold)
        cache_bypass_threshold = threshold;
         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
        /* TODO:  move to separate pioctl, or enhance pioctl */
-       cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
+       if (threshold == AFS_CACHE_BYPASS_DISABLED)
+           cache_bypass_strategy = NEVER_BYPASS_CACHE;
+       else if (!threshold)
+           cache_bypass_strategy = ALWAYS_BYPASS_CACHE;
+       else
+           cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
     }
 
     /* Return the current size threshold */
@@ -5097,12 +5209,12 @@ DECL_PIOCTL(PSetCachingThreshold)
 DECL_PIOCTL(PCallBackAddr)
 {
 #ifndef UKERNEL
-    afs_uint32 addr, code;
+    afs_uint32 code;
     int srvAddrCount;
     struct server *ts;
     struct srvAddr *sa;
     struct afs_conn *tc;
-    afs_int32 i, j;
+    afs_int32 i, j, addr;
     struct unixuser *tu;
     struct srvAddr **addrs;
     struct rx_connection *rxconn;
@@ -5111,7 +5223,7 @@ DECL_PIOCTL(PCallBackAddr)
     if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (!afs_osi_suser(acred))
+    if (!afs_osi_suser(*acred))
        return EACCES;
 
     if (afs_pd_getInt(ain, &addr) != 0)
@@ -5166,28 +5278,33 @@ DECL_PIOCTL(PCallBackAddr)
        if (!ts->cell)          /* not really an active server, anyway, it must */
            continue;           /* have just been added by setsprefs */
 
+       if ((sa->sa_flags & SRVADDR_ISDOWN) == 0 && !afs_HaveCallBacksFrom(ts)) {
+           /* Server is up, and we have no active callbacks from it. */
+           continue;
+       }
+
        /* get a connection, even if host is down; bumps conn ref count */
        tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
        tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
-                         1 /*force */ , 1 /*create */ , SHARED_LOCK, &rxconn);
+                         1 /*force */ , 1 /*create */ , SHARED_LOCK, 0, &rxconn);
        afs_PutUser(tu, SHARED_LOCK);
        if (!tc)
            continue;
 
-       if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
-           if (sa->sa_flags & SRVADDR_ISDOWN) {
-               rx_SetConnDeadTime(rxconn, 3);
-           }
+       if (sa->sa_flags & SRVADDR_ISDOWN) {
+           rx_SetConnDeadTime(rxconn, 3);
+       }
 #ifdef RX_ENABLE_LOCKS
-           AFS_GUNLOCK();
+       AFS_GUNLOCK();
 #endif /* RX_ENABLE_LOCKS */
-           code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
+       code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
 #ifdef RX_ENABLE_LOCKS
-           AFS_GLOCK();
+       AFS_GLOCK();
 #endif /* RX_ENABLE_LOCKS */
-       }
+
        afs_PutConn(tc, rxconn, SHARED_LOCK);   /* done with it now */
     }                          /* Outer loop over addrs */
+    afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
 #endif /* UKERNEL */
     return 0;
 }
@@ -5277,7 +5394,7 @@ DECL_PIOCTL(PSetTokens2)
     int i, cellNum, primaryFlag;
     XDR xdrs;
     struct unixuser *tu;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     struct ktc_setTokenData tokenSet;
     struct ktc_tokenUnion decodedToken;
 
@@ -5313,8 +5430,12 @@ DECL_PIOCTL(PSetTokens2)
 
     if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
        if (_settok_setParentPag(acred) == 0) {
-           afs_InitReq(&treq, *acred);
-           areq = &treq;
+           code = afs_CreateReq(&treq, *acred);
+           if (code) {
+               xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+               return code;
+           }
+           areq = treq;
        }
     }
 
@@ -5369,18 +5490,40 @@ DECL_PIOCTL(PSetTokens2)
 out:
     afs_ResetUserConns(tu);
     afs_PutUser(tu, WRITE_LOCK);
+    afs_DestroyReq(treq);
 
     return code;
 }
 
+/*!
+ * VIOC_GETTOK2 (7) - Return a user's nth token, or token for a cell by
+ *                     name.
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      EITHER  a string cellname
+ *                     OR      an integer 'iterator' to specify the nth
+ *                             token.
+ *
+ * \param[out] aout    XDR-encoded tokens from the user's tokenJar
+ *
+ * \retval EINVAL      invalid input (bad integer, or invalid string)
+ *                     unable to extract token(s)
+ * \retval ENOMEM      insufficient memory (returned from called routines)
+ * \retval EDOM                (integer) request was out of bounds or the user has no tokens
+ * \retval ENOTCONN    user found but has no valid token(s)
+ * \retval E2BIG       token(s) do not fit in the output buffer
+ *
+ */
 DECL_PIOCTL(PGetTokens2)
 {
-    struct cell *cell;
+    struct cell *cell = NULL;
     struct unixuser *tu = NULL;
     afs_int32 iterator;
     char *cellName = NULL;
     afs_int32 cellNum;
     int code = 0;
+    int integer_in = 1;                /* assume integer input */
     time_t now;
     XDR xdrs;
     struct ktc_setTokenData tokenSet;
@@ -5392,11 +5535,23 @@ DECL_PIOCTL(PGetTokens2)
     memset(&tokenSet, 0, sizeof(tokenSet));
 
     /* No input data - return tokens for primary cell */
-    /* 4 octets of data is an iterator count */
+    /* 4 octets of data is PROBABLY an iterator count */
     /* Otherwise, treat as string & return tokens for that cell name */
 
     if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
-       /* Integer iterator - return tokens for the n'th cell found for user */
+       char *scratch = afs_pd_where(ain);
+
+       if (scratch[3] == '\0' && strlen(scratch) == 3)
+           integer_in = 0;
+    } else {
+       integer_in = 0;
+    }
+
+    if (integer_in) {
+       /* The misleadingly-named getNthCell actually return the nth valid
+        * token found for the specified user; there can never be a gap
+        * in the ordinals at this level.
+        */
        if (afs_pd_getInt(ain, &iterator) != 0)
            return EINVAL;
        tu = getNthCell(areq->uid, iterator);
@@ -5469,7 +5624,7 @@ DECL_PIOCTL(PNFSNukeCreds)
            return EACCES;
        }
        afs_PutUser(tu, SHARED_LOCK);
-    } else if (!afs_osi_suser(acred)) {
+    } else if (!afs_osi_suser(*acred)) {
        return EACCES;
     }
 
@@ -5477,12 +5632,15 @@ DECL_PIOCTL(PNFSNukeCreds)
     for (i = 0; i < NUSERS; i++) {
        for (tu = afs_users[i]; tu; tu = tu->next) {
            if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
-               tu->states &= ~UHasTokens;
-               afs_FreeTokens(&tu->tokens);
                tu->refCount++;
                ReleaseWriteLock(&afs_xuser);
+
+               afs_LockUser(tu, WRITE_LOCK, 367);
+
+               tu->states &= ~UHasTokens;
+               afs_FreeTokens(&tu->tokens);
                afs_ResetUserConns(tu);
-               tu->refCount--;
+               afs_PutUser(tu, WRITE_LOCK);
                ObtainWriteLock(&afs_xuser, 228);
 #ifdef UKERNEL
                /* set the expire times to 0, causes