Linux: drop GLOCK before calling dput
[openafs.git] / src / afs / afs_pioctl.c
index 08d47f0..0836b87 100644 (file)
@@ -568,8 +568,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 +666,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 +676,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,13 +691,7 @@ 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);
 
@@ -730,7 +708,7 @@ afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
 {
     struct afs_ioctl_sys ua, *uap = &ua;
     struct vcache *tvc;
-    int ioctlDone = 0, code = 0;
+    int code = 0;
 
     AFS_STATCNT(afs_xioctl);
     ua.com = com;
@@ -752,7 +730,6 @@ afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
            code = HandleIoctl(tvc, uap->com, datap);
            osi_FreeSmallSpace(datap);
            AFS_GUNLOCK();
-           ioctlDone = 1;
        }
        else
            code = EINVAL;
@@ -811,6 +788,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;
@@ -819,7 +800,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;
@@ -828,14 +809,19 @@ 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);
+#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 */
@@ -848,19 +834,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;
@@ -868,14 +866,21 @@ 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)
+#  if (__FreeBSD_version >= 900044)
+       return sys_ioctl(td, uap);
+#  else
        return ioctl(td, uap);
+#  endif
 # 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
     }
 
@@ -1234,7 +1239,13 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #endif /* AFS_NEED_CLIENTCONTEXT */
     if (vp) {
 #ifdef AFS_LINUX22_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 (VOP_ISLOCKED(vp))
@@ -1424,6 +1435,7 @@ DECL_PIOCTL(PSetAcl)
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetAcl);
@@ -1437,19 +1449,19 @@ DECL_PIOCTL(PSetAcl)
        return EINVAL;
 
     do {
-       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tconn) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
+               RXAFS_StoreACL(rxconn, (struct AFSFid *)&avc->f.fid.Fid,
                               &acl, &OutStatus, &tsync);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
+            (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
              SHARED_LOCK, NULL));
 
     /* now we've forgotten all of the access info */
@@ -1564,6 +1576,7 @@ DECL_PIOCTL(PGetAcl)
     afs_int32 code;
     struct afs_conn *tconn;
     struct AFSFid Fid;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetAcl);
@@ -1586,18 +1599,18 @@ DECL_PIOCTL(PGetAcl)
     }
     acl.AFSOpaque_val = aout->ptr;
     do {
-       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tconn) {
            acl.AFSOpaque_val[0] = '\0';
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
            RX_AFS_GUNLOCK();
-           code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
+           code = RXAFS_FetchACL(rxconn, &Fid, &acl, &OutStatus, &tsync);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
+            (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
              SHARED_LOCK, NULL));
 
     if (code == 0) {
@@ -1760,12 +1773,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 {
@@ -1785,6 +1799,10 @@ _settok_tokenCell(char *cellName, int *cellNum, int *primary) {
     int t1;
     struct cell *cell;
 
+    if (primary) {
+       *primary = 0;
+    }
+
     if (cellName && strlen(cellName) > 0) {
        cell = afs_GetCellByName(cellName, READ_LOCK);
     } else {
@@ -1955,6 +1973,7 @@ DECL_PIOCTL(PGetVolumeStatus)
     afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     char *Name;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     osi_Assert(offLineMsg != NULL);
@@ -1966,19 +1985,19 @@ DECL_PIOCTL(PGetVolumeStatus)
     }
     Name = volName;
     do {
-       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
+               RXAFS_GetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &volstat,
                                      &Name, &offLineMsg, &motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
+            (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
              SHARED_LOCK, NULL));
 
     if (code)
@@ -2032,6 +2051,7 @@ DECL_PIOCTL(PSetVolumeStatus)
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
     struct volume *tvp;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
@@ -2079,19 +2099,19 @@ DECL_PIOCTL(PSetVolumeStatus)
        storeStat.Mask |= AFS_SETMAXQUOTA;
     }
     do {
-       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
+               RXAFS_SetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &storeStat,
                                      volName, offLineMsg, motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
+            (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
              SHARED_LOCK, NULL));
 
     if (code)
@@ -2133,7 +2153,7 @@ DECL_PIOCTL(PFlush)
     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);
@@ -2259,6 +2279,10 @@ getNthCell(afs_int32 uid, afs_int32 iterator) {
        tu->refCount++;
     }
     ReleaseReadLock(&afs_xuser);
+    if (tu) {
+       afs_LockUser(tu, READ_LOCK, 0);
+    }
+
 
     return tu;
 }
@@ -2409,10 +2433,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
@@ -2423,7 +2450,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
@@ -2675,7 +2702,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;
@@ -2954,6 +2981,7 @@ DECL_PIOCTL(PRemoveCallBack)
     struct AFSCallBack CallBacks_Array[1];
     struct AFSCBFids theFids;
     struct AFSCBs theCBs;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PRemoveCallBack);
