afs: Free 'addrs' array
[openafs.git] / src / afs / afs_pioctl.c
index c4e6a82..3152054 100644 (file)
 #ifdef AFS_OBSD_ENV
 #include "h/syscallargs.h"
 #endif
-#ifdef AFS_FBSD50_ENV
+#ifdef AFS_FBSD_ENV
 #include "h/sysproto.h"
 #endif
+#ifdef AFS_NBSD40_ENV
+#include <sys/ioctl.h>
+#include <sys/ioccom.h>
+#endif
 #include "afsincludes.h"       /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "afs/vice.h"
 #include "afs/afs_bypasscache.h"
 #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;
 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE;        /* show all messages */
 
-#ifdef AFS_DISCON_ENV
 afs_int32 afs_is_disconnected;
 afs_int32 afs_is_discon_rw;
 /* On reconnection, turn this knob on until it finishes,
  * then turn it off.
  */
 afs_int32 afs_in_sync = 0;
-#endif
 
 struct afs_pdata {
     char *ptr;
@@ -49,9 +53,11 @@ struct afs_pdata {
  */
 
 static_inline int
-afs_pd_alloc(struct afs_pdata *apd, size_t size) {
-
-    if (size > AFS_LRALLOCSIZ)
+afs_pd_alloc(struct afs_pdata *apd, size_t size)
+{
+    /* 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);
@@ -59,17 +65,25 @@ 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;
 }
 
 static_inline void
-afs_pd_free(struct afs_pdata *apd) {
+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);
@@ -79,17 +93,20 @@ afs_pd_free(struct afs_pdata *apd) {
 }
 
 static_inline char *
-afs_pd_where(struct afs_pdata *apd) {
+afs_pd_where(struct afs_pdata *apd)
+{
     return apd ? apd->ptr : NULL;
 }
 
 static_inline size_t
-afs_pd_remaining(struct afs_pdata *apd) {
+afs_pd_remaining(struct afs_pdata *apd)
+{
     return apd ? apd->remaining : 0;
 }
 
 static_inline int
-afs_pd_skip(struct afs_pdata *apd, size_t skip) {
+afs_pd_skip(struct afs_pdata *apd, size_t skip)
+{
     if (apd == NULL || apd->remaining < skip)
        return EINVAL;
     apd->remaining -= skip;
@@ -99,32 +116,31 @@ afs_pd_skip(struct afs_pdata *apd, size_t skip) {
 }
 
 static_inline int
-afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val) {
-    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
+{
+    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) {
-    return afs_pd_getInt(apd, (afs_int32 *)val);
+afs_pd_getInt(struct afs_pdata *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) {
-    if (apd == NULL || apd->remaining < bytes)
-       return EINVAL;
-    apd->remaining -= bytes;
-    memcpy(dest, apd->ptr, bytes);
-    apd->ptr += bytes;
-    return 0;
+afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
+{
+    return afs_pd_getBytes(apd, val, sizeof(*val));
 }
 
 static_inline void *
-afs_pd_inline(struct afs_pdata *apd, size_t bytes) {
+afs_pd_inline(struct afs_pdata *apd, size_t bytes)
+{
     void *ret;
 
     if (apd == NULL || apd->remaining < bytes)
@@ -138,8 +154,26 @@ 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) {
+afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen)
+{
     size_t len;
 
     if (apd == NULL || apd->remaining <= 0)
@@ -154,7 +188,8 @@ afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen) {
 }
 
 static_inline int
-afs_pd_getStringPtr(struct afs_pdata *apd, char **str) {
+afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
+{
     size_t len;
 
     if (apd == NULL || apd->remaining <= 0)
@@ -167,18 +202,8 @@ 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) {
+afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
+{
     if (apd == NULL || apd->remaining < len)
        return E2BIG;
     memcpy(apd->ptr, bytes, len);
@@ -188,6 +213,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 */
@@ -230,11 +261,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);
@@ -250,10 +283,10 @@ DECL_PIOCTL(PNewAlias);
 DECL_PIOCTL(PListCells);
 DECL_PIOCTL(PListAliases);
 DECL_PIOCTL(PRemoveMount);
-DECL_PIOCTL(PVenusLogging);
 DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
+DECL_PIOCTL(PFlushAllVolumeData);
 DECL_PIOCTL(PGetVnodeXStatus);
 DECL_PIOCTL(PGetVnodeXStatus2);
 DECL_PIOCTL(PSetSysName);
@@ -277,11 +310,10 @@ DECL_PIOCTL(PCallBackAddr);
 DECL_PIOCTL(PDiscon);
 DECL_PIOCTL(PNFSNukeCreds);
 DECL_PIOCTL(PNewUuid);
-DECL_PIOCTL(PPrecache); 
+DECL_PIOCTL(PPrecache);
 DECL_PIOCTL(PGetPAG);
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 DECL_PIOCTL(PSetCachingThreshold);
-DECL_PIOCTL(PSetCachingBlkSize);
 #endif
 
 /*
@@ -298,10 +330,10 @@ static int HandleClientContext(struct afs_ioctl *ablob, int *com,
                               afs_ucred_t **acred,
                               afs_ucred_t *credp);
 #endif
-int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
+int HandleIoctl(struct vcache *avc, afs_int32 acom,
                struct afs_ioctl *adata);
 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
-                    register struct afs_ioctl *ablob, int afollow,
+                    struct afs_ioctl *ablob, int afollow,
                     afs_ucred_t **acred);
 static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
                    afs_ucred_t *acred);
@@ -312,98 +344,99 @@ typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
 
 static pioctlFunction VpioctlSw[] = {
     PBogus,                    /* 0 */
-       PSetAcl,                /* 1 */
-       PGetAcl,                /* 2 */
-       PSetTokens,             /* 3 */
-       PGetVolumeStatus,       /* 4 */
-       PSetVolumeStatus,       /* 5 */
-       PFlush,                 /* 6 */
-       PBogus,                 /* 7 */
-       PGetTokens,             /* 8 */
-       PUnlog,                 /* 9 */
-       PCheckServers,          /* 10 */
-       PCheckVolNames,         /* 11 */
-       PCheckAuth,             /* 12 */
-       PBogus,                 /* 13 -- used to be quick check time */
-       PFindVolume,            /* 14 */
-       PBogus,                 /* 15 -- prefetch is now special-cased; see pioctl code! */
-       PBogus,                 /* 16 -- used to be testing code */
-       PNoop,                  /* 17 -- used to be enable group */
-       PNoop,                  /* 18 -- used to be disable group */
-       PBogus,                 /* 19 -- used to be list group */
-       PViceAccess,            /* 20 */
-       PUnlog,                 /* 21 -- unlog *is* unpag in this system */
-       PGetFID,                /* 22 -- get file ID */
-       PBogus,                 /* 23 -- used to be waitforever */
-       PSetCacheSize,          /* 24 */
-       PRemoveCallBack,        /* 25 -- flush only the callback */
-       PNewCell,               /* 26 */
-       PListCells,             /* 27 */
-       PRemoveMount,           /* 28 -- delete mount point */
-       PNewStatMount,          /* 29 -- new style mount point stat */
-       PGetFileCell,           /* 30 -- get cell name for input file */
-       PGetWSCell,             /* 31 -- get cell name for workstation */
-       PMariner,               /* 32 - set/get mariner host */
-       PGetUserCell,           /* 33 -- get cell name for user */
-       PVenusLogging,          /* 34 -- Enable/Disable logging */
-       PGetCellStatus,         /* 35 */
-       PSetCellStatus,         /* 36 */
-       PFlushVolumeData,       /* 37 -- flush all data from a volume */
-       PSetSysName,            /* 38 - Set system name */
-       PExportAfs,             /* 39 - Export Afs to remote nfs clients */
-       PGetCacheSize,          /* 40 - get cache size and usage */
-       PGetVnodeXStatus,       /* 41 - get vcache's special status */
-       PSetSPrefs33,           /* 42 - Set CM Server preferences... */
-       PGetSPrefs,             /* 43 - Get CM Server preferences... */
-       PGag,                   /* 44 - turn off/on all CM messages */
-       PTwiddleRx,             /* 45 - adjust some RX params       */
-       PSetSPrefs,             /* 46 - Set CM Server preferences... */
-       PStoreBehind,           /* 47 - set degree of store behind to be done */
-       PGCPAGs,                /* 48 - disable automatic pag gc-ing */
-       PGetInitParams,         /* 49 - get initial cm params */
-       PGetCPrefs,             /* 50 - get client interface addresses */
-       PSetCPrefs,             /* 51 - set client interface addresses */
-       PFlushMount,            /* 52 - flush mount symlink data */
-       PRxStatProc,            /* 53 - control process RX statistics */
-       PRxStatPeer,            /* 54 - control peer RX statistics */
-       PGetRxkcrypt,           /* 55 -- Get rxkad encryption flag */
-       PSetRxkcrypt,           /* 56 -- Set rxkad encryption flag */
-       PBogus,                 /* 57 -- arla: set file prio */
-       PBogus,                 /* 58 -- arla: fallback getfh */
-       PBogus,                 /* 59 -- arla: fallback fhopen */
-       PBogus,                 /* 60 -- arla: controls xfsdebug */
-       PBogus,                 /* 61 -- arla: controls arla debug */
-       PBogus,                 /* 62 -- arla: debug interface */
-       PBogus,                 /* 63 -- arla: print xfs status */
-       PBogus,                 /* 64 -- arla: force cache check */
-       PBogus,                 /* 65 -- arla: break callback */
-       PPrefetchFromTape,      /* 66 -- MR-AFS: prefetch file from tape */
-       PFsCmd,                 /* 67 -- RXOSD: generic commnd interface */
-       PBogus,                 /* 68 -- arla: fetch stats */
-       PGetVnodeXStatus2,      /* 69 - get caller access and some vcache status */
+    PSetAcl,                   /* 1 */
+    PGetAcl,                   /* 2 */
+    PSetTokens,                        /* 3 */
+    PGetVolumeStatus,          /* 4 */
+    PSetVolumeStatus,          /* 5 */
+    PFlush,                    /* 6 */
+    PBogus,                    /* 7 */
+    PGetTokens,                        /* 8 */
+    PUnlog,                    /* 9 */
+    PCheckServers,             /* 10 */
+    PCheckVolNames,            /* 11 */
+    PCheckAuth,                        /* 12 */
+    PBogus,                    /* 13 -- used to be quick check time */
+    PFindVolume,               /* 14 */
+    PBogus,                    /* 15 -- prefetch is now special-cased; see pioctl code! */
+    PBogus,                    /* 16 -- used to be testing code */
+    PNoop,                     /* 17 -- used to be enable group */
+    PNoop,                     /* 18 -- used to be disable group */
+    PBogus,                    /* 19 -- used to be list group */
+    PViceAccess,               /* 20 */
+    PUnlog,                    /* 21 -- unlog *is* unpag in this system */
+    PGetFID,                   /* 22 -- get file ID */
+    PBogus,                    /* 23 -- used to be waitforever */
+    PSetCacheSize,             /* 24 */
+    PRemoveCallBack,           /* 25 -- flush only the callback */
+    PNewCell,                  /* 26 */
+    PListCells,                        /* 27 */
+    PRemoveMount,              /* 28 -- delete mount point */
+    PNewStatMount,             /* 29 -- new style mount point stat */
+    PGetFileCell,              /* 30 -- get cell name for input file */
+    PGetWSCell,                        /* 31 -- get cell name for workstation */
+    PMariner,                  /* 32 - set/get mariner host */
+    PGetUserCell,              /* 33 -- get cell name for user */
+    PBogus,                    /* 34 -- Enable/Disable logging */
+    PGetCellStatus,            /* 35 */
+    PSetCellStatus,            /* 36 */
+    PFlushVolumeData,          /* 37 -- flush all data from a volume */
+    PSetSysName,               /* 38 - Set system name */
+    PExportAfs,                        /* 39 - Export Afs to remote nfs clients */
+    PGetCacheSize,             /* 40 - get cache size and usage */
+    PGetVnodeXStatus,          /* 41 - get vcache's special status */
+    PSetSPrefs33,              /* 42 - Set CM Server preferences... */
+    PGetSPrefs,                        /* 43 - Get CM Server preferences... */
+    PGag,                      /* 44 - turn off/on all CM messages */
+    PTwiddleRx,                        /* 45 - adjust some RX params       */
+    PSetSPrefs,                        /* 46 - Set CM Server preferences... */
+    PStoreBehind,              /* 47 - set degree of store behind to be done */
+    PGCPAGs,                   /* 48 - disable automatic pag gc-ing */
+    PGetInitParams,            /* 49 - get initial cm params */
+    PGetCPrefs,                        /* 50 - get client interface addresses */
+    PSetCPrefs,                        /* 51 - set client interface addresses */
+    PFlushMount,               /* 52 - flush mount symlink data */
+    PRxStatProc,               /* 53 - control process RX statistics */
+    PRxStatPeer,               /* 54 - control peer RX statistics */
+    PGetRxkcrypt,              /* 55 -- Get rxkad encryption flag */
+    PSetRxkcrypt,              /* 56 -- Set rxkad encryption flag */
+    PBogus,                    /* 57 -- arla: set file prio */
+    PBogus,                    /* 58 -- arla: fallback getfh */
+    PBogus,                    /* 59 -- arla: fallback fhopen */
+    PBogus,                    /* 60 -- arla: controls xfsdebug */
+    PBogus,                    /* 61 -- arla: controls arla debug */
+    PBogus,                    /* 62 -- arla: debug interface */
+    PBogus,                    /* 63 -- arla: print xfs status */
+    PBogus,                    /* 64 -- arla: force cache check */
+    PBogus,                    /* 65 -- arla: break callback */
+    PPrefetchFromTape,         /* 66 -- MR-AFS: prefetch file from tape */
+    PFsCmd,                    /* 67 -- RXOSD: generic commnd interface */
+    PBogus,                    /* 68 -- arla: fetch stats */
+    PGetVnodeXStatus2,         /* 69 - get caller access and some vcache status */
 };
 
 static pioctlFunction CpioctlSw[] = {
-    PBogus,                    /* 0 */
-       PNewAlias,              /* 1 -- create new cell alias */
-       PListAliases,           /* 2 -- list cell aliases */
-       PCallBackAddr,          /* 3 -- request addr for callback rxcon */
-       PBogus,                 /* 4 */
-       PDiscon,                /* 5 -- get/set discon mode */
-        PBogus,                 /* 6 */
-        PBogus,                 /* 7 */
-        PBogus,                 /* 8 */
-        PNewUuid,               /* 9 */
-    PBogus,                     /* 0 */
     PBogus,                     /* 0 */
+    PNewAlias,                  /* 1 -- create new cell alias */
+    PListAliases,               /* 2 -- list cell aliases */
+    PCallBackAddr,              /* 3 -- request addr for callback rxcon */
+    PBogus,                     /* 4 */
+    PDiscon,                    /* 5 -- get/set discon mode */
+    PBogus,                     /* 6 */
+    PGetTokens2,                /* 7 */
+    PSetTokens2,                /* 8 */
+    PNewUuid,                   /* 9 */
+    PBogus,                     /* 10 */
+    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)
+#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 */
@@ -414,10 +447,10 @@ static pioctlFunction OpioctlSw[]  = {
 int afs_nobody = NFS_NOBODY;
 
 int
-HandleIoctl(register struct vcache *avc, register afs_int32 acom,
+HandleIoctl(struct vcache *avc, afs_int32 acom,
            struct afs_ioctl *adata)
 {
-    register afs_int32 code;
+    afs_int32 code;
 
     code = 0;
     AFS_STATCNT(HandleIoctl);
@@ -435,8 +468,8 @@ HandleIoctl(register struct vcache *avc, register afs_int32 acom,
 
     case 3:{
            /* return the name of the cell this file is open on */
-           register struct cell *tcell;
-           register afs_int32 i;
+           struct cell *tcell;
+           afs_int32 i;
 
            tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
            if (tcell) {
@@ -476,7 +509,7 @@ HandleIoctl(register struct vcache *avc, register afs_int32 acom,
     return code;               /* so far, none implemented */
 }
 
-#ifdef AFS_AIX_ENV
+#ifdef AFS_AIX_ENV
 /* For aix we don't temporarily bypass ioctl(2) but rather do our
  * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
  * is now called from afs_gn_ioctl.
@@ -500,15 +533,110 @@ afs_ioctl(struct vcache *tvc, int cmd, int arg)
        return (ENOTTY);
     }
 }
-#endif /* AFS_AIX_ENV */
+# if defined(AFS_AIX32_ENV)
+#  if defined(AFS_AIX51_ENV)
+#   ifdef __64BIT__
+int
+kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
+          caddr_t arg3)
+#   else /* __64BIT__ */
+int
+kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
+            caddr_t arg3)
+#   endif /* __64BIT__ */
+#  else
+int
+kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
+#  endif /* AFS_AIX51_ENV */
+{
+    struct a {
+       int fd, com;
+       caddr_t arg, ext;
+#  ifdef AFS_AIX51_ENV
+       caddr_t arg2, arg3;
+#  endif
+    } u_uap, *uap = &u_uap;
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
-#if defined(AFS_SGI_ENV)
+    AFS_STATCNT(afs_xioctl);
+    uap->fd = fdes;
+    uap->com = com;
+    uap->arg = arg;
+#  ifdef AFS_AIX51_ENV
+    uap->arg2 = arg2;
+    uap->arg3 = arg3;
+#  endif
+    if (setuerror(getf(uap->fd, &fd))) {
+       return -1;
+    }
+    if (fd->f_type == DTYPE_VNODE) {
+       /* good, this is a vnode; next see if it is an AFS vnode */
+       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+#  if defined(AFS_AIX41_ENV)
+                   ufdrele(uap->fd);
+#  endif
+                   return (setuerror(code), code);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+#  if defined(AFS_AIX41_ENV)
+               ufdrele(uap->fd);
+#  endif
+            }
+       }
+    }
+    if (!ioctlDone) {
+#  if defined(AFS_AIX41_ENV)
+       ufdrele(uap->fd);
+#   if defined(AFS_AIX51_ENV)
+#    ifdef __64BIT__
+       code = okioctl(fdes, com, arg, ext, arg2, arg3);
+#    else /* __64BIT__ */
+       code = okioctl32(fdes, com, arg, ext, arg2, arg3);
+#    endif /* __64BIT__ */
+#   else /* !AFS_AIX51_ENV */
+       code = okioctl(fdes, com, arg, ext);
+#   endif /* AFS_AIX51_ENV */
+       return code;
+#  elif defined(AFS_AIX32_ENV)
+       okioctl(fdes, com, arg, ext);
+#  endif
+    }
+#  if defined(KERNEL_HAVE_UERROR)
+    if (!getuerror())
+       setuerror(code);
+#   if !defined(AFS_AIX41_ENV)
+    return (getuerror()? -1 : u.u_ioctlrv);
+#   else
+    return getuerror()? -1 : 0;
+#   endif
+#  endif
+    return 0;
+}
+# endif
+
+#elif defined(AFS_SGI_ENV)
+# if defined(AFS_SGI65_ENV)
 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
-         rval_t * rvalp
-#ifdef AFS_SGI65_ENV
-         , struct vopbd * vbds
-#endif
-    )
+         rval_t * rvalp, struct vopbd * vbds)
+# else
+afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
+         rval_t * rvalp, struct vopbd * vbds)
+# endif
 {
     struct afs_ioctl data;
     int error = 0;
@@ -534,280 +662,294 @@ afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
        return (ENOTTY);
     }
 }
