FBSD: deal with kernel API rename
[openafs.git] / src / afs / afs_pioctl.c
index ae5488b..2589b79 100644 (file)
@@ -27,6 +27,7 @@
 #include "afs/vice.h"
 #include "afs/afs_bypasscache.h"
 #include "rx/rx_globals.h"
+#include "token.h"
 
 struct VenusFid afs_rootFid;
 afs_int32 afs_waitForever = 0;
@@ -106,31 +107,26 @@ afs_pd_skip(struct afs_pdata *apd, size_t skip)
 }
 
 static_inline int
-afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
+afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
 {
-    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+    if (apd == NULL || apd->remaining < bytes)
        return EINVAL;
-    apd->remaining -= sizeof(afs_int32);
-    *val = *(afs_int32 *)apd->ptr;
-    apd->ptr += sizeof(afs_int32);
+    apd->remaining -= bytes;
+    memcpy(dest, apd->ptr, bytes);
+    apd->ptr += bytes;
     return 0;
 }
 
 static_inline int
-afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
+afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
 {
-    return afs_pd_getInt(apd, (afs_int32 *)val);
+    return afs_pd_getBytes(apd, val, sizeof(*val));
 }
 
 static_inline int
-afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
+afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
 {
-    if (apd == NULL || apd->remaining < bytes)
-       return EINVAL;
-    apd->remaining -= bytes;
-    memcpy(dest, apd->ptr, bytes);
-    apd->ptr += bytes;
-    return 0;
+    return afs_pd_getBytes(apd, val, sizeof(*val));
 }
 
 static_inline void *
@@ -149,6 +145,23 @@ afs_pd_inline(struct afs_pdata *apd, size_t bytes)
     return ret;
 }
 
+static_inline void
+afs_pd_xdrStart(struct afs_pdata *apd, XDR *xdrs, enum xdr_op op) {
+    xdrmem_create(xdrs, apd->ptr, apd->remaining, op);
+}
+
+static_inline void
+afs_pd_xdrEnd(struct afs_pdata *apd, XDR *xdrs) {
+    size_t pos;
+
+    pos = xdr_getpos(xdrs);
+    apd->ptr += pos;
+    apd->remaining -= pos;
+    xdr_destroy(xdrs);
+}
+
+
+
 static_inline int
 afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen)
 {
@@ -180,18 +193,6 @@ afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
 }
 
 static_inline int
-afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
-{
-    if (apd == NULL || apd->remaining < sizeof(afs_int32))
-       return E2BIG;
-    *(afs_int32 *)apd->ptr = val;
-    apd->ptr += sizeof(afs_int32);
-    apd->remaining -= sizeof(afs_int32);
-
-    return 0;
-}
-
-static_inline int
 afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
 {
     if (apd == NULL || apd->remaining < len)
@@ -203,6 +204,12 @@ afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
 }
 
 static_inline int
+afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
+{
+    return afs_pd_putBytes(apd, &val, sizeof(val));
+}
+
+static_inline int
 afs_pd_putString(struct afs_pdata *apd, char *str) {
 
     /* Add 1 so we copy the NULL too */
@@ -245,11 +252,13 @@ DECL_PIOCTL(PGetFileCell);
 DECL_PIOCTL(PGetWSCell);
 DECL_PIOCTL(PGetUserCell);
 DECL_PIOCTL(PSetTokens);
+DECL_PIOCTL(PSetTokens2);
 DECL_PIOCTL(PGetVolumeStatus);
 DECL_PIOCTL(PSetVolumeStatus);
 DECL_PIOCTL(PFlush);
 DECL_PIOCTL(PNewStatMount);
 DECL_PIOCTL(PGetTokens);
+DECL_PIOCTL(PGetTokens2);
 DECL_PIOCTL(PUnlog);
 DECL_PIOCTL(PMariner);
 DECL_PIOCTL(PCheckServers);
@@ -293,7 +302,7 @@ DECL_PIOCTL(PNFSNukeCreds);
 DECL_PIOCTL(PNewUuid);
 DECL_PIOCTL(PPrecache);
 DECL_PIOCTL(PGetPAG);
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 DECL_PIOCTL(PSetCachingThreshold);
 #endif
 
@@ -404,8 +413,8 @@ static pioctlFunction CpioctlSw[] = {
     PBogus,                     /* 4 */
     PDiscon,                    /* 5 -- get/set discon mode */
     PBogus,                     /* 6 */
-    PBogus,                     /* 7 */
-    PBogus,                     /* 8 */
+    PGetTokens2,                /* 7 */
+    PSetTokens2,                /* 8 */
     PNewUuid,                   /* 9 */
     PBogus,                     /* 10 */
     PBogus,                     /* 11 */
@@ -416,7 +425,7 @@ static pioctlFunction CpioctlSw[] = {
 static pioctlFunction OpioctlSw[]  = {
     PBogus,                    /* 0 */
     PNFSNukeCreds,             /* 1 -- nuke all creds for NFS client */
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
 #else
     PNoop                       /* 2 -- get/set cache-bypass size threshold */
@@ -658,19 +667,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))) {
@@ -684,11 +683,7 @@ afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
                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);
@@ -698,13 +693,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);
 