@@ -2969,17 +2997,17 @@ DECL_PIOCTL(PRemoveCallBack)
     CallBacks_Array[0].CallBackType = CB_DROPPED;
     if (avc->callback) {
        do {
-           tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+           tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
            if (tc) {
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
                RX_AFS_GUNLOCK();
-               code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
+               code = RXAFS_GiveUpCallBacks(rxconn, &theFids, &theCBs);
                RX_AFS_GLOCK();
                XSTATS_END_TIME;
            }
            /* don't set code on failure since we wouldn't use it */
        } while (afs_Analyze
-                (tc, code, &avc->f.fid, areq,
+                (tc, rxconn, code, &avc->f.fid, areq,
                  AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
 
        ObtainWriteLock(&afs_xcbhash, 457);
@@ -3220,6 +3248,7 @@ DECL_PIOCTL(PRemoveMount)
     struct AFSFetchStatus OutDirStatus;
     struct VenusFid tfid;
     struct AFSVolSync tsync;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     /* "ain" is the name of the file in this dir to remove */
@@ -3287,19 +3316,19 @@ DECL_PIOCTL(PRemoveMount)
     ObtainWriteLock(&avc->lock, 231);
     osi_dnlc_remove(avc, bufp, tvc);
     do {
-       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
+               RXAFS_RemoveFile(rxconn, (struct AFSFid *)&avc->f.fid.Fid, bufp,
                                 &OutDirStatus, &tsync);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
+            (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
              SHARED_LOCK, NULL));
 
     if (code) {
@@ -3472,11 +3501,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))
@@ -3487,11 +3514,6 @@ 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);
 #endif
@@ -3500,14 +3522,7 @@ DECL_PIOCTL(PFlushVolumeData)
                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);
@@ -3528,16 +3543,21 @@ 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) {
+           continue;
+       }
        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 (!(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);
@@ -3958,7 +3978,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);
        }
@@ -4008,7 +4028,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,
@@ -4896,8 +4916,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;
@@ -4906,8 +4926,9 @@ DECL_PIOCTL(PPrefetchFromTape)
     struct VenusFid tfid;
     struct AFSFid *Fid;
     struct vcache *tvc;
+    struct rx_connection *rxconn;
 
-    AFS_STATCNT(PSetAcl);
+    AFS_STATCNT(PPrefetchFromTape);
     if (!avc)
        return EINVAL;
 
@@ -4930,25 +4951,25 @@ DECL_PIOCTL(PPrefetchFromTape)
               ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
 
     do {
-       tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
        if (tc) {
 
            RX_AFS_GUNLOCK();
-           tcall = rx_NewCall(tc->id);
+           tcall = rx_NewCall(rxconn);
            code =
                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;
     } while (afs_Analyze
-            (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
+            (tc, rxconn, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
              SHARED_LOCK, NULL));
     /* This call is done only to have the callback things handled correctly */
     afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
@@ -4969,6 +4990,7 @@ DECL_PIOCTL(PFsCmd)
     struct FsCmdOutputs *Outputs;
     struct VenusFid tfid;
     struct AFSFid *Fid;
+    struct rx_connection *rxconn;
 
     if (!avc)
        return EINVAL;
@@ -4998,17 +5020,17 @@ DECL_PIOCTL(PFsCmd)
 
     if (Inputs->command) {
        do {
-           tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
+           tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
            if (tc) {
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_FsCmd(tc->id, Fid, Inputs,
+                   RXAFS_FsCmd(rxconn, Fid, Inputs,
                                        (struct FsCmdOutputs *)aout);
                RX_AFS_GLOCK();
            } else
                code = -1;
        } while (afs_Analyze
-                (tc, code, &tvc->f.fid, areq,
+                (tc, rxconn, code, &tvc->f.fid, areq,
                  AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
        /* This call is done to have the callback things handled correctly */
        afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
@@ -5094,6 +5116,7 @@ DECL_PIOCTL(PCallBackAddr)
     afs_int32 i, j;
     struct unixuser *tu;
     struct srvAddr **addrs;
+    struct rx_connection *rxconn;
 
     /*AFS_STATCNT(PCallBackAddr); */
     if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
@@ -5157,24 +5180,24 @@ DECL_PIOCTL(PCallBackAddr)
        /* 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);
+                         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(tc->id, 3);
+               rx_SetConnDeadTime(rxconn, 3);
            }
 #ifdef RX_ENABLE_LOCKS
            AFS_GUNLOCK();
 #endif /* RX_ENABLE_LOCKS */
-           code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
+           code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
 #ifdef RX_ENABLE_LOCKS
            AFS_GLOCK();
 #endif /* RX_ENABLE_LOCKS */
        }
-       afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
+       afs_PutConn(tc, rxconn, SHARED_LOCK);   /* done with it now */
     }                          /* Outer loop over addrs */
 #endif /* UKERNEL */
     return 0;
@@ -5363,7 +5386,7 @@ out:
 
 DECL_PIOCTL(PGetTokens2)
 {
-    struct cell *cell;
+    struct cell *cell = NULL;
     struct unixuser *tu = NULL;
     afs_int32 iterator;
     char *cellName = NULL;
@@ -5465,12 +5488,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