-#endif /* AFS_SGI_ENV */
-
-/* unlike most calls here, this one uses u.u_error to return error conditions,
-   since this is really an intercepted chapter 2 call, rather than a vnode
-   interface call.
-   */
-/* AFS_HPUX102 and up uses VNODE ioctl instead */
-#if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
-# if !defined(AFS_SGI_ENV)
-#  ifdef       AFS_AIX32_ENV
-#   ifdef AFS_AIX51_ENV
-#    ifdef __64BIT__
-int
-kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2, 
-          caddr_t arg3)
-#    else /* __64BIT__ */
-int
-kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2, 
-            caddr_t arg3)
-#    endif /* __64BIT__ */
-#   else
-int
-kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
-#   endif
-{
-    struct a {
-       int fd, com;
-       caddr_t arg, ext;
-#   ifdef AFS_AIX51_ENV
-       caddr_t arg2, arg3;
-#   endif
-    } u_uap, *uap = &u_uap;
-#  else
-#   if defined(AFS_SUN5_ENV)
-
+#elif defined(AFS_SUN5_ENV)
 struct afs_ioctl_sys {
     int fd;
     int com;
     int arg;
 };
 
-int 
+int
 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
 {
-#   elif defined(AFS_FBSD50_ENV)
-#    define arg data
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+    fd = getf(uap->fd);
+    if (!fd)
+       return (EBADF);
+    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))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+                   releasef(uap->fd);
+                   return (EFAULT);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+    releasef(uap->fd);
+    if (!ioctlDone)
+       code = ioctl(uap, rvp);
+
+    return (code);
+}
+#elif defined(AFS_LINUX22_ENV)
+struct afs_ioctl_sys {
+    unsigned int com;
+    unsigned long arg;
+};
+int
+afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
+          unsigned long arg)
+{
+    struct afs_ioctl_sys ua, *uap = &ua;
+    struct vcache *tvc;
+    int code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+    ua.com = com;
+    ua.arg = arg;
+
+    tvc = VTOAFS(ip);
+    if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+       /* This is an AFS vnode */
+       if (((uap->com >> 8) & 0xff) == 'V') {
+           struct afs_ioctl *datap;
+           AFS_GLOCK();
+           datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+           code = copyin_afs_ioctl((char *)uap->arg, datap);
+           if (code) {
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               return -code;
+           }
+           code = HandleIoctl(tvc, uap->com, datap);
+           osi_FreeSmallSpace(datap);
+           AFS_GUNLOCK();
+       }
+       else
+           code = EINVAL;
+    }
+    return -code;
+}
+#elif defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
+struct ioctl_args {
+    int fd;
+    u_long com;
+    caddr_t arg;
+};
+
+int
+afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
+{
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+    if ((code = fdgetf(p, uap->fd, &fd)))
+       return code;
+    if (fd->f_type == DTYPE_VNODE) {
+       tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code = copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+                   return code;
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+
+    if (!ioctlDone)
+       return ioctl(p, uap, retval);
+
+    return (code);
+}
+#elif defined(AFS_XBSD_ENV)
+# if defined(AFS_FBSD_ENV)
+#  define arg data
 int
-afs_xioctl(struct thread *td, register struct ioctl_args *uap, 
+afs_xioctl(struct thread *td, struct ioctl_args *uap,
           register_t *retval)
 {
     afs_proc_t *p = td->td_proc;
-#   elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+# 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;
     u_long com;
     caddr_t arg;
 };
 
-int
-afs_xioctl(afs_proc_t *p, register struct ioctl_args *uap, register_t *retval)
-{
-#   elif defined(AFS_LINUX22_ENV)
-struct afs_ioctl_sys {
-    unsigned int com;
-    unsigned long arg;
-};
-int
-afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
-          unsigned long arg)
-{
-    struct afs_ioctl_sys ua, *uap = &ua;
-#   elif defined(UKERNEL)
+int
+afs_xioctl(afs_proc_t *p, const struct ioctl_args *uap, register_t *retval)
+{
+# endif
+    struct filedesc *fdp;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+    struct file *fd;
+
+    AFS_STATCNT(afs_xioctl);
+#if defined(AFS_NBSD40_ENV)
+    fdp = p->l_proc->p_fd;
+#else
+    fdp = p->p_fd;
+#endif
+#if defined(AFS_NBSD50_ENV)
+    if ((fd = fd_getfile(SCARG(uap, fd))) == NULL)
+       return (EBADF);
+#elif defined(AFS_FBSD100_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 */
+    if (fd->f_type == DTYPE_VNODE) {
+       /* good, this is a vnode; next see if it is an AFS vnode */
+# if defined(AFS_OBSD_ENV)
+       tvc =
+           IsAfsVnode((struct vnode *)fd->
+                      f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
+# else
+       tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
+# endif
+       if (tvc && IsAfsVnode((struct vnode *)fd->f_data)) {
+           /* This is an AFS vnode */
+#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;
+           }
+       }
+    }
+
+#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)
+        code = sys_ioctl(p, uap, retval);
+# endif
+    }
+
+    return (code);
+}
+#elif defined(UKERNEL)
 int
 afs_xioctl(void)
 {
-    register struct a {
+    struct a {
        int fd;
        int com;
        caddr_t arg;
     } *uap = (struct a *)get_user_struct()->u_ap;
-#   else
-int
-afs_xioctl(void)
-{
-    register struct a {
-       int fd;
-       int com;
-       caddr_t arg;
-    } *uap = (struct a *)u.u_ap;
-#   endif /* AFS_SUN5_ENV */
-#  endif
-#  if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
     struct file *fd;
-#  elif !defined(AFS_LINUX22_ENV)
-    register struct file *fd;
-#  endif
-#  if defined(AFS_XBSD_ENV)
-    register struct filedesc *fdp;
-#  endif
-    register struct vcache *tvc;
-    register int ioctlDone = 0, code = 0;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
     AFS_STATCNT(afs_xioctl);
-#  if defined(AFS_DARWIN_ENV)
-    if ((code = fdgetf(p, uap->fd, &fd)))
-       return code;
-#  elif defined(AFS_XBSD_ENV)
-    fdp = p->p_fd;
-    if ((u_int) uap->fd >= fdp->fd_nfiles
-       || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
-       return EBADF;
-    if ((fd->f_flag & (FREAD | FWRITE)) == 0)
-       return EBADF;
-#  elif defined(AFS_LINUX22_ENV)
-    ua.com = com;
-    ua.arg = arg;
-#  elif defined(AFS_AIX32_ENV)
-    uap->fd = fdes;
-    uap->com = com;
-    uap->arg = arg;
-#   ifdef AFS_AIX51_ENV
-    uap->arg2 = arg2;
-    uap->arg3 = arg3;
-#   endif
-    if (setuerror(getf(uap->fd, &fd))) {
-       return -1;
-    }
-#  elif defined(AFS_SUN5_ENV)
-#   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      /* AFS_SUN57_ENV */
-#  else
+
     fd = getf(uap->fd);
     if (!fd)
        return (EBADF);
-#  endif
     /* first determine whether this is any sort of vnode */
-#  if defined(AFS_LINUX22_ENV)
-    tvc = VTOAFS(ip);
-    {
-#  else
-#   ifdef AFS_SUN5_ENV
-    if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
-#   else
     if (fd->f_type == DTYPE_VNODE) {
-#   endif
        /* good, this is a vnode; next see if it is an AFS vnode */
-#   if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
-       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
-#   elif defined(AFS_OBSD_ENV)
-       tvc =
-           IsAfsVnode((struct vnode *)fd->
-                      f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
-#   else
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
-#   endif
-#  endif /* AFS_LINUX22_ENV */
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
            /* This is an AFS vnode */
            if (((uap->com >> 8) & 0xff) == 'V') {
-               register struct afs_ioctl *datap;
+               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_AIX41_ENV)
-                   ufdrele(uap->fd);
-#  elif defined(AFS_SUN54_ENV)
-                   releasef(uap->fd);
-#  elif defined(AFS_SUN5_ENV)
-                   releasef(fd);
-#  endif
 
-#  if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-                   return code;
-#  elif defined(AFS_SUN5_ENV)
-                   return (EFAULT);
-#  elif defined(AFS_LINUX22_ENV)
-                   return -code;
-#  else
                    return (setuerror(code), code);
-#  endif
                }
                code = HandleIoctl(tvc, uap->com, datap);
                osi_FreeSmallSpace(datap);
                AFS_GUNLOCK();
                ioctlDone = 1;
-#  if defined(AFS_AIX41_ENV)
-               ufdrele(uap->fd);
-#  endif
            }
-#  if defined(AFS_LINUX22_ENV)
-           else
-               code = EINVAL;
-#  endif
        }
     }
 
     if (!ioctlDone) {
-#  if defined(AFS_AIX41_ENV)
-       ufdrele(uap->fd);
-#   ifdef AFS_AIX51_ENV
-#    ifdef __64BIT__
-       code = okioctl(fdes, com, arg, ext, arg2, arg3);
-#    else /* __64BIT__ */
-       code = okioctl32(fdes, com, arg, ext, arg2, arg3);
-#    endif /* __64BIT__ */
-#   else /* !AFS_AIX51_ENV */
-       code = okioctl(fdes, com, arg, ext);
-#   endif /* AFS_AIX51_ENV */
-       return code;
-#  elif defined(AFS_AIX32_ENV)
-       okioctl(fdes, com, arg, ext);
-#  elif defined(AFS_SUN5_ENV)
-#   if defined(AFS_SUN57_ENV)
-       releasef(uap->fd);
-#   elif defined(AFS_SUN54_ENV)
-       RELEASEF(uap->fd);
-#   else
-       releasef(fd);
-#   endif
-       code = ioctl(uap, rvp);
-#  elif defined(AFS_FBSD50_ENV)
-       return ioctl(td, uap);
-#  elif defined(AFS_FBSD_ENV)
-       return ioctl(p, uap);
-#  elif defined(AFS_OBSD_ENV)
-       code = sys_ioctl(p, uap, retval);
-#  elif defined(AFS_DARWIN_ENV)
-       return ioctl(p, uap, retval);
-#  elif !defined(AFS_LINUX22_ENV)
        ioctl();
-#  endif
     }
-#  ifdef       AFS_SUN5_ENV
-    if (ioctlDone)
-#   ifdef      AFS_SUN54_ENV
-       releasef(uap->fd);
-#   else
-       releasef(fd);
-#   endif
-    return (code);
-#  elif defined(AFS_LINUX22_ENV)
-    return -code;
-#  elif defined(KERNEL_HAVE_UERROR)
-    if (!getuerror())
-       setuerror(code);
-#   if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
-    return (getuerror()? -1 : u.u_ioctlrv);
-#   else
-    return getuerror()? -1 : 0;
-#   endif
-#  endif
 
-#  if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-    return (code);
-#  else
     return 0;
-#  endif
 }
-# endif /* AFS_SGI_ENV */
 #endif /* AFS_HPUX102_ENV */
 
 #if defined(AFS_SGI_ENV)
@@ -835,7 +977,7 @@ afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
 # endif
 }
 
-#elif defined(AFS_FBSD50_ENV)
+#elif defined(AFS_FBSD_ENV)
 int
 afs_pioctl(struct thread *td, void *args, int *retval)
 {
@@ -863,14 +1005,18 @@ afs_pioctl(afs_proc_t *p, void *args, int *retval)
     } *uap = (struct a *)args;
 
     AFS_STATCNT(afs_pioctl);
-# ifdef AFS_DARWIN80_ENV
+# if defined(AFS_DARWIN80_ENV) || defined(AFS_NBSD40_ENV)
     return (afs_syscall_pioctl
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
             kauth_cred_get()));
 # else
     return (afs_syscall_pioctl
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
+#  if defined(AFS_FBSD_ENV)
+            td->td_ucred));
+#  else
             p->p_cred->pc_ucred));