@@ -721,7 +710,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;
@@ -743,7 +732,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;
@@ -802,6 +790,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;
@@ -810,7 +802,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;
@@ -819,14 +811,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 */
@@ -839,19 +836,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;
@@ -859,14 +868,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
     }
 
@@ -1334,7 +1350,8 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     if (code)
        goto out;
 
-    if (function == 8 && device == 'V') {      /* PGetTokens */
+    if ((function == 8 && device == 'V') ||
+       (function == 7 && device == 'C')) {     /* PGetTokens */
        code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
     } else {
        code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
@@ -1414,6 +1431,7 @@ DECL_PIOCTL(PSetAcl)
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetAcl);
@@ -1427,19 +1445,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 */
@@ -1554,6 +1572,7 @@ DECL_PIOCTL(PGetAcl)
     afs_int32 code;
     struct afs_conn *tconn;
     struct AFSFid Fid;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetAcl);
@@ -1576,18 +1595,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) {
@@ -1750,12 +1769,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 {
@@ -1769,6 +1789,51 @@ DECL_PIOCTL(PGetUserCell)
     return 0;
 }
 
+/* Work out which cell we're changing tokens for */
+static_inline int
+_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 {
+       cell = afs_GetPrimaryCell(READ_LOCK);
+       if (primary)
+           *primary = 1;
+    }
+    if (!cell) {
+       t1 = afs_initState;
+       if (t1 < 101)
+           return EIO;
+       else
+           return ESRCH;
+    }
+    *cellNum = cell->cellNum;
+    afs_PutCell(cell, READ_LOCK);
+
+    return 0;
+}
+
+
+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
+    return setpag(cred, -1, &pag, 1);
+#endif
+}
+
 /*!
  * VIOCSETTOK (3) - Set authentication tokens
  *
@@ -1791,10 +1856,11 @@ DECL_PIOCTL(PGetUserCell)
  */
 DECL_PIOCTL(PSetTokens)
 {
-    afs_int32 i;
+    afs_int32 cellNum;
+    afs_int32 size;
+    afs_int32 code;
     struct unixuser *tu;
     struct ClearToken clear;
-    struct cell *tcell;
     char *stp;
     char *cellName;
     int stLen;
@@ -1815,9 +1881,9 @@ DECL_PIOCTL(PSetTokens)
     if (afs_pd_skip(ain, stLen) != 0)
        return EINVAL;
 
-    if (afs_pd_getInt(ain, &i) != 0)
+    if (afs_pd_getInt(ain, &size) != 0)
        return EINVAL;
-    if (i != sizeof(struct ClearToken))
+    if (size != sizeof(struct ClearToken))
        return EINVAL;
 
     if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
@@ -1843,36 +1909,25 @@ DECL_PIOCTL(PSetTokens)
        if (afs_pd_getStringPtr(ain, &cellName) != 0)
            return EINVAL;
 
-       /* rest is cell name, look it up */
-       tcell = afs_GetCellByName(cellName, READ_LOCK);
-       if (!tcell)
-           goto nocell;
+       code = _settok_tokenCell(cellName, &cellNum, NULL);
+       if (code)
+           return code;
     } else {
        /* default to primary cell, primary id */
-       flag = 1;               /* primary id */
-       tcell = afs_GetPrimaryCell(READ_LOCK);
-       if (!tcell)
-           goto nocell;
+       code = _settok_tokenCell(NULL, &cellNum, &flag);
+       if (code)
+           return code;
     }
-    i = tcell->cellNum;
-    afs_PutCell(tcell, READ_LOCK);
+
     if (set_parent_pag) {
-       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);
-       if (!setpag(osi_curproc(), acred, -1, &pag, 1)) {
-#else
-       if (!setpag(acred, -1, &pag, 1)) {
-#endif
+       if (_settok_setParentPag(acred) == 0) {
            afs_InitReq(&treq, *acred);
            areq = &treq;
        }
     }
+
     /* now we just set the tokens */
-    tu = afs_GetUser(areq->uid, i, WRITE_LOCK);        /* i has the cell # */
+    tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
     /* Set tokens destroys any that are already there */
     afs_FreeTokens(&tu->tokens);
     afs_AddRxkadToken(&tu->tokens, stp, stLen, &clear);
@@ -1889,16 +1944,6 @@ DECL_PIOCTL(PSetTokens)
     afs_PutUser(tu, WRITE_LOCK);
 
     return 0;
-
-  nocell:
-    {
-       int t1;
-       t1 = afs_initState;
-       if (t1 < 101)
-           return EIO;
-       else
-           return ESRCH;
-    }
 }
 
 /*!
@@ -1924,8 +1969,11 @@ DECL_PIOCTL(PGetVolumeStatus)
     afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     char *Name;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
+    osi_Assert(offLineMsg != NULL);
+    osi_Assert(motd != NULL);
     AFS_STATCNT(PGetVolumeStatus);
     if (!avc) {
        code = EINVAL;
@@ -1933,19 +1981,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)
@@ -1999,6 +2047,7 @@ DECL_PIOCTL(PSetVolumeStatus)
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
     struct volume *tvp;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
@@ -2046,19 +2095,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)
@@ -2202,6 +2251,38 @@ DECL_PIOCTL(PNewStatMount)
 }
 
 /*!
+ * A helper function to get the n'th cell which a particular user has tokens
+ * for. This is racy. If new tokens are added whilst we're iterating, then
+ * we may return some cells twice. If tokens expire mid run, then we'll
+ * miss some cells from our output. So, could be better, but that would
+ * require an interface change.
+ */
+
+static struct unixuser *
+getNthCell(afs_int32 uid, afs_int32 iterator) {
+    int i;
+    struct unixuser *tu = NULL;
+
+    i = UHash(uid);
+    ObtainReadLock(&afs_xuser);
+    for (tu = afs_users[i]; tu; tu = tu->next) {
+       if (tu->uid == uid && (tu->states & UHasTokens)) {
+           if (iterator-- == 0)
+           break;      /* are we done yet? */
+       }
+    }
+    if (tu) {
+       tu->refCount++;
+    }
+    ReleaseReadLock(&afs_xuser);
+    if (tu) {
+       afs_LockUser(tu, READ_LOCK, 0);
+    }
+
+
+    return tu;
+}
+/*!
  * VIOCGETTOK (8) - Get authentication tokens
  *
  * \ingroup pioctl
@@ -2228,11 +2309,11 @@ DECL_PIOCTL(PNewStatMount)
 DECL_PIOCTL(PGetTokens)
 {
     struct cell *tcell;
-    afs_int32 i;
-    struct unixuser *tu;
+    struct unixuser *tu = NULL;
     union tokenUnion *token;
     afs_int32 iterator = 0;
     int newStyle;
+    int cellNum;
     int code = E2BIG;
 
     AFS_STATCNT(PGetTokens);
@@ -2253,27 +2334,13 @@ DECL_PIOCTL(PGetTokens)
        if (afs_pd_getInt(ain, &iterator) != 0)
            return EINVAL;
     }
-    i = UHash(areq->uid);
-    ObtainReadLock(&afs_xuser);
-    for (tu = afs_users[i]; tu; tu = tu->next) {
-       if (newStyle) {
-           if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
-               if (iterator-- == 0)
-                   break;      /* are we done yet? */
-           }
-       } else {
-           if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
-               break;
-       }
-    }
-    if (tu) {
-       /*
-        * No need to hold a read lock on each user entry
-        */
-       tu->refCount++;
+    if (newStyle) {
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+       cellNum = afs_GetPrimaryCellNum();
+       if (cellNum)
+           tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
     }
-    ReleaseReadLock(&afs_xuser);
-
     if (!tu) {
        return EDOM;
     }
@@ -2286,6 +2353,11 @@ DECL_PIOCTL(PGetTokens)
     }
     token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
 