+#  endif
 # endif
 }
 
@@ -885,14 +1031,14 @@ afs_pioctl(afs_proc_t *p, void *args, int *retval)
 
 int
 #ifdef AFS_SUN5_ENV
-afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow, 
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
                   rval_t *vvp, afs_ucred_t *credp)
 #else
 #ifdef AFS_DARWIN100_ENV
 afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
                   int follow, afs_ucred_t *credp)
 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow, 
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
                   afs_ucred_t *credp)
 #else
 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
@@ -906,7 +1052,7 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #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)
     afs_ucred_t *foreigncreds = NULL;
 #endif
-    register afs_int32 code = 0;
+    afs_int32 code = 0;
     struct vnode *vp = NULL;
 #ifdef AFS_AIX41_ENV
     struct ucred *credp = crref();     /* don't free until done! */
@@ -1006,9 +1152,6 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
            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 */
-       VN_HOLD(vp);
-#endif /* AFS_FBSD80_ENV */
 #endif /* AFS_LINUX22_ENV */
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
@@ -1027,13 +1170,13 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
        struct vnode *realvp;
        if
 #ifdef AFS_SUN511_ENV
-          (VOP_REALVP(vp, &realvp, NULL) == 0) 
+          (VOP_REALVP(vp, &realvp, NULL) == 0)
 #else
-         (VOP_REALVP(vp, &realvp) == 0) 
+         (VOP_REALVP(vp, &realvp) == 0)
 #endif
 {
            struct vnode *oldvp = vp;
-           
+
            VN_HOLD(realvp);
            vp = realvp;
            AFS_RELE(oldvp);
@@ -1107,7 +1250,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))
@@ -1142,13 +1291,13 @@ afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
 
 int
 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
-                register struct afs_ioctl *ablob, int afollow,
+                struct afs_ioctl *ablob, int afollow,
                 afs_ucred_t **acred)
 {
     struct vcache *avc;
-    struct vrequest treq;
-    register afs_int32 code;
-    register afs_int32 function, device;
+    struct vrequest *treq = NULL;
+    afs_int32 code;
+    afs_int32 function, device;
     struct afs_pdata input, output;
     struct afs_pdata copyInput, copyOutput;
     size_t outSize;
@@ -1164,13 +1313,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;
     }
@@ -1216,7 +1365,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);
@@ -1228,7 +1378,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;
@@ -1246,7 +1396,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;
 }
 
 /*!
@@ -1283,18 +1435,20 @@ DECL_PIOCTL(PGetFID)
  *
  * \post Changed ACL, via direct writing to the wire
  */
-int dummy_PSetAcl(char *ain, char *aout)
+int
+dummy_PSetAcl(char *ain, char *aout)
 {
     return 0;
 }
 
 DECL_PIOCTL(PSetAcl)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct afs_conn *tconn;
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetAcl);
@@ -1308,31 +1462,26 @@ 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 */
-    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;
 }
 
@@ -1346,10 +1495,15 @@ int afs_defaultAsynchrony = 0;
  * \param[in] ain      sbstruct (store behind structure) input
  * \param[out] aout    resulting sbstruct
  *
- * \retval EPERM       Error if the user doesn't have super-user credentials
- * \retval EACCES      Error if there isn't enough access to not check the mode bits
+ * \retval EPERM
+ *     Error if the user doesn't have super-user credentials
+ * \retval EACCES
+ *     Error if there isn't enough access to not check the mode bits
  *
- * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
+ * \post
+ *     Changes either the default asynchrony (the amount of data that
+ *     can remain to be written when the cache manager returns control
+ *     to the user), or the asyncrony for the specified file.
  */
 DECL_PIOCTL(PStoreBehind)
 {
@@ -1417,7 +1571,10 @@ DECL_PIOCTL(PGCPAGs)
  *
  * \post Obtain the ACL, based on file ID
  *
- * \notes there is a hack to tell which type of ACL is being returned, checks the top 2-bytes to judge what type of ACL it is, only for dfs xlat or ACLs
+ * \notes
+ *     There is a hack to tell which type of ACL is being returned, checks
+ *     the top 2-bytes of the input size to judge what type of ACL it is,
+ *     only for dfs xlator ACLs
  */
 DECL_PIOCTL(PGetAcl)
 {
@@ -1427,6 +1584,7 @@ DECL_PIOCTL(PGetAcl)
     afs_int32 code;
     struct afs_conn *tconn;
     struct AFSFid Fid;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetAcl);
@@ -1449,18 +1607,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) {
@@ -1473,11 +1631,18 @@ DECL_PIOCTL(PGetAcl)
 }
 
 /*!
- * PNoop returns success.  Used for functions which are not implemented or are no longer in use.
+ * PNoop returns success.  Used for functions which are not implemented
+ * or are no longer in use.
  *
  * \ingroup pioctl
  *
- * \notes Functions involved in this: 17 (VIOCENGROUP) -- used to be enable group; 18 (VIOCDISGROUP) -- used to be disable group; 2 (?) -- get/set cache-bypass size threshold
+ * \retval Always returns success
+ *
+ * \notes
+ *     Functions involved in this:
+ *     17 (VIOCENGROUP) -- used to be enable group;
+ *     18 (VIOCDISGROUP) -- used to be disable group;
+ *     2 (?) -- get/set cache-bypass size threshold
  */
 DECL_PIOCTL(PNoop)
 {
@@ -1486,13 +1651,35 @@ DECL_PIOCTL(PNoop)
 }
 
 /*!
- * PBogus returns fail.  Used for functions which are not implemented or are no longer in use.
+ * PBogus returns fail.  Used for functions which are not implemented or
+ * are no longer in use.
  *
  * \ingroup pioctl
  *
- * \retval EINVAL      Error if some of the standard args aren't set
- *
- * \notes Functions involved in this: 0 (?); 4 (?); 6 (?); 7 (VIOCSTAT); 8 (?); 13 (VIOCGETTIME) -- used to be quick check time; 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!; 16 (VIOCNOP) -- used to be testing code; 19 (VIOCLISTGROUPS) -- used to be list group; 23 (VIOCWAITFOREVER) -- used to be waitforever; 57 (VIOC_FPRIOSTATUS) -- arla: set file prio; 58 (VIOC_FHGET) -- arla: fallback getfh; 59 (VIOC_FHOPEN) -- arla: fallback fhopen; 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug; 61 (VIOC_ARLADEBUG) -- arla: controls arla debug; 62 (VIOC_AVIATOR) -- arla: debug interface; 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status; 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check; 65 (VIOC_BREAKCELLBACK) -- arla: break callback; 68 (?) -- arla: fetch stats;
+ * \retval EINVAL      Always returns this value
+ *
+ * \notes
+ *     Functions involved in this:
+ *     0 (?);
+ *     4 (?);
+ *     6 (?);
+ *     7 (VIOCSTAT);
+ *     8 (?);
+ *     13 (VIOCGETTIME) -- used to be quick check time;
+ *     15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!;
+ *     16 (VIOCNOP) -- used to be testing code;
+ *     19 (VIOCLISTGROUPS) -- used to be list group;
+ *     23 (VIOCWAITFOREVER) -- used to be waitforever;
+ *     57 (VIOC_FPRIOSTATUS) -- arla: set file prio;
+ *     58 (VIOC_FHGET) -- arla: fallback getfh;
+ *     59 (VIOC_FHOPEN) -- arla: fallback fhopen;
+ *     60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug;
+ *     61 (VIOC_ARLADEBUG) -- arla: controls arla debug;
+ *     62 (VIOC_AVIATOR) -- arla: debug interface;
+ *     63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status;
+ *     64 (VIOC_CALCULATE_CACHE) -- arla: force cache check;
+ *     65 (VIOC_BREAKCELLBACK) -- arla: break callback;
+ *     68 (?) -- arla: fetch stats;
  */
 DECL_PIOCTL(PBogus)
 {
@@ -1515,7 +1702,7 @@ DECL_PIOCTL(PBogus)
  */
 DECL_PIOCTL(PGetFileCell)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
 
     AFS_STATCNT(PGetFileCell);
     if (!avc)
@@ -1539,8 +1726,10 @@ DECL_PIOCTL(PGetFileCell)
  * \param[in] ain      not in use
  * \param[out] aout    cell name
  *
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval ESRCH       Error if the machine isn't part of a cell, for whatever reason
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval ESRCH
+ *     Error if the machine isn't part of a cell, for whatever reason
  *
  * \post Get the primary cell that the machine is a part of.
  */
@@ -1570,15 +1759,16 @@ DECL_PIOCTL(PGetWSCell)
  * \param[in] ain      not in use (user id found via areq)
  * \param[out] aout    cell name
  *
- * \retval ESRCH       Error if the user id doesn't have a primary cell specified
+ * \retval ESRCH
+ *     Error if the user id doesn't have a primary cell specified
  *
  * \post Get the primary cell for a certain user, based on the user's uid
  */
 DECL_PIOCTL(PGetUserCell)
 {
-    register afs_int32 i;
-    register struct unixuser *tu;
-    register struct cell *tcell;
+    afs_int32 i;
+    struct unixuser *tu;
+    struct cell *tcell;
 
     AFS_STATCNT(PGetUserCell);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1591,12 +1781,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 {
@@ -1610,6 +1801,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
  *
@@ -1618,23 +1854,29 @@ DECL_PIOCTL(PGetUserCell)
  * \param[in] ain      the krb tickets from which to set the afs tokens
  * \param[out] aout    not in use
  *
- * \retval EINVAL      Error if the ticket is either too long or too short
- * \retval EIO         Error if the AFS initState is below 101
- * \retval ESRCH       Error if the cell for which the Token is being set can't be found
+ * \retval EINVAL
+ *     Error if the ticket is either too long or too short
+ * \retval EIO
+ *     Error if the AFS initState is below 101
+ * \retval ESRCH
+ *     Error if the cell for which the Token is being set can't be found
  *
- * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
+ * \post
+ *     Set the Tokens for a specific cell name, unless there is none set,
+ *     then default to primary
  *
  */
 DECL_PIOCTL(PSetTokens)
 {
-    afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 cellNum;
+    afs_int32 size;
+    afs_int32 code;
+    struct unixuser *tu;
     struct ClearToken clear;
-    register struct cell *tcell;
     char *stp;
     char *cellName;
     int stLen;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     afs_int32 flag, set_parent_pag = 0;
 
     AFS_STATCNT(PSetTokens);
@@ -1651,9 +1893,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)
@@ -1663,12 +1905,14 @@ DECL_PIOCTL(PSetTokens)
        clear.AuthHandle = 999; /* more rxvab compat stuff */
 
     if (afs_pd_remaining(ain) != 0) {
-       /* still stuff left?  we've got primary flag and cell name.  Set these */
+       /* still stuff left?  we've got primary flag and cell name.
+        * Set these */
 
        if (afs_pd_getInt(ain, &flag) != 0)
            return EINVAL;
 
-       /* some versions of gcc appear to need != 0 in order to get this right */
+       /* some versions of gcc appear to need != 0 in order to get this
+        * right */
        if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
            flag &= ~0x8000;
            set_parent_pag = 1;
@@ -1677,52 +1921,31 @@ 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)
-# if defined(AFS_DARWIN_ENV)
-       afs_proc_t *p = current_proc(); /* XXX */
-# else
-       afs_proc_t *p = curproc;        /* XXX */
-# endif
-# ifndef AFS_DARWIN80_ENV
-       uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
-               p->p_pid, p->p_comm);
-# endif
-       if (!setpag(p, acred, -1, &pag, 1)) {
-#else
-       if (!setpag(acred, -1, &pag, 1)) {
-#endif
-           afs_InitReq(&treq, *acred);
-           areq = &treq;
+       if (_settok_setParentPag(acred) == 0) {
+           code = afs_CreateReq(&treq, *acred);
+           if (code) {
+               return code;
+           }
+           areq = treq;
        }
     }
+
     /* now we just set the tokens */
-    tu = afs_GetUser(areq->uid, i, WRITE_LOCK);        /* i has the cell # */
-    tu->vid = clear.ViceId;
-    if (tu->stp != NULL) {
-       afs_osi_Free(tu->stp, tu->stLen);
-    }
-    tu->stp = (char *)afs_osi_Alloc(stLen);
-    if (tu->stp == NULL) {
-       return ENOMEM;
-    }
-    tu->stLen = stLen;
-    memcpy(tu->stp, stp, stLen);
-    tu->ct = clear;
+    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);
 #ifndef AFS_NOSTATS
     afs_stats_cmfullperf.authent.TicketUpdates++;
     afs_ComputePAGStats();
@@ -1732,19 +1955,11 @@ DECL_PIOCTL(PSetTokens)
     afs_SetPrimary(tu, flag);
     tu->tokenTime = osi_Time();
     afs_ResetUserConns(tu);
+    afs_NotifyUser(tu, UTokensObtained);
     afs_PutUser(tu, WRITE_LOCK);
+    afs_DestroyReq(treq);
 
     return 0;
-
-  nocell:
-    {
-       int t1;
-       t1 = afs_initState;
-       if (t1 < 101)
-           return EIO;
-       else
-           return ESRCH;
-    }
 }
 
 /*!
@@ -1757,19 +1972,24 @@ DECL_PIOCTL(PSetTokens)
  *
  * \retval EINVAL      Error if some of the standard args aren't set
  *
- * \post The status of a volume (based on the FID of the volume), or an offline message /motd
+ * \post
+ *     The status of a volume (based on the FID of the volume), or an
+ *     offline message /motd
  */
 DECL_PIOCTL(PGetVolumeStatus)
 {
     char volName[32];
     char *offLineMsg = afs_osi_Alloc(256);
     char *motd = afs_osi_Alloc(256);
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    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;
@@ -1777,19 +1997,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)
@@ -1814,31 +2034,42 @@ DECL_PIOCTL(PGetVolumeStatus)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
- * \param[out] aout    status of a volume, offlines messages, minimum quota, maximumm quota
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval EROFS       Error if the volume is read only, or a backup volume
- * \retval ENODEV      Error if the volume can't be accessed
- * \retval E2BIG       Error if the volume name, offline message, and motd are too big
- *
- * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
+ * \param[in] ain
+ *     values to set the status at, offline message, message of the day,
+ *     volume name, minimum quota, maximum quota
+ * \param[out] aout
+ *     status of a volume, offlines messages, minimum quota, maximumm quota
+ *
+ * \retval EINVAL
+ *     Error if some of the standard args aren't set
+ * \retval EROFS
+ *     Error if the volume is read only, or a backup volume
+ * \retval ENODEV
+ *     Error if the volume can't be accessed
+ * \retval E2BIG
+ *     Error if the volume name, offline message, and motd are too big
+ *
+ * \post
+ *     Set the status of a volume, including any offline messages,
+ *     a minimum quota, and a maximum quota
  */
 DECL_PIOCTL(PSetVolumeStatus)
 {
     char *volName;
     char *offLineMsg;
     char *motd;
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
-    register struct volume *tvp;
+    struct volume *tvp;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
     if (!avc)
        return EINVAL;
+    memset(&storeStat, 0, sizeof(storeStat));
 
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
@@ -1881,28 +2112,27 @@ 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)
        return code;
     /* we are sending parms back to make compat. with prev system.  should
-     * change interface later to not ask for current status, just set new status */
+     * change interface later to not ask for current status, just set new
+     * status */
 
-    /* XXX - We really need to check that this doesn't overflow, too, otherwise
-     * bad fileserver status could be _really_ bad */
     if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
        return EINVAL;
     if (afs_pd_putString(aout, volName) != 0)
@@ -1932,15 +2162,9 @@ 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;
 }
 