+    /* If they don't have an RXKAD token, but do have other tokens,
+     * then sadly there's nothing this interface can do to help them. */
+    if (token == NULL)
+       return ENOTCONN;
+
     /* for compat, we try to return 56 byte tix if they fit */
     iterator = token->rxkad.ticketLen;
     if (iterator < 56)
@@ -2357,10 +2429,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
@@ -2371,7 +2446,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
@@ -2579,7 +2654,7 @@ DECL_PIOCTL(PCheckAuth)
 {
     int i;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct sa_conn_vector *tcv;
     struct unixuser *tu;
     afs_int32 retValue;
 
@@ -2602,8 +2677,8 @@ DECL_PIOCTL(PCheckAuth)
        /* all connections in cell 1 working? */
        for (i = 0; i < NSERVERS; i++) {
            for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
-               for (tc = sa->conns; tc; tc = tc->next) {
-                   if (tc->user == tu && (tu->states & UTokensBad))
+               for (tcv = sa->conns; tcv; tcv = tcv->next) {
+                   if (tcv->user == tu && (tu->states & UTokensBad))
                        retValue = EACCES;
                }
            }
@@ -2623,7 +2698,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;
@@ -2902,6 +2977,7 @@ DECL_PIOCTL(PRemoveCallBack)
     struct AFSCallBack CallBacks_Array[1];
     struct AFSCBFids theFids;
     struct AFSCBs theCBs;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PRemoveCallBack);
@@ -2917,17 +2993,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);
@@ -3168,6 +3244,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 */
@@ -3235,19 +3312,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) {
@@ -3420,11 +3497,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))
@@ -3435,11 +3510,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
@@ -3819,7 +3889,8 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
 
     if (vlonly) {
        afs_int32 *p;
-       p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
+       p = afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
+        osi_Assert(p != NULL);
        p[0] = s;
        memcpy(p + 1, l, s * sizeof(afs_int32));
        afs_TraverseCells(&ReSortCells_cb, p);
@@ -3905,7 +3976,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);
        }
@@ -3955,7 +4026,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,
@@ -4314,7 +4385,6 @@ DECL_PIOCTL(PGetInitParams)
 
     return afs_pd_putBytes(aout, &cm_initParams,
                           sizeof(struct cm_initparams));
-    return 0;
 }
 
 #ifdef AFS_SGI65_ENV
@@ -4844,8 +4914,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;
@@ -4854,8 +4924,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;
 
@@ -4878,25 +4949,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);
@@ -4917,6 +4988,7 @@ DECL_PIOCTL(PFsCmd)
     struct FsCmdOutputs *Outputs;
     struct VenusFid tfid;
     struct AFSFid *Fid;
+    struct rx_connection *rxconn;
 
     if (!avc)
        return EINVAL;
@@ -4946,17 +5018,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);
@@ -4993,7 +5065,7 @@ DECL_PIOCTL(PNewUuid)
     return 0;
 }
 
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
 DECL_PIOCTL(PSetCachingThreshold)
 {
@@ -5042,6 +5114,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 */
@@ -5075,6 +5148,7 @@ DECL_PIOCTL(PCallBackAddr)
     }
 
     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
     j = 0;
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
@@ -5104,24 +5178,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, &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;
@@ -5204,6 +5278,186 @@ DECL_PIOCTL(PDiscon)
     return afs_pd_putInt(aout, mode);
 }
 