@@ -1949,8 +2173,11 @@ DECL_PIOCTL(PFlush)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the last component in a path, related to mountpoint that we're looking for information about
- * \param[out] aout    volume, cell, link data 
+ * \param[in] ain
+ *     the last component in a path, related to mountpoint that we're
+ *     looking for information about
+ * \param[out] aout
+ *     volume, cell, link data
  *
  * \retval EINVAL      Error if some of the standard args aren't set
  * \retval ENOTDIR     Error if the 'mount point' argument isn't a directory
@@ -1960,9 +2187,9 @@ DECL_PIOCTL(PFlush)
  */
 DECL_PIOCTL(PNewStatMount)
 {
-    register afs_int32 code;
-    register struct vcache *tvc;
-    register struct dcache *tdc;
+    afs_int32 code;
+    struct vcache *tvc;
+    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
     char *name;
@@ -1984,7 +2211,7 @@ DECL_PIOCTL(PNewStatMount)
     }
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
-       return ENOENT;
+       return EIO;
     Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
@@ -2004,10 +2231,10 @@ DECL_PIOCTL(PNewStatMount)
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
     }
     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;
@@ -2035,29 +2262,69 @@ 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
- *      
- * \param[in] ain       userid
+ *
+ * \param[in] ain       cellid to return tokens for
  * \param[out] aout     token
- * 
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval EDOM                Error if the input parameter is out of the bounds of the available tokens
- * \retval ENOTCONN    Error if there aren't tokens for this cell
- *  
- * \post If the input paramater exists, get the token that corresponds to the parameter value, if there is no token at this value, get the token for the first cell
+ *
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval EDOM
+ *     Error if the input parameter is out of the bounds of the available
+ *     tokens
+ * \retval ENOTCONN
+ *     Error if there aren't tokens for this cell
+ *
+ * \post
+ *     If the input paramater exists, get the token that corresponds to
+ *     the parameter value, if there is no token at this value, get the
+ *     token for the first cell
  *
  * \notes "it's a weird interface (from comments in the code)"
  */
 
 DECL_PIOCTL(PGetTokens)
 {
-    register struct cell *tcell;
-    register afs_int32 i;
-    register struct unixuser *tu;
+    struct cell *tcell;
+    struct unixuser *tu = NULL;
+    union tokenUnion *token;
     afs_int32 iterator = 0;
     int newStyle;
+    int cellNum;
     int code = E2BIG;
 
     AFS_STATCNT(PGetTokens);
@@ -2078,54 +2345,50 @@ 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++;
-    }
-    ReleaseReadLock(&afs_xuser);
-
+    if (newStyle) {
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+       cellNum = afs_GetPrimaryCellNum();
+       if (cellNum)
+           tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
+    }
     if (!tu) {
        return EDOM;
     }
-    if (((tu->states & UHasTokens) == 0)
-       || (tu->ct.EndTimestamp < osi_Time())) {
+    if (!(tu->states & UHasTokens)
+       || !afs_HasUsableTokens(tu->tokens, osi_Time())) {
        tu->states |= (UTokensBad | UNeedsReset);
+       afs_NotifyUser(tu, UTokensDropped);
        afs_PutUser(tu, READ_LOCK);
        return ENOTCONN;
     }
-    iterator = tu->stLen;      /* for compat, we try to return 56 byte tix if they fit */
+    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)
        iterator = 56;          /* # of bytes we're returning */
 
     if (afs_pd_putInt(aout, iterator) != 0)
        goto out;
-    if (afs_pd_putBytes(aout, tu->stp, tu->stLen) != 0)
+    if (afs_pd_putBytes(aout, token->rxkad.ticket, token->rxkad.ticketLen) != 0)
        goto out;
-    if (tu->stLen < 56) {
+    if (token->rxkad.ticketLen < 56) {
        /* Tokens are always 56 bytes or larger */
-       if (afs_pd_skip(aout, iterator - tu->stLen) != 0) {
+       if (afs_pd_skip(aout, iterator - token->rxkad.ticketLen) != 0) {
            goto out;
        }
     }
 
     if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
        goto out;
-    if (afs_pd_putBytes(aout, &tu->ct, sizeof(struct ClearToken)) != 0)
+    if (afs_pd_putBytes(aout, &token->rxkad.clearToken,
+                       sizeof(struct ClearToken)) != 0)
        goto out;
 
     if (newStyle) {
@@ -2166,8 +2429,8 @@ out:
  */
 DECL_PIOCTL(PUnlog)
 {
-    register afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 i;
+    struct unixuser *tu;
 
     AFS_STATCNT(PUnlog);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2177,28 +2440,29 @@ DECL_PIOCTL(PUnlog)
     ObtainWriteLock(&afs_xuser, 227);
     for (tu = afs_users[i]; tu; tu = tu->next) {
        if (tu->uid == areq->uid) {
-           tu->vid = UNDEFVID;
-           tu->states &= ~UHasTokens;
-           /* security is not having to say you're sorry */
-           memset(&tu->ct, 0, sizeof(struct ClearToken));
            tu->refCount++;
            ReleaseWriteLock(&afs_xuser);
-           /* We have to drop the lock over the call to afs_ResetUserConns, since
-            * it obtains the afs_xvcache lock.  We could also keep the lock, and
-            * modify ResetUserConns to take parm saying we obtained the lock
-            * already, but that is overkill.  By keeping the "tu" pointer
-            * held over the released lock, we guarantee that we won't lose our
-            * place, and that we'll pass over every user conn that existed when
-            * we began this call.
+
+           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
+            * the lock, and modify ResetUserConns to take parm saying we
+            * obtained the lock already, but that is overkill.  By keeping
+            * the "tu" pointer held over the released lock, we guarantee
+            * that we won't lose our place, and that we'll pass over
+            * 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
             * afs_GCUserData to remove this entry
             */
-           tu->ct.EndTimestamp = 0;
            tu->tokenTime = 0;
 #endif /* UKERNEL */
        }
@@ -2215,7 +2479,10 @@ DECL_PIOCTL(PUnlog)
  * \param[in] ain      host address to be set
  * \param[out] aout    old host address
  *
- * \post depending on whether or not a variable is set, either get the host for the cache manager monitor, or set the old address and give it a new address
+ * \post
+ *     depending on whether or not a variable is set, either get the host
+ *     for the cache manager monitor, or set the old address and give it
+ *     a new address
  *
  * \notes Errors turn off mariner
  */
@@ -2260,12 +2527,14 @@ DECL_PIOCTL(PMariner)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval ENOENT      Error if we are unable to obtain the cell
  *
- * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
+ * \post
+ *     Either a fast check (where it doesn't contact servers) or a
+ *     local check (checks local cell only)
  */
 DECL_PIOCTL(PCheckServers)
 {
-    register int i;
-    register struct server *ts;
+    int i;
+    struct server *ts;
     afs_int32 temp;
     char *cellName = NULL;
     struct cell *cellp;
@@ -2357,7 +2626,10 @@ DECL_PIOCTL(PCheckServers)
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  *
- * \post Check the root volume, and then check the names if the volume check variable is set to force, has expired, is busy, or if the mount points variable is set
+ * \post
+ *     Check the root volume, and then check the names if the volume
+ *     check variable is set to force, has expired, is busy, or if
+ *     the mount points variable is set
  */
 DECL_PIOCTL(PCheckVolNames)
 {
@@ -2379,9 +2651,13 @@ DECL_PIOCTL(PCheckVolNames)
  * \param[in] ain      not in use
  * \param[out] aout    not in use
  *
- * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
+ * \retval EACCESS
+ *     Error if no user is specififed, the user has no tokens set,
+ *     or if the user's tokens are bad
  *
- * \post check to see if a user has the correct authentication.  If so, allow access.
+ * \post
+ *     check to see if a user has the correct authentication.
+ *     If so, allow access.
  *
  * \notes Check the connections to all the servers specified
  */
@@ -2389,7 +2665,7 @@ DECL_PIOCTL(PCheckAuth)
 {
     int i;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct sa_conn_vector *tcv;
     struct unixuser *tu;
     afs_int32 retValue;
 
@@ -2412,8 +2688,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;
                }
            }
@@ -2431,9 +2707,9 @@ static int
 Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
         afs_ucred_t *acred)
 {
-    register char *tp;
-    register afs_int32 code;
-#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+    char *tp;
+    afs_int32 code;
+#if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     size_t bufferSize;
 #else
     u_int bufferSize;
@@ -2453,7 +2729,7 @@ Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
        return EWOULDBLOCK;     /* pretty close */
     }
     afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
-              (afs_size_t) 0, tp);
+              (afs_size_t) 0, tp, (void *)0, (void *)0);
     return 0;
 }
 
@@ -2474,9 +2750,9 @@ Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
  */
 DECL_PIOCTL(PFindVolume)
 {
-    register struct volume *tvp;
-    register struct server *ts;
-    register afs_int32 i;
+    struct volume *tvp;
+    struct server *ts;
+    afs_int32 i;
     int code = 0;
 
     AFS_STATCNT(PFindVolume);
@@ -2522,7 +2798,7 @@ out:
  */
 DECL_PIOCTL(PViceAccess)
 {
-    register afs_int32 code;
+    afs_int32 code;
     afs_int32 temp;
 
     AFS_STATCNT(PViceAccess);
@@ -2588,9 +2864,12 @@ DECL_PIOCTL(PPrecache)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EROFS       Error if the cache is set to be in memory
  *
- * \post Set the cache size based on user input.  If no size is given, set it to the default OpenAFS cache size.
+ * \post
+ *     Set the cache size based on user input.  If no size is given,
+ *     set it to the default OpenAFS cache size.
  *
- * \notes recompute the general cache parameters for every single block allocated
+ * \notes
+ *     recompute the general cache parameters for every single block allocated
  */
 DECL_PIOCTL(PSetCacheSize)
 {
@@ -2639,9 +2918,9 @@ DECL_PIOCTL(PGetCacheSize)
 {
     afs_int32 results[MAXGCSTATS];
     afs_int32 flags;
-    register struct dcache * tdc;
-    int i, size;
-    
+    struct dcache * tdc;
+    int i;
+
     AFS_STATCNT(PGetCacheSize);
 
     if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
@@ -2651,12 +2930,12 @@ DECL_PIOCTL(PGetCacheSize)
     } else {
        return EINVAL;
     }
-    
+
     memset(results, 0, sizeof(results));
     results[0] = afs_cacheBlocks;
     results[1] = afs_blocksUsed;
     results[2] = afs_cacheFiles;
-    
+
     if (1 == flags){
         for (i = 0; i < afs_cacheFiles; i++) {
            if (afs_indexFlags[i] & IFFree) results[3]++;
@@ -2672,9 +2951,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]++;
@@ -2697,15 +2977,19 @@ DECL_PIOCTL(PGetCacheSize)
  * \retval EINVAL      Error if some of the standard args aren't set
  * \retval 0           0 returned if the volume is set to read-only
  *
- * \post Flushes callbacks, by setting the length of callbacks to one, setting the next callback to be sent to the CB_DROPPED value, and then dequeues everything else.
+ * \post
+ *     Flushes callbacks, by setting the length of callbacks to one,
+ *     setting the next callback to be sent to the CB_DROPPED value,
+ *     and then dequeues everything else.
  */
 DECL_PIOCTL(PRemoveCallBack)
 {
-    register struct afs_conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSCallBack CallBacks_Array[1];
     struct AFSCBFids theFids;
     struct AFSCBs theCBs;
+    struct rx_connection *rxconn;
     XSTATS_DECLS;
 
     AFS_STATCNT(PRemoveCallBack);
@@ -2721,26 +3005,20 @@ 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);
-       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;
@@ -2751,8 +3029,12 @@ DECL_PIOCTL(PRemoveCallBack)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the name of the cell, the hosts that will be a part of the cell, whether or not it's linked with another cell, the other cell it's linked with, the file server port, and the volume server port
- * \param[out] aout    not in use
+ * \param[in] ain
+ *     the name of the cell, the hosts that will be a part of the cell,
+ *     whether or not it's linked with another cell, the other cell it's
+ *     linked with, the file server port, and the volume server port
+ * \param[out] aout
+ *     not in use
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EACCES      Error if the user doesn't have super-user cedentials
@@ -2790,7 +3072,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);
@@ -2871,8 +3153,8 @@ DECL_PIOCTL(PNewAlias)
 DECL_PIOCTL(PListCells)
 {
     afs_int32 whichCell;
-    register struct cell *tcell = 0;
-    register afs_int32 i;
+    struct cell *tcell = 0;
+    afs_int32 i;
     int code;
 
     AFS_STATCNT(PListCells);
@@ -2910,7 +3192,7 @@ out:
 DECL_PIOCTL(PListAliases)
 {
     afs_int32 whichAlias;
-    register struct cell_alias *tcalias = 0;
+    struct cell_alias *tcalias = 0;
     int code;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2943,25 +3225,32 @@ out:
  * \param[in] ain      the name of the file in this dir to remove
  * \param[out] aout    not in use
  *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval ENOTDIR     Error if the argument to remove is not a directory
- * \retval ENOENT      Error if there is no cache to remove the mount point from or if a vcache doesn't exist
- *
- * \post Ensure that everything is OK before deleting the mountpoint.  If not, don't delete.  Delete a mount point based on a file id.
+ * \retval EINVAL
+ *     Error if some of the standard args aren't set
+ * \retval ENOTDIR
+ *     Error if the argument to remove is not a directory
+ * \retval ENOENT
+ *     Error if there is no cache to remove the mount point from or
+ *     if a vcache doesn't exist
+ *
+ * \post
+ *     Ensure that everything is OK before deleting the mountpoint.
+ *     If not, don't delete.  Delete a mount point based on a file id.
  */
 DECL_PIOCTL(PRemoveMount)
 {
-    register afs_int32 code;
+    afs_int32 code;
     char *bufp;
     char *name;
     struct sysname_info sysState;
     afs_size_t offset, len;
-    register struct afs_conn *tc;
-    register struct dcache *tdc;
-    register struct vcache *tvc;
+    struct afs_conn *tc;
+    struct dcache *tdc;
+    struct vcache *tvc;
     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 */
@@ -2980,7 +3269,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 {
@@ -3000,11 +3289,11 @@ DECL_PIOCTL(PRemoveMount)
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
     }
     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;
@@ -3029,19 +3318,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) {
@@ -3074,20 +3363,6 @@ DECL_PIOCTL(PRemoveMount)
 }
 
 /*!
- * VIOC_VENUSLOG (34) - Enable/Disable venus logging
- *
- * \ingroup pioctl
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- *
- * \notes Obsoleted, perhaps should be PBogus
- */
-DECL_PIOCTL(PVenusLogging)
-{
-    return EINVAL;             /* OBSOLETE */
-}
-
-/*!
  * VIOC_GETCELLSTATUS (35) - Get cell status info
  *
  * \ingroup pioctl
@@ -3102,7 +3377,7 @@ DECL_PIOCTL(PVenusLogging)
  */
 DECL_PIOCTL(PGetCellStatus)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
     char *cellName;
     afs_int32 temp;
 
@@ -3127,17 +3402,22 @@ DECL_PIOCTL(PGetCellStatus)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      The cell you want to set information about, and the values you want to set
- * \param[out] aout    not in use
+ * \param[in] ain
+ *     The cell you want to set information about, and the values you
+ *     want to set
+ * \param[out] aout
+ *     not in use
  *
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EACCES      Error if the user doesn't have super-user credentials
  *
- * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
+ * \post
+ *     Set the state of the cell in a defined struct cell, based on
+ *     whether or not SetUID is allowed
  */
 DECL_PIOCTL(PSetCellStatus)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
     char *cellName;
     afs_int32 flags0, flags1;
 
@@ -3164,53 +3444,40 @@ 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 Wipe everything on the volume.  This is done dependent on which platform this is for.
- *
- * \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)
 {
-    register afs_int32 i;
-    register struct dcache *tdc;
-    register struct vcache *tvc;
-    register struct volume *tv;
-    afs_int32 cell, volume;
+    afs_int32 i;
+    struct dcache *tdc;
+    struct vcache *tvc;
+    struct volume *tv;
+    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 invalidate all
-     * the vcaches associated with the volume.
+     * Clear stat'd flag from all vnodes from this volume; this will
+     * invalidate all the vcaches associated with the volume.
      */
  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);
@@ -3222,10 +3489,6 @@ DECL_PIOCTL(PFlushVolumeData)
                    afs_osi_Sleep(&tvc->f.states);
                    goto loop;
                }
-#endif
-#if    defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
-               VN_HOLD(AFSTOV(tvc));
-#elif defined(AFS_DARWIN80_ENV)
                vp = AFSTOV(tvc);
                if (vnode_get(vp))
                    continue;
@@ -3235,28 +3498,13 @@ DECL_PIOCTL(PFlushVolumeData)
                    AFS_GLOCK();
                    continue;
                }
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-               osi_vnhold(tvc, 0);
 #else
-               VREFCOUNT_INC(tvc); /* AIX, apparently */
+               AFS_FAST_HOLD(tvc);
 #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
@@ -3266,25 +3514,32 @@ DECL_PIOCTL(PFlushVolumeData)
                AFS_FAST_RELE(tvc);
            }
        }
+    }
     ReleaseReadLock(&afs_xvcache);
 
 
-    ObtainWriteLock(&afs_xdcache, 328);        /* needed if you're going to flush any stuff */
+    ObtainWriteLock(&afs_xdcache, 328);        /* needed to flush any stuff */
     for (i = 0; i < afs_cacheFiles; i++) {
        if (!(afs_indexFlags[i] & IFEverUsed))
            continue;           /* never had any data */
-       tdc = afs_GetDSlot(i, NULL);
-       if (tdc->refCount <= 1) {       /* too high, in use by running sys call */
+       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 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.
-                    * 
-                    * If we *must* flush, then this code has to be rearranged to call
-                    * afs_storeAllSegments() first */
+           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);
                }
            }
@@ -3296,39 +3551,110 @@ 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);
+}
 
 /*!
- * VIOCGETVCXSTATUS (41) - gets vnode x status
+ * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
  *
  * \ingroup pioctl
  *
- * \param[in] ain      not in use (avc used)
- * \param[out] aout    vcxstat: the file id, the data version, any lock, the parent vnode, the parent unique id, the trunc position, the callback, cbExpires, what access is being made, what files are open, any users executing/writing, the flock ount, the states, the move stat
+ * \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
  *
- * \retval EINVAL      Error if some of the initial default arguments aren't set
- * \retval EACCES      Error if access to check the mode bits is denied
+ * \ingroup pioctl
  *
- * \post gets stats for the vnode, a struct listed in vcxstat
+ * \param[in] ain
+ *     not in use (avc used)
+ * \param[out] aout
+ *     vcxstat: the file id, the data version, any lock, the parent vnode,
+ *     the parent unique id, the trunc position, the callback, cbExpires,
+ *     what access is being made, what files are open,
+ *     any users executing/writing, the flock count, the states,
+ *     the move stat
+ *
+ * \retval EINVAL
+ *     Error if some of the initial default arguments aren't set
+ * \retval EACCES
+ *     Error if access to check the mode bits is denied
+ *
+ * \post
+ *     gets stats for the vnode, a struct listed in vcxstat
  */
 DECL_PIOCTL(PGetVnodeXStatus)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct vcxstat stat;
     afs_int32 mode, i;
 