+#define MAX_PIOCTL_TOKENS 10
+
+DECL_PIOCTL(PSetTokens2)
+{
+    int code =0;
+    int i, cellNum, primaryFlag;
+    XDR xdrs;
+    struct unixuser *tu;
+    struct vrequest treq;
+    struct ktc_setTokenData tokenSet;
+    struct ktc_tokenUnion decodedToken;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    AFS_STATCNT(PSetTokens2);
+    if (!afs_resourceinit_flag)
+       return EIO;
+
+    afs_pd_xdrStart(ain, &xdrs, XDR_DECODE);
+
+    if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+       afs_pd_xdrEnd(ain, &xdrs);
+       return EINVAL;
+    }
+
+    afs_pd_xdrEnd(ain, &xdrs);
+
+    /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
+     * process from using up the whole of the kernel memory by allocating
+     * tokens.
+     */
+    if (tokenSet.tokens.tokens_len > MAX_PIOCTL_TOKENS) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return E2BIG;
+    }
+
+    code = _settok_tokenCell(tokenSet.cell, &cellNum, &primaryFlag);
+    if (code) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return code;
+    }
+
+    if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
+       if (_settok_setParentPag(acred) == 0) {
+           afs_InitReq(&treq, *acred);
+           areq = &treq;
+       }
+    }
+
+    tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
+    /* Free any tokens that we've already got */
+    afs_FreeTokens(&tu->tokens);
+
+    /* Iterate across the set of tokens we've received, and stuff them
+     * into this user's tokenJar
+     */
+    for (i=0; i < tokenSet.tokens.tokens_len; i++) {
+       xdrmem_create(&xdrs,
+                     tokenSet.tokens.tokens_val[i].token_opaque_val,
+                     tokenSet.tokens.tokens_val[i].token_opaque_len,
+                     XDR_DECODE);
+
+       memset(&decodedToken, 0, sizeof(decodedToken));
+       if (!xdr_ktc_tokenUnion(&xdrs, &decodedToken)) {
+           xdr_destroy(&xdrs);
+           code = EINVAL;
+           goto out;
+       }
+
+       xdr_destroy(&xdrs);
+
+       afs_AddTokenFromPioctl(&tu->tokens, &decodedToken);
+       /* This is untidy - the old token interface supported passing
+        * the primaryFlag as part of the token interface. Current
+        * OpenAFS userland never sets this, but it's specified as being
+        * part of the XG interface, so we should probably still support
+        * it. Rather than add it to our AddToken interface, just handle
+        * it here.
+        */
+       if (decodedToken.at_type == AFSTOKEN_UNION_KAD) {
+           if (decodedToken.ktc_tokenUnion_u.at_kad.rk_primary_flag)
+               primaryFlag = 1;
+       }
+
+       /* XXX - We should think more about destruction here. It's likely that
+        * there is key material in what we're about to throw away, which
+        * we really should zero out before giving back to the allocator */
+       xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &decodedToken);
+    }
+
+    tu->states |= UHasTokens;
+    tu->states &= ~UTokensBad;
+    afs_SetPrimary(tu, primaryFlag);
+    tu->tokenTime = osi_Time();
+
+    xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+
+out:
+    afs_ResetUserConns(tu);
+    afs_PutUser(tu, WRITE_LOCK);
+
+    return code;
+}
+
+DECL_PIOCTL(PGetTokens2)
+{
+    struct cell *cell = NULL;
+    struct unixuser *tu = NULL;
+    afs_int32 iterator;
+    char *cellName = NULL;
+    afs_int32 cellNum;
+    int code = 0;
+    time_t now;
+    XDR xdrs;
+    struct ktc_setTokenData tokenSet;
+
+    AFS_STATCNT(PGetTokens);
+    if (!afs_resourceinit_flag)
+       return EIO;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    /* No input data - return tokens for primary cell */
+    /* 4 octets of data is 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 */
+       if (afs_pd_getInt(ain, &iterator) != 0)
+           return EINVAL;
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+        if (afs_pd_remaining(ain) > 0) {
+           if (afs_pd_getStringPtr(ain, &cellName) != 0)
+               return EINVAL;
+        } else {
+           cellName = NULL;
+       }
+       code = _settok_tokenCell(cellName, &cellNum, NULL);
+       if (code)
+           return code;
+       tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
+    }
+    if (tu == NULL)
+       return EDOM;
+
+    now = osi_Time();
+
+    if (!(tu->states & UHasTokens)
+       || !afs_HasValidTokens(tu->tokens, now)) {
+       tu->states |= (UTokensBad | UNeedsReset);
+       afs_PutUser(tu, READ_LOCK);
+       return ENOTCONN;
+    }
+
+    code = afs_ExtractTokensForPioctl(tu->tokens, now, &tokenSet);
+    if (code)
+       goto out;
+
+    cell = afs_GetCell(tu->cell, READ_LOCK);
+    tokenSet.cell = cell->cellName;
+    afs_pd_xdrStart(aout, &xdrs, XDR_ENCODE);
+    if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+       code = E2BIG;
+       goto out;
+    }
+    afs_pd_xdrEnd(aout, &xdrs);
+
+out:
+    tokenSet.cell = NULL;
+
+    if (tu)
+       afs_PutUser(tu, READ_LOCK);
+    if (cell)
+       afs_PutCell(cell, READ_LOCK);
+    xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
+
+    return code;
+};
+
 DECL_PIOCTL(PNFSNukeCreds)
 {
     afs_uint32 addr;
@@ -5232,12 +5486,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