@@ -3354,7 +3680,7 @@ DECL_PIOCTL(PGetVnodeXStatus)
     hset(stat.flushDV, avc->flushDV);
     hset(stat.mapDV, avc->mapDV);
     stat.truncPos = avc->f.truncPos;
-    {                          /* just grab the first two - won't break anything... */
+    {                  /* just grab the first two - won't break anything... */
        struct axscache *ac;
 
        for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
@@ -3376,7 +3702,7 @@ DECL_PIOCTL(PGetVnodeXStatus)
 
 DECL_PIOCTL(PGetVnodeXStatus2)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct vcxstat2 stat;
     afs_int32 mode;
 
@@ -3411,13 +3737,23 @@ DECL_PIOCTL(PGetVnodeXStatus2)
  * \param[in] ain      new value for @sys
  * \param[out] aout    count, entry, list (debug values?)
  *
- * \retval EINVAL      Error if afsd isn't running, the new sysname is too large, the new sysname causes issues (starts with a .0 or ..0), there is no PAG set in the credentials, the user of a PAG can't be found, (!(exporter = au->exporter)) "NOT SURE ON THIS"
- * \retval ENODEV      Error if there isn't already a system named that ("I THINK")
- * \retval EACCES      Error if the user doesn't have super-user credentials
- *
- * \post Set the value of @sys if these things work: if the input isn't too long or if input doesn't start with .0 or ..0
- *
- * \notes We require root for local sysname changes, but not for remote (since we don't really believe remote uids anyway) outname[] shouldn't really be needed- this is left as an exercise for the reader.
+ * \retval EINVAL
+ *     Error if afsd isn't running, the new sysname is too large,
+ *     the new sysname causes issues (starts with a . or ..),
+ *     there is no PAG set in the credentials, or the user of a PAG
+ *     can't be found
+ * \retval EACCES
+ *     Error if the user doesn't have super-user credentials
+ *
+ * \post
+ *     Set the value of @sys if these things work: if the input isn't
+ *     too long or if input doesn't start with . or ..
+ *
+ * \notes
+ *     We require root for local sysname changes, but not for remote
+ *     (since we don't really believe remote uids anyway)
+ *     outname[] shouldn't really be needed- this is left as an
+ *     exercise for the reader.
  */
 DECL_PIOCTL(PSetSysName)
 {
@@ -3425,9 +3761,9 @@ DECL_PIOCTL(PSetSysName)
     char outname[MAXSYSNAME];
     afs_int32 setsysname;
     int foundname = 0;
-    register struct afs_exporter *exporter;
-    register struct unixuser *au;
-    register afs_int32 pag, error;
+    struct afs_exporter *exporter;
+    struct unixuser *au;
+    afs_int32 pag, error;
     int t, count, num = 0, allpags = 0;
     char **sysnamelist;
     struct afs_pdata validate;
@@ -3470,8 +3806,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;
        }
@@ -3530,7 +3866,7 @@ DECL_PIOCTL(PSetSysName)
                for (count = 1; count < setsysname; ++count) {
                    if (!afs_sysnamelist[count])
                        osi_Panic
-                           ("PSetSysName: no afs_sysnamelist entry to write\n");
+                          ("PSetSysName: no afs_sysnamelist entry to write\n");
                    if (afs_pd_getString(ain, afs_sysnamelist[count],
                                         MAXSYSNAME) != 0)
                        return EINVAL;
@@ -3546,7 +3882,7 @@ DECL_PIOCTL(PSetSysName)
        if (foundname) {
            if (afs_pd_putString(aout, outname) != 0)
                return E2BIG;
-           for (count = 1; count < foundname; ++count) {       /* ... or list. */
+           for (count = 1; count < foundname; ++count) {    /* ... or list. */
                if (!sysnamelist[count])
                    osi_Panic
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
@@ -3593,11 +3929,12 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
 {
     int i;
     struct volume *j;
-    register int k;
+    int k;
 
     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);
@@ -3634,7 +3971,7 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
     touchedSize = 0;
     for (k = 0; k < num; sp++, k++) {
        if (debugsetsp) {
-           printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
+           afs_warn("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
        }
        matches = 0;
        ObtainReadLock(&afs_xserver);
@@ -3654,7 +3991,7 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
 
        if (sa && matches) {    /* found one! */
            if (debugsetsp) {
-               printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
+               afs_warn("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
            }
            sa->sa_iprank = sp->rank + afs_randomMod15();
            afs_SortOneServer(sa->server);
@@ -3683,7 +4020,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);
        }
@@ -3699,9 +4036,13 @@ afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
  * \param[in] ain      the sprefs value you want the sprefs to be set to
  * \param[out] aout    not in use
  *
- * \retval EIO         Error if the afs daemon hasn't started yet
- * \retval EACCES      Error if the user doesn't have super-user credentials
- * \retval EINVAL      Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
+ * \retval EIO
+ *     Error if the afs daemon hasn't started yet
+ * \retval EACCES
+ *     Error if the user doesn't have super-user credentials
+ * \retval EINVAL
+ *     Error if the struct setsprefs is too large or if it multiplied
+ *     by the number of servers is too large
  *
  * \post set the sprefs using the afs_setsprefs() function
  */
@@ -3729,7 +4070,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,
@@ -3737,7 +4078,7 @@ DECL_PIOCTL(PSetSPrefs)
     return 0;
 }
 
-/* 
+/*
  * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
  *
  * \param[in] ain      the server preferences to be set
@@ -3766,7 +4107,7 @@ DECL_PIOCTL(PSetSPrefs33)
     return 0;
 }
 
-/* 
+/*
  * VIOC_GETSPREFS (43) - Get server ranks
  *
  * \ingroup pioctl
@@ -3779,7 +4120,12 @@ DECL_PIOCTL(PSetSPrefs33)
  *
  * \post Get the sprefs
  *
- * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
+ * \notes
+ *     in the hash table of server structs, all servers with the same
+ *     IP address; will be on the same overflow chain; This could be
+ *     sped slightly in some circumstances by having it cache the
+ *     immediately previous slot in the hash table and some
+ *     supporting information; Only reports file servers now.
  */
 DECL_PIOCTL(PGetSPrefs)
 {
@@ -3864,22 +4210,26 @@ int afs_NFSRootOnly = 1;
  *
  * \ingroup pioctl
  *
- * \param[in] ain      a struct Vic * EIOctl containing export values needed to change between nfs and afs
- * \param[out] aout    a struct of the exporter states (exporter->exp_states)
+ * \param[in] ain
+ *     an integer containing the desired exportee flags
+ * \param[out] aout
+ *     an integer containing the current exporter flags
  *
  * \retval ENODEV      Error if the exporter doesn't exist
  * \retval EACCES      Error if the user doesn't have super-user credentials
  *
- * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
+ * \post
+ *     Changes the state of various values to reflect the change
+ *     of the export values between nfs and afs.
  *
  * \notes Legacy code obtained from IBM.
  */
 DECL_PIOCTL(PExportAfs)
 {
-    afs_int32 export, newint =
-       0, type, changestate, handleValue, convmode, pwsync, smounts;
+    afs_int32 export, newint = 0;
+    afs_int32 type, changestate, handleValue, convmode, pwsync, smounts;
     afs_int32 rempags = 0, pagcb = 0;
-    register struct afs_exporter *exporter;
+    struct afs_exporter *exporter;
 
     AFS_STATCNT(PExportAfs);
     if (afs_pd_getInt(ain, &handleValue) != 0)
@@ -4067,7 +4417,8 @@ DECL_PIOCTL(PTwiddleRx)
  * \param[in] ain      not in use
  * \param[out] aout    initial cache manager params
  *
- * \retval E2BIG       Error if the initial parameters are bigger than some PIGGYSIZE
+ * \retval E2BIG
+ *     Error if the initial parameters are bigger than some PIGGYSIZE
  *
  * \post return the initial cache manager parameters
  */
@@ -4078,7 +4429,6 @@ DECL_PIOCTL(PGetInitParams)
 
     return afs_pd_putBytes(aout, &cm_initParams,
                           sizeof(struct cm_initparams));
-    return 0;
 }
 
 #ifdef AFS_SGI65_ENV
@@ -4104,7 +4454,7 @@ crget(void)
  * \param[in] ain      not in use
  * \param[out] aout    value of cryptall
  *
- * \post get the value of cryptall (presumably whether or not things should be encrypted)
+ * \post Turns on, or disables, rxkad encryption by setting the cryptall global
  */
 DECL_PIOCTL(PGetRxkcrypt)
 {
@@ -4119,12 +4469,17 @@ DECL_PIOCTL(PGetRxkcrypt)
  * \param[in] ain      the argument whether or not things should be encrypted
  * \param[out] aout    not in use
  *
- * \retval EPERM       Error if the user doesn't have super-user credentials
- * \retval EINVAL      Error if the input is too big, or if the input is outside the bounds of what it can be set to
+ * \retval EPERM
+ *     Error if the user doesn't have super-user credentials
+ * \retval EINVAL
+ *     Error if the input is too big, or if the input is outside the
+ *     bounds of what it can be set to
  *
  * \post set whether or not things should be encrypted
  *
- * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
+ * \notes
+ *     may need to be modified at a later date to take into account
+ *     other values for cryptall (beyond true or false)
  */
 DECL_PIOCTL(PSetRxkcrypt)
 {
@@ -4171,7 +4526,8 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
 #endif
     AFS_STATCNT(HandleClientContext);
     if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
-       /* Must at least include the PIOCTL_HEADER header words required by the protocol */
+       /* Must at least include the PIOCTL_HEADER header words
+        * required by the protocol */
        return EINVAL;          /* Too small to be good  */
     }
     ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
@@ -4192,7 +4548,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     ain += sizeof(g1);
     *com = *((afs_uint32 *) ain);
     ain += sizeof(afs_int32);
-    exporter_type = *((afs_uint32 *) ain);     /* In case we support more than NFS */
+    exporter_type = *((afs_uint32 *) ain);/* In case we support more than NFS */
 
     /*
      * Of course, one must be root for most of these functions, but
@@ -4235,21 +4591,26 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     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
-    set_cr_group_info(newcred, groups_alloc(1)); /* not that anything sets this */
+# 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);
     h = ((g1-0x3f00) >> 14) + h + h + h;
-    GROUP_AT(cr_group_info(newcred), 0) = ((h << 28) | l);
+    GROUP_AT(afs_cr_group_info(newcred), 0) = ((h << 28) | l);
 # else
-    set_cr_group_info(newcred, groups_alloc(2));
-    GROUP_AT(cr_group_info(newcred), 0) = g0;
-    GROUP_AT(cr_group_info(newcred), 1) = g1;
+    afs_set_cr_group_info(newcred, groups_alloc(2));
+    GROUP_AT(afs_cr_group_info(newcred), 0) = g0;
+    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;
@@ -4257,7 +4618,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
 #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)
+# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
     newcred->cr_ngroups = 2;
 # else
     for (i = 2; i < NGROUPS; i++)
@@ -4284,7 +4645,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        /* Special case for 'setpag' */
        afs_uint32 pagvalue = genpag();
 
-       au = afs_GetUser(pagvalue, -1, WRITE_LOCK);     /* a new unixuser struct */
+       au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
        /*
         * Note that we leave the 'outexporter' struct held so it won't
         * dissappear on us
@@ -4301,14 +4662,14 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     } else if (!code) {
        EXP_RELE(outexporter);
     }
-    if (!code) 
+    if (!code)
        *com = (*com) | comp;
     return code;
 }
 #endif /* AFS_NEED_CLIENTCONTEXT */
 
 
-/*! 
+/*!
  * VIOC_GETCPREFS (50) - Get client interface
  *
  * \ingroup pioctl
@@ -4319,7 +4680,9 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
  * \retval EIO         Error if the afs daemon hasn't started yet
  * \retval EINVAL      Error if some of the standard args aren't set
  *
- * \post get all interface addresses and other information of the client interface
+ * \post
+ *     get all interface addresses and other information of the client
+ *     interface
  */
 DECL_PIOCTL(PGetCPrefs)
 {
@@ -4347,7 +4710,7 @@ DECL_PIOCTL(PGetCPrefs)
     ObtainReadLock(&afs_xinterface);
 
     /* copy out the client interface information from the
-     ** kernel data structure "interface" to the output buffer
+     * kernel data structure "interface" to the output buffer
      */
     for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
         && (j < maxNumber); i++, j++, srvout++)
@@ -4421,20 +4784,27 @@ DECL_PIOCTL(PSetCPrefs)
  *
  * \ingroup pioctl
  *
- * \param[in] ain      the last part of a path to a mount point, which tells us what to flush
- * \param[out] aout    not in use
+ * \param[in] ain
+ *     the last part of a path to a mount point, which tells us what to flush
+ * \param[out] aout
+ *     not in use
  *
- * \retval EINVAL      Error if some of the initial arguments aren't set
- * \retval ENOTDIR     Error if the initial argument for the mount point isn't a directory
- * \retval ENOENT      Error if the dcache entry isn't set
+ * \retval EINVAL
+ *     Error if some of the initial arguments aren't set
+ * \retval ENOTDIR
+ *     Error if the initial argument for the mount point isn't a directory
+ * \retval ENOENT
+ *     Error if the dcache entry isn't set
  *
- * \post remove all of the mount data from the dcache regarding a certain mount point
+ * \post
+ *     remove all of the mount data from the dcache regarding a
+ *     certain mount point
  */
 DECL_PIOCTL(PFlushMount)
 {
-    register afs_int32 code;
-    register struct vcache *tvc;
-    register struct dcache *tdc;
+    afs_int32 code;
+    struct vcache *tvc;
+    struct dcache *tdc;
     struct VenusFid tfid;
     char *bufp;
     char *mount;
@@ -4456,7 +4826,7 @@ DECL_PIOCTL(PFlushMount)
     }
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
-       return ENOENT;
+       return EIO;
     Check_AtSys(avc, mount, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
@@ -4476,33 +4846,24 @@ DECL_PIOCTL(PFlushMount)
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
     }
     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)
@@ -4521,7 +4882,9 @@ DECL_PIOCTL(PFlushMount)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EINVAL      Error if the flag input is too long
  *
- * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
+ * \post
+ *     either enable process RPCStats, disable process RPCStats,
+ *     or clear the process RPCStats
  */
 DECL_PIOCTL(PRxStatProc)
 {
@@ -4560,7 +4923,9 @@ DECL_PIOCTL(PRxStatProc)
  * \retval EACCES      Error if the user doesn't have super-user credentials
  * \retval EINVAL      Error if the flag input is too long
  *
- * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
+ * \post
+ *     either enable peer RPCStatws, disable peer RPCStats,
+ *     or clear the peer RPCStats
  */
 DECL_PIOCTL(PRxStatPeer)
 {
@@ -4589,8 +4954,8 @@ DECL_PIOCTL(PRxStatPeer)
 
 DECL_PIOCTL(PPrefetchFromTape)
 {
-    register 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;
@@ -4599,8 +4964,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;
 
@@ -4623,25 +4989,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);
@@ -4655,13 +5021,14 @@ DECL_PIOCTL(PPrefetchFromTape)
 
 DECL_PIOCTL(PFsCmd)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct afs_conn *tc;
     struct vcache *tvc;
     struct FsCmdInputs *Inputs;
     struct FsCmdOutputs *Outputs;
     struct VenusFid tfid;
     struct AFSFid *Fid;
+    struct rx_connection *rxconn;
 
     if (!avc)
        return EINVAL;
@@ -4691,21 +5058,20 @@ 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, 
-                                       (struct FsCmdOutputs *)aout);
+                   RXAFS_FsCmd(rxconn, Fid, Inputs, Outputs);
                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);
-    } else {                   /* just a status request, return also link data */
+    } else {           /* just a status request, return also link data */
        code = 0;
        Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
        Outputs->chars[0] = 0;
@@ -4738,13 +5104,13 @@ DECL_PIOCTL(PNewUuid)
     return 0;
 }
 
-#if defined(AFS_CACHE_BYPASS)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
 DECL_PIOCTL(PSetCachingThreshold)
 {
     afs_int32 getting = 1;
     afs_int32 setting = 1;
-    afs_int32 threshold;
+    afs_int32 threshold = AFS_CACHE_BYPASS_DISABLED;
 
     if (afs_pd_getInt(ain, &threshold) != 0)
        setting = 0;
@@ -4754,22 +5120,27 @@ DECL_PIOCTL(PSetCachingThreshold)
 
     if (setting == 0 && getting == 0)
        return EINVAL;
-       
-    /* 
+
+    /*
      * If setting, set first, and return the value now in effect
      */
     if (setting) {
        if (!afs_osi_suser(*acred))
            return EPERM;
        cache_bypass_threshold = threshold;
-        afs_warn("Cache Bypass Threshold set to: %d\n", 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 */
-    if (getting) {
-       return afs_pd_putInt32(aout, cache_bypass_threshold);
+    if (getting)
+       return afs_pd_putInt(aout, cache_bypass_threshold);
 
     return(0);
 }
@@ -4779,14 +5150,15 @@ 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;
 
     /*AFS_STATCNT(PCallBackAddr); */
     if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
@@ -4820,6 +5192,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) {
@@ -4849,38 +5222,39 @@ 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 */
+    afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
 #endif /* UKERNEL */
     return 0;
 }
 
 DECL_PIOCTL(PDiscon)
 {
-#ifdef AFS_DISCON_ENV
     static afs_int32 mode = 1; /* Start up in 'off' */
     afs_int32 force = 0;
     int code = 0;
-    char flags[3];
+    char flags[4];
+    struct vrequest lreq;
 
-    if (afs_pd_getBytes(ain, &flags, 3) == 0) {
+    if (afs_pd_getBytes(ain, &flags, 4) == 0) {
        if (!afs_osi_suser(*acred))
            return EPERM;
 
@@ -4890,6 +5264,12 @@ DECL_PIOCTL(PDiscon)
            afs_ConflictPolicy = flags[1] - 1;
        if (flags[2])
            force = 1;
+       if (flags[3]) {
+           /* Fake InitReq support for UID override */
+           memset(&lreq, 0, sizeof(lreq));
+           lreq.uid = flags[3];
+           areq = &lreq; /* override areq we got */
+       }
 
        /*
         * All of these numbers are hard coded in fs.c. If they
@@ -4915,7 +5295,7 @@ DECL_PIOCTL(PDiscon)
            afs_in_sync = 0;
 
            if (code && !force) {
-               printf("Files not synchronized properly, still in discon state. \n"
+               afs_warnuser("Files not synchronized properly, still in discon state. \n"
                       "Please retry or use \"force\".\n");
                mode = 0;
            } else {
@@ -4925,7 +5305,7 @@ DECL_PIOCTL(PDiscon)
                afs_ClearAllStatdFlag();
                afs_is_disconnected = 0;
                afs_is_discon_rw = 0;
-               printf("\nSync succeeded. You are back online.\n");
+               afs_warnuser("\nSync succeeded. You are back online.\n");
            }
 
            ReleaseWriteLock(&afs_discon_lock);
@@ -4941,16 +5321,206 @@ DECL_PIOCTL(PDiscon)
        return code;
 
     return afs_pd_putInt(aout, mode);
-#else
-    return EINVAL;
+}
+
+#define MAX_PIOCTL_TOKENS 10
+
+DECL_PIOCTL(PSetTokens2)
+{
+    int code =0;
+    int i, cellNum, primaryFlag;
+    XDR xdrs;
+    struct unixuser *tu;
+    struct vrequest *treq = NULL;
+    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 defined(AFS_LINUX26_ENV)
+       afs_ucred_t *old_cred = *acred;
+#endif
+       if (_settok_setParentPag(acred) == 0) {
+#if defined(AFS_LINUX26_ENV)
+           /* setpag() may have changed our credentials */
+           *acred = crref();
+           crfree(old_cred);
 #endif
+           code = afs_CreateReq(&treq, *acred);
+           if (code) {
+               xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+               return code;
+           }
+           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);
+    afs_DestroyReq(treq);
+
+    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;
-    register afs_int32 i;
-    register struct unixuser *tu;
+    afs_int32 i;
+    struct unixuser *tu;
 
     AFS_STATCNT(PUnlog);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -4974,20 +5544,20 @@ 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->vid = UNDEFVID;
-               tu->states &= ~UHasTokens;
-               /* security is not having to say you're sorry */
-               memset(&tu->ct, 0, sizeof(struct ClearToken));
                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
                 * afs_GCUserData to remove this entry
                 */
-               tu->ct.EndTimestamp = 0;
                tu->tokenTime = 0;
 #endif /* UKERNEL */
            }