New GetToken pioctl
[openafs.git] / src / afs / afs_pioctl.c
index cc13e04..6b1a57c 100644 (file)
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #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"
 
 struct VenusFid afs_rootFid;
 afs_int32 afs_waitForever = 0;
 short afs_waitForeverCount = 0;
 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE;        /* show all messages */
 
-#define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
-       char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
-       struct AFS_UCRED **acred)
+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;
+
+struct afs_pdata {
+    char *ptr;
+    size_t remaining;
+};
+
+/*
+ * A set of handy little functions for encoding and decoding
+ * pioctls without losing your marbles, or memory integrity
+ */
+
+static_inline int
+afs_pd_alloc(struct afs_pdata *apd, size_t size)
+{
+
+    if (size > AFS_LRALLOCSIZ)
+       apd->ptr = osi_Alloc(size + 1);
+    else
+       apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+
+    if (apd->ptr == NULL)
+       return ENOMEM;
+
+    apd->remaining = size;
+
+    return 0;
+}
+
+static_inline void
+afs_pd_free(struct afs_pdata *apd)
+{
+    if (apd->ptr == NULL)
+       return;
+
+    if (apd->remaining > AFS_LRALLOCSIZ)
+       osi_Free(apd->ptr, apd->remaining + 1);
+    else
+       osi_FreeLargeSpace(apd->ptr);
+
+    apd->ptr = NULL;
+    apd->remaining = 0;
+}
+
+static_inline char *
+afs_pd_where(struct afs_pdata *apd)
+{
+    return apd ? apd->ptr : NULL;
+}
+
+static_inline size_t
+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)
+{
+    if (apd == NULL || apd->remaining < skip)
+       return EINVAL;
+    apd->remaining -= skip;
+    apd->ptr += skip;
+
+    return 0;
+}
+
+static_inline int
+afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
+{
+    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+       return EINVAL;
+    apd->remaining -= sizeof(afs_int32);
+    *val = *(afs_int32 *)apd->ptr;
+    apd->ptr += sizeof(afs_int32);
+    return 0;
+}
+
+static_inline int
+afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
+{
+    return afs_pd_getInt(apd, (afs_int32 *)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;
+}
+
+static_inline void *
+afs_pd_inline(struct afs_pdata *apd, size_t bytes)
+{
+    void *ret;
+
+    if (apd == NULL || apd->remaining < bytes)
+       return NULL;
+
+    ret = apd->ptr;
+
+    apd->remaining -= bytes;
+    apd->ptr += 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)
+{
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    if (len > maxLen)
+       return E2BIG;
+    memcpy(str, apd->ptr, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
+{
+    size_t len;
+
+    if (apd == NULL || apd->remaining <= 0)
+       return EINVAL;
+    len = strlen(apd->ptr) + 1;
+    *str = apd->ptr;
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
+{
+    if (apd == NULL || apd->remaining < sizeof(afs_int32))
+       return E2BIG;
+    *(afs_int32 *)apd->ptr = val;
+    apd->ptr += sizeof(afs_int32);
+    apd->remaining -= sizeof(afs_int32);
+
+    return 0;
+}
+
+static_inline int
+afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
+{
+    if (apd == NULL || apd->remaining < len)
+       return E2BIG;
+    memcpy(apd->ptr, bytes, len);
+    apd->ptr += len;
+    apd->remaining -= len;
+    return 0;
+}
+
+static_inline int
+afs_pd_putString(struct afs_pdata *apd, char *str) {
+
+    /* Add 1 so we copy the NULL too */
+    return afs_pd_putBytes(apd, str, strlen(str) +1);
+}
+
+/*!
+ * \defgroup pioctl Path IOCTL functions
+ *
+ * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
+ *
+ * \param[in] avc
+ *     the AFS vcache structure in use by pioctl
+ * \param[in] afun
+ *     not in use
+ * \param[in] areq
+ *     the AFS vrequest structure
+ * \param[in] ain
+ *     an afs_pdata block describing the data received from the caller
+ * \param[in] aout
+ *     an afs_pdata block describing a pre-allocated block for output
+ * \param[in] acred
+ *     UNIX credentials structure underlying the operation
+ */
+
+#define DECL_PIOCTL(x) \
+       static int x(struct vcache *avc, int afun, struct vrequest *areq, \
+                    struct afs_pdata *ain, struct afs_pdata *aout, \
+                    afs_ucred_t **acred)
 
 /* Prototypes for pioctl routines */
 DECL_PIOCTL(PGetFID);
@@ -46,11 +263,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);
@@ -66,7 +285,6 @@ DECL_PIOCTL(PNewAlias);
 DECL_PIOCTL(PListCells);
 DECL_PIOCTL(PListAliases);
 DECL_PIOCTL(PRemoveMount);
-DECL_PIOCTL(PVenusLogging);
 DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
@@ -88,8 +306,16 @@ DECL_PIOCTL(PFlushMount);
 DECL_PIOCTL(PRxStatProc);
 DECL_PIOCTL(PRxStatPeer);
 DECL_PIOCTL(PPrefetchFromTape);
-DECL_PIOCTL(PResidencyCmd);
+DECL_PIOCTL(PFsCmd);
 DECL_PIOCTL(PCallBackAddr);
+DECL_PIOCTL(PDiscon);
+DECL_PIOCTL(PNFSNukeCreds);
+DECL_PIOCTL(PNewUuid);
+DECL_PIOCTL(PPrecache);
+DECL_PIOCTL(PGetPAG);
+#if defined(AFS_CACHE_BYPASS)
+DECL_PIOCTL(PSetCachingThreshold);
+#endif
 
 /*
  * A macro that says whether we're going to need HandleClientContext().
@@ -102,219 +328,138 @@ DECL_PIOCTL(PCallBackAddr);
 /* Prototypes for private routines */
 #ifdef AFS_NEED_CLIENTCONTEXT
 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
-                              struct AFS_UCRED **acred,
-                              struct AFS_UCRED *credp);
+                              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_UCRED **acred);
-static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
-                   struct AFS_UCRED *acred);
+                    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);
 
+typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
+                              struct afs_pdata *, struct afs_pdata *,
+                              afs_ucred_t **);
 
-static int (*(VpioctlSw[])) () = {
+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 */
-       PResidencyCmd,          /* 67 -- MR-AFS: 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 int (*(CpioctlSw[])) () = {
-    PBogus,                    /* 0 */
-       PNewAlias,              /* 1 -- create new cell alias */
-       PListAliases,           /* 2 -- list cell aliases */
-       PCallBackAddr,          /* 3 -- request addr for callback rxcon */
+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 */
+    PGetTokens2,                /* 7 */
+    PSetTokens2,                /* 8 */
+    PNewUuid,                   /* 9 */
+    PBogus,                     /* 10 */
+    PBogus,                     /* 11 */
+    PPrecache,                  /* 12 */
+    PGetPAG,                    /* 13 */
 };
 
-#define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
-int afs_nobody = NFS_NOBODY;
-
-#if (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)) || defined(AFS_HPUX_64BIT_ENV) || defined(AFS_SUN57_64BIT_ENV) || (defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)) || defined(NEED_IOCTL32)
-static void
-afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
-{
-    dst->in = (char *)(unsigned long)src->in;
-    dst->out = (char *)(unsigned long)src->out;
-    dst->in_size = src->in_size;
-    dst->out_size = src->out_size;
-}
-#endif
-
-/*
- * If you need to change copyin_afs_ioctl(), you may also need to change
- * copyin_iparam().
- */
-
-static int
-copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
-{
-    int code;
-#if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
-    struct afs_ioctl32 dst32;
-
-    if (!(IS64U)) {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           afs_ioctl32_to_afs_ioctl(&dst32, dst);
-       return code;
-    }
-#endif /* defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) */
-
-
-#if defined(AFS_HPUX_64BIT_ENV)
-    struct afs_ioctl32 dst32;
-
-    if (is_32bit(u.u_procp)) { /* is_32bit() in proc_iface.h */
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           afs_ioctl32_to_afs_ioctl(&dst32, dst);
-       return code;
-    }
-#endif /* defined(AFS_HPUX_64BIT_ENV) */
-
-#if defined(AFS_SUN57_64BIT_ENV)
-    struct afs_ioctl32 dst32;
-
-    if (get_udatamodel() == DATAMODEL_ILP32) {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           afs_ioctl32_to_afs_ioctl(&dst32, dst);
-       return code;
-    }
-#endif /* defined(AFS_SUN57_64BIT_ENV) */
-
-#if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
-    struct afs_ioctl32 dst32;
-
-    if (!ABI_IS_64BIT(get_current_abi())) {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           afs_ioctl32_to_afs_ioctl(&dst32, dst);
-       return code;
-    }
-#endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
-
-#if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
-    struct afs_ioctl32 dst32;
-
-#ifdef AFS_SPARC64_LINUX26_ENV
-    if (test_thread_flag(TIF_32BIT))
-#elif AFS_SPARC64_LINUX24_ENV
-    if (current->thread.flags & SPARC_FLAG_32BIT)
-#elif defined(AFS_SPARC64_LINUX20_ENV)
-    if (current->tss.flags & SPARC_FLAG_32BIT)
-
-#elif defined(AFS_AMD64_LINUX26_ENV)
-    if (test_thread_flag(TIF_IA32))
-#elif defined(AFS_AMD64_LINUX20_ENV)
-    if (current->thread.flags & THREAD_IA32)
-
-#elif defined(AFS_PPC64_LINUX26_ENV)
-    if (current->thread_info->flags & _TIF_32BIT)
-#elif defined(AFS_PPC64_LINUX20_ENV)
-    if (current->thread.flags & PPC_FLAG_32BIT)
-
-#elif defined(AFS_S390X_LINUX26_ENV)
-    if (test_thread_flag(TIF_31BIT))
-#elif defined(AFS_S390X_LINUX20_ENV)
-    if (current->thread.flags & S390_FLAG_31BIT)
-
+static pioctlFunction OpioctlSw[]  = {
+    PBogus,                    /* 0 */
+    PNFSNukeCreds,             /* 1 -- nuke all creds for NFS client */
+#if defined(AFS_CACHE_BYPASS)
+    PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
 #else
-#error pioctl32 not done for this linux
+    PNoop                       /* 2 -- get/set cache-bypass size threshold */
 #endif
-    {
-       AFS_COPYIN(cmarg, (caddr_t) & dst32, sizeof dst32, code);
-       if (!code)
-           afs_ioctl32_to_afs_ioctl(&dst32, dst);
-       return code;
-    }
-#endif /* defined(AFS_LINUX_64BIT_KERNEL) */
+};
 
-    AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
-    return code;
-}
+#define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
+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);
 
     switch (acom & 0xff) {
     case 1:
-       avc->states |= CSafeStore;
+       avc->f.states |= CSafeStore;
        avc->asynchrony = 0;
+       /* SXW - Should we force a MetaData flush for this flag setting */
        break;
 
        /* case 2 used to be abort store, but this is no longer provided,
@@ -323,10 +468,10 @@ 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->fid.Cell, READ_LOCK);
+           tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
            if (tcell) {
                i = strlen(tcell->cellName) + 1;        /* bytes to copy out */
 
@@ -364,8 +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.
@@ -389,15 +533,111 @@ 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 =
+                   (struct afs_ioctl *)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;
@@ -423,82 +663,73 @@ 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 */
-#ifndef AFS_HPUX102_ENV
-#if !defined(AFS_SGI_ENV)
-#ifdef AFS_AIX32_ENV
-#ifdef AFS_AIX51_ENV
-#ifdef __64BIT__
-kioctl(fdes, com, arg, ext, arg2, arg3)
-#else /* __64BIT__ */
-kioctl32(fdes, com, arg, ext, arg2, arg3)
-#endif /* __64BIT__ */
-     caddr_t arg2, arg3;
-#else
-kioctl(fdes, com, arg, ext)
-#endif
-     int fdes, com;
-     caddr_t arg, ext;
-{
-    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;
 };
 
-afs_xioctl(uap, rvp)
-     struct afs_ioctl_sys *uap;
-     rval_t *rvp;
-{
-#elif defined(AFS_OSF_ENV)
-afs_xioctl(p, args, retval)
-     struct proc *p;
-     void *args;
-     long *retval;
-{
-    struct a {
-       long fd;
-       u_long com;
-       caddr_t arg;
-    } *uap = (struct a *)args;
-#elif defined(AFS_FBSD50_ENV)
-#define arg data
 int
-afs_xioctl(td, uap, retval)
-     struct thread *td;
-     register struct ioctl_args *uap;
-     register_t *retval;
+afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
 {
-    struct proc *p = td->td_proc;
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-struct ioctl_args {
-    int fd;
-    u_long com;
-    caddr_t arg;
-};
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
 
-int
-afs_xioctl(p, uap, retval)
-     struct proc *p;
-     register struct ioctl_args *uap;
-     register_t *retval;
-{
+    AFS_STATCNT(afs_xioctl);
+# if defined(AFS_SUN57_ENV)
+    fd = getf(uap->fd);
+    if (!fd)
+       return (EBADF);
+# elif defined(AFS_SUN54_ENV)
+    fd = GETF(uap->fd);
+    if (!fd)
+       return (EBADF);
+# else
+    if (code = getf(uap->fd, &fd)) {
+       return (code);
+    }
+# endif
+    if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
+       tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
+       if (tvc && IsAfsVnode(AFSTOV(tvc))) {
+           /* This is an AFS vnode */
+           if (((uap->com >> 8) & 0xff) == 'V') {
+               struct afs_ioctl *datap;
+               AFS_GLOCK();
+               datap =
+                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               if (code) {
+                   osi_FreeSmallSpace(datap);
+                   AFS_GUNLOCK();
+# if defined(AFS_SUN54_ENV)
+                   releasef(uap->fd);
+# else
+                   releasef(fd);
+# endif
+                   return (EFAULT);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+# if defined(AFS_SUN57_ENV)
+    releasef(uap->fd);
+# elif defined(AFS_SUN54_ENV)
+    RELEASEF(uap->fd);
+# else
+    releasef(fd);
+# endif
+    if (!ioctlDone)
+       code = ioctl(uap, rvp);
+
+    return (code);
+}
 #elif defined(AFS_LINUX22_ENV)
 struct afs_ioctl_sys {
     unsigned int com;
@@ -509,236 +740,207 @@ afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
           unsigned long arg)
 {
     struct afs_ioctl_sys ua, *uap = &ua;
-#else
+    struct vcache *tvc;
+    int ioctlDone = 0, 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();
+           ioctlDone = 1;
+       }
+       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(void)
+afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
 {
-    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_OSF_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;
+    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, struct ioctl_args *uap,
+          register_t *retval)
+{
+    afs_proc_t *p = td->td_proc;
+# else
+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)
+{
+# 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 ((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_OSF_ENV)
-    fd = NULL;
-    if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
-       return code;
-#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)
+# if defined(AFS_OBSD_ENV)
        tvc =
            IsAfsVnode((struct vnode *)fd->
                       f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
-#else
+# else
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
-#endif
-#endif /* AFS_LINUX22_ENV */
+# endif
        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);
-               code=copyin_afs_ioctl((char *)uap->arg, datap);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               code = copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
                    AFS_GUNLOCK();
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
                    return code;
-#else
-#if    defined(AFS_SUN5_ENV)
-#ifdef AFS_SUN54_ENV
-                   releasef(uap->fd);
-#else
-                   releasef(fd);
-#endif
-                   return (EFAULT);
-#else
-#ifdef AFS_OSF_ENV
-#ifdef AFS_OSF30_ENV
-                   FP_UNREF_ALWAYS(fd);
-#else
-                   FP_UNREF(fd);
-#endif
-                   return code;
-#else /* AFS_OSF_ENV */
-#ifdef AFS_AIX41_ENV
-                   ufdrele(uap->fd);
-#endif
-#ifdef AFS_LINUX22_ENV
-                   return -code;
-#else
-                   setuerror(code);
-                   return;
-#endif
-#endif
-#endif
-#endif
                }
                code = HandleIoctl(tvc, uap->com, datap);
                osi_FreeSmallSpace(datap);
                AFS_GUNLOCK();
                ioctlDone = 1;
-#ifdef AFS_AIX41_ENV
-               ufdrele(uap->fd);
-#endif
-#ifdef AFS_OSF_ENV
-#ifdef AFS_OSF30_ENV
-               FP_UNREF_ALWAYS(fd);
-#else
-               FP_UNREF(fd);
-#endif
-#endif
            }
-#if defined(AFS_LINUX22_ENV)
-           else
-               code = EINVAL;
-#endif
        }
     }
 
     if (!ioctlDone) {
-#ifdef 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;
-#else /* !AFS_AIX41_ENV */
-#ifdef 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_OSF_ENV)
-       code = ioctl(p, args, retval);
-#ifdef AFS_OSF30_ENV
-       FP_UNREF_ALWAYS(fd);
-#else
-       FP_UNREF(fd);
-#endif
-       return code;
-#elif !defined(AFS_LINUX22_ENV)
+# if defined(AFS_FBSD_ENV)
+       return ioctl(td, uap);
+# elif defined(AFS_OBSD_ENV)
+       code = sys_ioctl(p, uap, retval);
+# elif defined(AFS_NBSD_ENV)
+           struct lwp *l = osi_curproc();
+           code = sys_ioctl(l, uap, retval);
+# endif
+    }
+
+    return (code);
+}
+#elif defined(UKERNEL)
+int
+afs_xioctl(void)
+{
+    struct a {
+       int fd;
+       int com;
+       caddr_t arg;
+    } *uap = (struct a *)get_user_struct()->u_ap;
+    struct file *fd;
+    struct vcache *tvc;
+    int ioctlDone = 0, code = 0;
+
+    AFS_STATCNT(afs_xioctl);
+
+    fd = getf(uap->fd);
+    if (!fd)
+       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 */
+       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 (setuerror(code), code);
+               }
+               code = HandleIoctl(tvc, uap->com, datap);
+               osi_FreeSmallSpace(datap);
+               AFS_GUNLOCK();
+               ioctlDone = 1;
+           }
+       }
+    }
+
+    if (!ioctlDone) {
        ioctl();
-#endif
-#endif
     }
-#ifdef AFS_SUN5_ENV
-    if (ioctlDone)
-#ifdef AFS_SUN54_ENV
-       releasef(uap->fd);
-#else
-       releasef(fd);
-#endif
-    return (code);
-#else
-#ifdef AFS_LINUX22_ENV
-    return -code;
-#else
-#if 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
-#endif /* AFS_LINUX22_ENV */
-#endif /* AFS_SUN5_ENV */
-#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-    return (code);
-#endif
+
+    return 0;
 }
-#endif /* AFS_SGI_ENV */
 #endif /* AFS_HPUX102_ENV */
 
 #if defined(AFS_SGI_ENV)
@@ -759,36 +961,16 @@ afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
     AFS_GLOCK();
     code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
     AFS_GUNLOCK();
-#ifdef AFS_SGI64_ENV
+# ifdef AFS_SGI64_ENV
     return code;
-#else
+# else
     return u.u_error;
-#endif
-}
-
-#elif defined(AFS_OSF_ENV)
-afs_pioctl(p, args, retval)
-     struct proc *p;
-     void *args;
-     int *retval;
-{
-    struct a {
-       char *path;
-       int cmd;
-       caddr_t cmarg;
-       int follow;
-    } *uap = (struct a *)args;
-
-    AFS_STATCNT(afs_pioctl);
-    return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
+# endif
 }
 
-#elif defined(AFS_FBSD50_ENV)
+#elif defined(AFS_FBSD_ENV)
 int
-afs_pioctl(td, args, retval)
-     struct thread *td;
-     void *args;
-     int *retval;
+afs_pioctl(struct thread *td, void *args, int *retval)
 {
     struct a {
        char *path;
@@ -804,10 +986,7 @@ afs_pioctl(td, args, retval)
 
 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 int
-afs_pioctl(p, args, retval)
-     struct proc *p;
-     void *args;
-     int *retval;
+afs_pioctl(afs_proc_t *p, void *args, int *retval)
 {
     struct a {
        char *path;
@@ -817,9 +996,19 @@ afs_pioctl(p, args, retval)
     } *uap = (struct a *)args;
 
     AFS_STATCNT(afs_pioctl);
+# 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
 }
 
 #endif
@@ -833,28 +1022,28 @@ afs_pioctl(p, args, retval)
 
 int
 #ifdef AFS_SUN5_ENV
-afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
-     rval_t *rvp;
-     struct AFS_UCRED *credp;
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
+                  rval_t *vvp, afs_ucred_t *credp)
 #else
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-afs_syscall_pioctl(path, com, cmarg, follow, credp)
-     struct AFS_UCRED *credp;
+#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_ucred_t *credp)
 #else
-afs_syscall_pioctl(path, com, cmarg, follow)
+afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #endif
 #endif
-     char *path;
-     unsigned int com;
-     caddr_t cmarg;
-     int follow;
 {
     struct afs_ioctl data;
 #ifdef AFS_NEED_CLIENTCONTEXT
-    struct AFS_UCRED *tmpcred;
+    afs_ucred_t *tmpcred = NULL;
 #endif
-    struct AFS_UCRED *foreigncreds = NULL;
-    register afs_int32 code = 0;
+#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
+    afs_int32 code = 0;
     struct vnode *vp = NULL;
 #ifdef AFS_AIX41_ENV
     struct ucred *credp = crref();     /* don't free until done! */
@@ -877,7 +1066,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
     }
     if ((com & 0xff) == PSetClientContext) {
 #ifdef AFS_NEED_CLIENTCONTEXT
-#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
        code = HandleClientContext(&data, &com, &foreigncreds, credp);
 #else
        code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
@@ -907,7 +1096,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
         * like afs_osi_suser(cred) which, I think, is better since it
         * generalizes and supports multi cred environments...
         */
-#ifdef AFS_SUN5_ENV
+#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
        tmpcred = credp;
        credp = foreigncreds;
 #elif defined(AFS_AIX41_ENV)
@@ -949,11 +1138,15 @@ afs_syscall_pioctl(path, com, cmarg, follow)
                       foreigncreds ? foreigncreds : credp);
 #else
 #ifdef AFS_LINUX22_ENV
-       code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
+       code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
        if (!code)
            vp = (struct vnode *)dp->d_inode;
 #else
-       code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
+       code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
+#if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
+       if (vp != NULL)
+               VN_HOLD(vp);
+#endif /* AFS_FBSD80_ENV */
 #endif /* AFS_LINUX22_ENV */
 #endif /* AFS_AIX41_ENV */
        AFS_GLOCK();
@@ -967,6 +1160,24 @@ afs_syscall_pioctl(path, com, cmarg, follow)
     } else
        vp = NULL;
 
+#if defined(AFS_SUN510_ENV)
+    if (vp && !IsAfsVnode(vp)) {
+       struct vnode *realvp;
+       if
+#ifdef AFS_SUN511_ENV
+          (VOP_REALVP(vp, &realvp, NULL) == 0)
+#else
+         (VOP_REALVP(vp, &realvp) == 0)
+#endif
+{
+           struct vnode *oldvp = vp;
+
+           VN_HOLD(realvp);
+           vp = realvp;
+           AFS_RELE(oldvp);
+       }
+    }
+#endif
     /* now make the call if we were passed no file, or were passed an AFS file */
     if (!vp || IsAfsVnode(vp)) {
 #if defined(AFS_SUN5_ENV)
@@ -999,6 +1210,9 @@ afs_syscall_pioctl(path, com, cmarg, follow)
        }
 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
+#elif defined(UKERNEL)
+       code = afs_HandlePioctl(vp, com, &data, follow,
+                               &(get_user_struct()->u_cred));
 #else
        code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
 #endif
@@ -1020,7 +1234,9 @@ afs_syscall_pioctl(path, com, cmarg, follow)
        set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
 #elif  defined(AFS_SGI_ENV)
        OSI_SET_CURRENT_CRED(tmpcred);  /* restore original credentials */
-#elif  !defined(AFS_SUN5_ENV)
+#elif  defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+       credp = tmpcred;                /* restore original credentials */
+#else
        osi_curcred() = tmpcred;        /* restore original credentials */
 #endif /* AFS_HPUX101_ENV */
        crfree(foreigncreds);
@@ -1031,6 +1247,10 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #ifdef AFS_LINUX22_ENV
        dput(dp);
 #else
+#if defined(AFS_FBSD80_ENV)
+    if (VOP_ISLOCKED(vp))
+       VOP_UNLOCK(vp, 0);
+#endif /* AFS_FBSD80_ENV */
        AFS_RELE(vp);           /* put vnode back */
 #endif
     }
@@ -1044,37 +1264,53 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
 }
 
+#ifdef AFS_DARWIN100_ENV
+int
+afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
+                  int follow, afs_ucred_t *credp)
+{
+    return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
+                               CAST_USER_ADDR_T((unsigned int)cmarg), follow,
+                               credp);
+}
+#endif
+
 #define MAXPIOCTLTOKENLEN \
 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
 
 int
 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
-                register struct afs_ioctl *ablob, int afollow,
-                struct AFS_UCRED **acred)
+                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;
-    afs_int32 inSize, outSize, outSizeMax;
-    char *inData, *outData;
-    int (*(*pioctlSw)) ();
+    afs_int32 code;
+    afs_int32 function, device;
+    struct afs_pdata input, output;
+    struct afs_pdata copyInput, copyOutput;
+    size_t outSize;
+    pioctlFunction *pioctlSw;
     int pioctlSwSize;
     struct afs_fakestat_state fakestate;
 
+    memset(&input, 0, sizeof(input));
+    memset(&output, 0, sizeof(output));
+
     avc = avp ? VTOAFS(avp) : NULL;
     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
-    if ((code = afs_InitReq(&treq, *acred)))
+
+    code = afs_InitReq(&treq, *acred);
+    if (code)
        return code;
+
     afs_InitFakeStat(&fakestate);
     if (avc) {
        code = afs_EvalFakeStat(&avc, &fakestate, &treq);
-       if (code) {
-           afs_PutFakeStat(&fakestate);
-           return code;
-       }
+       if (code)
+           goto out;
     }
     device = (acom & 0xff00) >> 8;
     switch (device) {
@@ -1086,98 +1322,116 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
        pioctlSw = CpioctlSw;
        pioctlSwSize = sizeof(CpioctlSw);
        break;
+    case 'O':                  /* Coordinated/common pioctls */
+       pioctlSw = OpioctlSw;
+       pioctlSwSize = sizeof(OpioctlSw);
+       break;
     default:
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;
+       code = EINVAL;
+       goto out;
     }
     function = acom & 0xff;
     if (function >= (pioctlSwSize / sizeof(char *))) {
-       afs_PutFakeStat(&fakestate);
-       return EINVAL;          /* out of range */
+       code = EINVAL;
+       goto out;
     }
-    inSize = ablob->in_size;
 
     /* Do all range checking before continuing */
-    if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
-       return E2BIG;
-
-    /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
-    if (inSize > AFS_LRALLOCSIZ) {
-       inData = osi_Alloc(inSize + 1);
-    } else {
-       inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    if (ablob->in_size > MAXPIOCTLTOKENLEN ||
+        ablob->in_size < 0 || ablob->out_size < 0) {
+       code = EINVAL;
+       goto out;
     }
-    if (!inData)
-       return ENOMEM;
-    if (inSize > 0) {
-       AFS_COPYIN(ablob->in, inData, inSize, code);
-       inData[inSize] = '\0';
-    } else
-       code = 0;
-    if (code) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return code;
+
+    code = afs_pd_alloc(&input, ablob->in_size);
+    if (code)
+       goto out;
+
+    if (ablob->in_size > 0) {
+       AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
+       input.ptr[input.remaining] = '\0';
     }
-    if (function == 8 && device == 'V') {      /* PGetTokens */
-       outSizeMax = MAXPIOCTLTOKENLEN;
-       outData = osi_Alloc(outSizeMax);
+    if (code)
+       goto out;
+
+    if ((function == 8 && device == 'V') ||
+       (function == 7 && device == 'C')) {     /* PGetTokens */
+       code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
     } else {
-       outSizeMax = AFS_LRALLOCSIZ;
-       outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-    }
-    if (!outData) {
-       if (inSize > AFS_LRALLOCSIZ) {
-           osi_Free(inData, inSize + 1);
-       } else {
-           osi_FreeLargeSpace(inData);
-       }
-       afs_PutFakeStat(&fakestate);
-       return ENOMEM;
+       code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
     }
-    outSize = 0;
+    if (code)
+       goto out;
+
+    copyInput = input;
+    copyOutput = output;
+
     code =
-       (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
-                              &outSize, acred);
-    if (inSize > AFS_LRALLOCSIZ) {
-       osi_Free(inData, inSize + 1);
-    } else {
-       osi_FreeLargeSpace(inData);
-    }
+       (*pioctlSw[function]) (avc, function, &treq, &copyInput,
+                              &copyOutput, acred);
+
+    outSize = copyOutput.ptr - output.ptr;
+
     if (code == 0 && ablob->out_size > 0) {
        if (outSize > ablob->out_size) {
            code = E2BIG;       /* data wont fit in user buffer */
        } else if (outSize) {
-           AFS_COPYOUT(outData, ablob->out, outSize, code);
+           AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
        }
     }
-    if (outSizeMax > AFS_LRALLOCSIZ) {
-       osi_Free(outData, outSizeMax);
-    } else {
-       osi_FreeLargeSpace(outData);
-    }
+
+out:
+    afs_pd_free(&input);
+    afs_pd_free(&output);
+
     afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
 }
 
+/*!
+ * VIOCGETFID (22) - Get file ID quickly
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    fid of requested file
+ *
+ * \retval EINVAL      Error if some of the initial arguments aren't set
+ *
+ * \post get the file id of some file
+ */
 DECL_PIOCTL(PGetFID)
 {
     AFS_STATCNT(PGetFID);
     if (!avc)
        return EINVAL;
-    memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
-    *aoutSize = sizeof(struct VenusFid);
+    if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
+       return EINVAL;
+    return 0;
+}
+
+/*!
+ * VIOCSETAL (1) - Set access control list
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the ACL being set
+ * \param[out] aout    the ACL being set returned
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ *
+ * \post Changed ACL, via direct writing to the wire
+ */
+int
+dummy_PSetAcl(char *ain, char *aout)
+{
     return 0;
 }
 
 DECL_PIOCTL(PSetAcl)
 {
-    register afs_int32 code;
-    struct conn *tconn;
+    afs_int32 code;
+    struct afs_conn *tconn;
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
@@ -1186,70 +1440,105 @@ DECL_PIOCTL(PSetAcl)
     AFS_STATCNT(PSetAcl);
     if (!avc)
        return EINVAL;
-    if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1000)
+
+    if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
+       return EINVAL;
+    acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
+    if (acl.AFSOpaque_len > 1024)
        return EINVAL;
 
-    acl.AFSOpaque_val = ain;
     do {
-       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->fid.Fid,
+               RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
                               &acl, &OutStatus, &tsync);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
+            (tconn, 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->states &= ~(CStatd | CUnique);
+    avc->f.states &= ~(CStatd | CUnique);
     ReleaseWriteLock(&afs_xcbhash);
-    if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
+    if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
        osi_dnlc_purgedp(avc);
+
+    /* SXW - Should we flush metadata here? */
     return code;
 }
 
 int afs_defaultAsynchrony = 0;
 
+/*!
+ * VIOC_STOREBEHIND (47) Adjust store asynchrony
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \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)
 {
-    afs_int32 code = 0;
-    struct sbstruct *sbr;
+    struct sbstruct sbr;
+
+    if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
+       return EINVAL;
 
-    sbr = (struct sbstruct *)ain;
-    if (sbr->sb_default != -1) {
+    if (sbr.sb_default != -1) {
        if (afs_osi_suser(*acred))
-           afs_defaultAsynchrony = sbr->sb_default;
+           afs_defaultAsynchrony = sbr.sb_default;
        else
-           code = EPERM;
+           return EPERM;
     }
 
-    if (avc && (sbr->sb_thisfile != -1)) {
+    if (avc && (sbr.sb_thisfile != -1)) {
        if (afs_AccessOK
            (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
-           avc->asynchrony = sbr->sb_thisfile;
+           avc->asynchrony = sbr.sb_thisfile;
        else
-           code = EACCES;
+           return EACCES;
     }
 
-    *aoutSize = sizeof(struct sbstruct);
-    sbr = (struct sbstruct *)aout;
-    sbr->sb_default = afs_defaultAsynchrony;
+    memset(&sbr, 0, sizeof(sbr));
+    sbr.sb_default = afs_defaultAsynchrony;
     if (avc) {
-       sbr->sb_thisfile = avc->asynchrony;
+       sbr.sb_thisfile = avc->asynchrony;
     }
 
-    return code;
+    return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
 }
 
+/*!
+ * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EACCES      Error if the user doesn't have super-user credentials
+ *
+ * \post set the gcpags to GCPAGS_USERDISABLED
+ */
 DECL_PIOCTL(PGCPAGs)
 {
     if (!afs_osi_suser(*acred)) {
@@ -1259,23 +1548,42 @@ DECL_PIOCTL(PGCPAGs)
     return 0;
 }
 
+/*!
+ * VIOCGETAL (2) - Get access control list
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    the ACL
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval ERANGE      Error if the vnode of the file id is too large
+ * \retval -1          Error if getting the ACL failed
+ *
+ * \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 of the input size to judge what type of ACL it is,
+ *     only for dfs xlator ACLs
+ */
 DECL_PIOCTL(PGetAcl)
 {
     struct AFSOpaque acl;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
     afs_int32 code;
-    struct conn *tconn;
+    struct afs_conn *tconn;
     struct AFSFid Fid;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetAcl);
     if (!avc)
        return EINVAL;
-    Fid.Volume = avc->fid.Fid.Volume;
-    Fid.Vnode = avc->fid.Fid.Vnode;
-    Fid.Unique = avc->fid.Fid.Unique;
-    if (avc->states & CForeign) {
+    Fid.Volume = avc->f.fid.Fid.Volume;
+    Fid.Vnode = avc->f.fid.Fid.Vnode;
+    Fid.Unique = avc->f.fid.Fid.Unique;
+    if (avc->f.states & CForeign) {
        /*
         * For a dfs xlator acl we have a special hack so that the
         * xlator will distinguish which type of acl will return. So
@@ -1285,13 +1593,13 @@ DECL_PIOCTL(PGetAcl)
         */
        if (Fid.Vnode & 0xc0000000)
            return ERANGE;
-       Fid.Vnode |= (ainSize << 30);
+       Fid.Vnode |= (ain->remaining << 30);
     }
-    acl.AFSOpaque_val = aout;
+    acl.AFSOpaque_val = aout->ptr;
     do {
-       tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+       tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tconn) {
-           *aout = 0;
+           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);
@@ -1300,43 +1608,121 @@ DECL_PIOCTL(PGetAcl)
        } else
            code = -1;
     } while (afs_Analyze
-            (tconn, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
+            (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
              SHARED_LOCK, NULL));
 
     if (code == 0) {
-       *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
+       if (acl.AFSOpaque_len == 0)
+           afs_pd_skip(aout, 1); /* leave the NULL */
+       else
+           afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
     }
     return code;
 }
 
+/*!
+ * PNoop returns success.  Used for functions which are not implemented
+ * or are no longer in use.
+ *
+ * \ingroup pioctl
+ *
+ * \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)
 {
     AFS_STATCNT(PNoop);
     return 0;
 }
 
+/*!
+ * PBogus returns fail.  Used for functions which are not implemented or
+ * are no longer in use.
+ *
+ * \ingroup pioctl
+ *
+ * \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)
 {
     AFS_STATCNT(PBogus);
     return EINVAL;
 }
 
+/*!
+ * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use (avc used to pass in file id)
+ * \param[out] aout    cell name
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval ESRCH       Error if the file isn't part of a cell
+ *
+ * \post Get a cell based on a passed in file id
+ */
 DECL_PIOCTL(PGetFileCell)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
 
     AFS_STATCNT(PGetFileCell);
     if (!avc)
        return EINVAL;
-    tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
+    tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
     if (!tcell)
        return ESRCH;
-    strcpy(aout, tcell->cellName);
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
+
     afs_PutCell(tcell, READ_LOCK);
-    *aoutSize = strlen(aout) + 1;
     return 0;
 }
 
+/*!
+ * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \post Get the primary cell that the machine is a part of.
+ */
 DECL_PIOCTL(PGetWSCell)
 {
     struct cell *tcell = NULL;
@@ -1348,17 +1734,31 @@ DECL_PIOCTL(PGetWSCell)
     tcell = afs_GetPrimaryCell(READ_LOCK);
     if (!tcell)                        /* no primary cell? */
        return ESRCH;
-    strcpy(aout, tcell->cellName);
-    *aoutSize = strlen(aout) + 1;
+
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       return EINVAL;
     afs_PutCell(tcell, READ_LOCK);
     return 0;
 }
 
+/*!
+ * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \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 */
@@ -1380,25 +1780,86 @@ DECL_PIOCTL(PGetUserCell)
        if (!tcell)
            return ESRCH;
        else {
-           strcpy(aout, tcell->cellName);
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               return E2BIG;
            afs_PutCell(tcell, READ_LOCK);
-           *aoutSize = strlen(aout) + 1;       /* 1 for the null */
        }
     } else {
        ReleaseWriteLock(&afs_xuser);
-       *aout = 0;
-       *aoutSize = 1;
     }
     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 (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
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \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;
     afs_int32 flag, set_parent_pag = 0;
@@ -1407,76 +1868,66 @@ DECL_PIOCTL(PSetTokens)
     if (!afs_resourceinit_flag) {
        return EIO;
     }
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    stp = ain;                 /* remember where the ticket is */
-    if (i < 0 || i > MAXKTCTICKETLEN)
+
+    if (afs_pd_getInt(ain, &stLen) != 0)
+       return EINVAL;
+
+    stp = afs_pd_where(ain);   /* remember where the ticket is */
+    if (stLen < 0 || stLen > MAXKTCTICKETLEN)
        return EINVAL;          /* malloc may fail */
-    stLen = i;
-    ain += i;                  /* skip over ticket */
-    memcpy((char *)&i, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
-    if (i != sizeof(struct ClearToken)) {
+    if (afs_pd_skip(ain, stLen) != 0)
        return EINVAL;
-    }
-    memcpy((char *)&clear, ain, sizeof(struct ClearToken));
+
+    if (afs_pd_getInt(ain, &size) != 0)
+       return EINVAL;
+    if (size != sizeof(struct ClearToken))
+       return EINVAL;
+
+    if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
+       return EINVAL;
+
     if (clear.AuthHandle == -1)
        clear.AuthHandle = 999; /* more rxvab compat stuff */
-    ain += sizeof(struct ClearToken);
-    if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
-       /* still stuff left?  we've got primary flag and cell name.  Set these */
-       memcpy((char *)&flag, ain, sizeof(afs_int32));  /* primary id flag */
-       ain += sizeof(afs_int32);       /* skip id field */
-       /* rest is cell name, look it up */
-       /* some versions of gcc appear to need != 0 in order to get this right */
+
+    if (afs_pd_remaining(ain) != 0) {
+       /* 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 */
        if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
            flag &= ~0x8000;
            set_parent_pag = 1;
        }
-       tcell = afs_GetCellByName(ain, READ_LOCK);
-       if (!tcell)
-           goto nocell;
+
+       if (afs_pd_getStringPtr(ain, &cellName) != 0)
+           return EINVAL;
+
+       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_int32 pag;
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-#if defined(AFS_DARWIN_ENV)
-       struct proc *p = current_proc();        /* XXX */
-#else
-       struct proc *p = curproc;       /* XXX */
-#endif
-       uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
-               p->p_pid, p->p_comm);
-       if (!setpag(p, acred, -1, &pag, 1)) {
-#else
-#ifdef AFS_OSF_ENV
-       if (!setpag(u.u_procp, acred, -1, &pag, 1)) {   /* XXX u.u_procp is a no-op XXX */
-#else
-       if (!setpag(acred, -1, &pag, 1)) {
-#endif
-#endif
+       if (_settok_setParentPag(acred) == 0) {
            afs_InitReq(&treq, *acred);
            areq = &treq;
        }
     }
+
     /* now we just set the tokens */
-    tu = afs_GetUser(areq->uid, i, WRITE_LOCK);        /* i has the cell # */
-    tu->vid = clear.ViceId;
-    if (tu->stp != NULL) {
-       afs_osi_Free(tu->stp, tu->stLen);
-    }
-    tu->stp = (char *)afs_osi_Alloc(stLen);
-    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();
@@ -1486,31 +1937,35 @@ DECL_PIOCTL(PSetTokens)
     afs_SetPrimary(tu, flag);
     tu->tokenTime = osi_Time();
     afs_ResetUserConns(tu);
+    afs_NotifyUser(tu, UTokensObtained);
     afs_PutUser(tu, WRITE_LOCK);
 
     return 0;
-
-  nocell:
-    {
-       int t1;
-       t1 = afs_initState;
-       if (t1 < 101)
-           return EIO;
-       else
-           return ESRCH;
-    }
 }
 
+/*!
+ * VIOCGETVOLSTAT (4) - Get volume status
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    status of the volume
+ *
+ * \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
+ */
 DECL_PIOCTL(PGetVolumeStatus)
 {
     char volName[32];
     char *offLineMsg = afs_osi_Alloc(256);
     char *motd = afs_osi_Alloc(256);
-    register struct conn *tc;
-    register afs_int32 code = 0;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
-    register char *cp;
-    char *Name, *OfflineMsg, *MOTD;
+    char *Name;
     XSTATS_DECLS;
 
     AFS_STATCNT(PGetVolumeStatus);
@@ -1519,95 +1974,110 @@ DECL_PIOCTL(PGetVolumeStatus)
        goto out;
     }
     Name = volName;
-    OfflineMsg = offLineMsg;
-    MOTD = motd;
     do {
-       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
-                                     &Name, &OfflineMsg, &MOTD);
+               RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
+                                     &Name, &offLineMsg, &motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
+            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
              SHARED_LOCK, NULL));
 
     if (code)
        goto out;
     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = (cp - aout);
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, volName) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return E2BIG;
+    if (afs_pd_putString(aout, motd) != 0)
+       return E2BIG;
   out:
     afs_osi_Free(offLineMsg, 256);
     afs_osi_Free(motd, 256);
     return code;
 }
 
+/*!
+ * VIOCSETVOLSTAT (5) - Set volume status
+ *
+ * \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
+ */
 DECL_PIOCTL(PSetVolumeStatus)
 {
-    char volName[32];
-    char *offLineMsg = afs_osi_Alloc(256);
-    char *motd = afs_osi_Alloc(256);
-    register struct conn *tc;
-    register afs_int32 code = 0;
+    char *volName;
+    char *offLineMsg;
+    char *motd;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     struct AFSFetchVolumeStatus volstat;
     struct AFSStoreVolumeStatus storeStat;
-    register struct volume *tvp;
-    register char *cp;
+    struct volume *tvp;
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
-    if (!avc) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!avc)
+       return EINVAL;
 
-    tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
+    tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
        if (tvp->states & (VRO | VBackup)) {
            afs_PutVolume(tvp, READ_LOCK);
-           code = EROFS;
-           goto out;
+           return EROFS;
        }
        afs_PutVolume(tvp, READ_LOCK);
-    } else {
-       code = ENODEV;
-       goto out;
-    }
-    /* Copy the junk out, using cp as a roving pointer. */
-    cp = ain;
-    memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
-    cp += sizeof(AFSFetchVolumeStatus);
-    if (strlen(cp) >= sizeof(volName)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(volName, cp);
-    cp += strlen(volName) + 1;
-    if (strlen(cp) >= sizeof(offLineMsg)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(offLineMsg, cp);
-    cp += strlen(offLineMsg) + 1;
-    if (strlen(cp) >= sizeof(motd)) {
-       code = E2BIG;
-       goto out;
-    }
-    strcpy(motd, cp);
+    } else
+       return ENODEV;
+
+
+    if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &volName) != 0)
+       return EINVAL;
+    if (strlen(volName) > 32)
+        return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
+       return EINVAL;
+    if (strlen(offLineMsg) > 256)
+       return E2BIG;
+
+    if (afs_pd_getStringPtr(ain, &motd) != 0)
+       return EINVAL;
+    if (strlen(motd) > 256)
+       return E2BIG;
+
+    /* Done reading ... */
+
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
        storeStat.MinQuota = volstat.MinQuota;
@@ -1618,41 +2088,51 @@ DECL_PIOCTL(PSetVolumeStatus)
        storeStat.Mask |= AFS_SETMAXQUOTA;
     }
     do {
-       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume, &storeStat,
+               RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
                                      volName, offLineMsg, motd);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
+            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
              SHARED_LOCK, NULL));
 
     if (code)
-       goto out;
+       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 */
-    cp = aout;
-    memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
-    cp += sizeof(VolumeStatus);
-    strcpy(cp, volName);
-    cp += strlen(volName) + 1;
-    strcpy(cp, offLineMsg);
-    cp += strlen(offLineMsg) + 1;
-    strcpy(cp, motd);
-    cp += strlen(motd) + 1;
-    *aoutSize = cp - aout;
-  out:
-    afs_osi_Free(offLineMsg, 256);
-    afs_osi_Free(motd, 256);
+     * change interface later to not ask for current status, just set new
+     * status */
+
+    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, volName) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, offLineMsg) != 0)
+       return EINVAL;
+    if (afs_pd_putString(aout, motd) != 0)
+       return EINVAL;
+
     return code;
 }
 
+/*!
+ * VIOCFLUSH (6) - Invalidate cache entry
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ *
+ * \post Flush any information the cache manager has on an entry
+ */
 DECL_PIOCTL(PFlush)
 {
     AFS_STATCNT(PFlush);
@@ -1662,17 +2142,7 @@ DECL_PIOCTL(PFlush)
     afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
     ObtainWriteLock(&avc->lock, 225);
-    ObtainWriteLock(&afs_xcbhash, 456);
-    afs_DequeueCallback(avc);
-    avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
-    ReleaseWriteLock(&afs_xcbhash);
-    /* now find the disk cache entries */
-    afs_TryToSmush(avc, *acred, 1);
-    osi_dnlc_purgedp(avc);
-    if (avc->linkData && !(avc->states & CCore)) {
-       afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
-       avc->linkData = NULL;
-    }
+    afs_ResetVCache(avc, *acred);
     ReleaseWriteLock(&avc->lock);
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonUnlock(&avc->pvnLock, avc);
@@ -1680,19 +2150,41 @@ DECL_PIOCTL(PFlush)
     return 0;
 }
 
+/*!
+ * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
+ *
+ * \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
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval ENOTDIR     Error if the 'mount point' argument isn't a directory
+ * \retval EIO         Error if the link data can't be accessed
+ *
+ * \post Get the volume, and cell, as well as the link data for a mount point
+ */
 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;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PNewStatMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -1702,7 +2194,7 @@ DECL_PIOCTL(PNewStatMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -1713,9 +2205,9 @@ DECL_PIOCTL(PNewStatMount)
     if (code) {
        goto out;
     }
-    tfid.Cell = avc->fid.Cell;
-    tfid.Fid.Volume = avc->fid.Fid.Volume;
-    if (!tfid.Fid.Unique && (avc->states & CForeign)) {
+    tfid.Cell = avc->f.fid.Cell;
+    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
+    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
     } else {
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
@@ -1737,8 +2229,8 @@ DECL_PIOCTL(PNewStatMount)
                code = EINVAL;
            else {
                /* we have the data */
-               strcpy(aout, tvc->linkData);
-               *aoutSize = strlen(tvc->linkData) + 1;
+               if (afs_pd_putString(aout, tvc->linkData) != 0)
+                   code = EINVAL;
            }
        } else
            code = EIO;
@@ -1751,14 +2243,67 @@ DECL_PIOCTL(PNewStatMount)
     return code;
 }
 
+/*!
+ * 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);
+
+    return tu;
+}
+/*!
+ * VIOCGETTOK (8) - Get authentication tokens
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \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;
-    register char *cp;
-    afs_int32 iterator;
+    struct cell *tcell;
+    struct unixuser *tu = NULL;
+    union tokenUnion *token;
+    afs_int32 iterator = 0;
     int newStyle;
+    int cellNum;
+    int code = E2BIG;
 
     AFS_STATCNT(PGetTokens);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -1773,75 +2318,92 @@ DECL_PIOCTL(PGetTokens)
      * tokens, the primary cell indicator (an afs_int32 0) and the cell name
      * at the end, in that order.
      */
-    if ((newStyle = (ainSize > 0))) {
-       memcpy((char *)&iterator, ain, sizeof(afs_int32));
-    }
-    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;
-       }
+    newStyle = (afs_pd_remaining(ain) > 0);
+    if (newStyle) {
+       if (afs_pd_getInt(ain, &iterator) != 0)
+           return EINVAL;
     }
-    if (tu) {
-       /*
-        * No need to hold a read lock on each user entry
-        */
-       tu->refCount++;
+    if (newStyle) {
+       tu = getNthCell(areq->uid, iterator);
+    } else {
+       cellNum = afs_GetPrimaryCellNum();
+       if (cellNum)
+           tu = afs_FindUser(areq->uid, cellNum, READ_LOCK);
     }
-    ReleaseReadLock(&afs_xuser);
-
     if (!tu) {
        return EDOM;
     }
-    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;
     }
-    /* use iterator for temp */
-    cp = aout;
-    iterator = tu->stLen;      /* for compat, we try to return 56 byte tix if they fit */
+    token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
+
+    /* 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 */
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, tu->stp, tu->stLen);    /* copy out st */
-    cp += iterator;
-    iterator = sizeof(struct ClearToken);
-    memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-    cp += sizeof(afs_int32);
-    memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
-    cp += sizeof(struct ClearToken);
+
+    if (afs_pd_putInt(aout, iterator) != 0)
+       goto out;
+    if (afs_pd_putBytes(aout, token->rxkad.ticket, token->rxkad.ticketLen) != 0)
+       goto out;
+    if (token->rxkad.ticketLen < 56) {
+       /* Tokens are always 56 bytes or larger */
+       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, &token->rxkad.clearToken,
+                       sizeof(struct ClearToken)) != 0)
+       goto out;
+
     if (newStyle) {
        /* put out primary id and cell name, too */
        iterator = (tu->states & UPrimary ? 1 : 0);
-       memcpy(cp, (char *)&iterator, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, iterator) != 0)
+           goto out;
        tcell = afs_GetCell(tu->cell, READ_LOCK);
        if (tcell) {
-           strcpy(cp, tcell->cellName);
-           cp += strlen(tcell->cellName) + 1;
+           if (afs_pd_putString(aout, tcell->cellName) != 0)
+               goto out;
            afs_PutCell(tcell, READ_LOCK);
        } else
-           *cp++ = 0;
+           if (afs_pd_putString(aout, "") != 0)
+               goto out;
     }
-    *aoutSize = cp - aout;
+    /* Got here, all is good */
+    code = 0;
+out:
     afs_PutUser(tu, READ_LOCK);
-    return 0;
+    return code;
 }
 
+/*!
+ * VIOCUNLOG (9) - Invalidate tokens
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EIO Error if the afs daemon hasn't been started yet
+ *
+ * \post remove tokens from a user, specified by the user id
+ *
+ * \notes sets the token's time to 0, which then causes it to be removed
+ * \notes Unlog is the same as un-pag in OpenAFS
+ */
 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 */
@@ -1851,19 +2413,18 @@ 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((char *)&tu->ct, 0, sizeof(struct ClearToken));
+           afs_FreeTokens(&tu->tokens);
            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_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--;
@@ -1872,7 +2433,6 @@ DECL_PIOCTL(PUnlog)
            /* set the expire times to 0, causes
             * afs_GCUserData to remove this entry
             */
-           tu->ct.EndTimestamp = 0;
            tu->tokenTime = 0;
 #endif /* UKERNEL */
        }
@@ -1881,6 +2441,21 @@ DECL_PIOCTL(PUnlog)
     return 0;
 }
 
+/*!
+ * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \notes Errors turn off mariner
+ */
 DECL_PIOCTL(PMariner)
 {
     afs_int32 newHostAddr;
@@ -1893,7 +2468,9 @@ DECL_PIOCTL(PMariner)
     else
        oldHostAddr = 0xffffffff;       /* disabled */
 
-    memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newHostAddr) != 0)
+       return EINVAL;
+
     if (newHostAddr == 0xffffffff) {
        /* disable mariner operations */
        afs_mariner = 0;
@@ -1901,17 +2478,35 @@ DECL_PIOCTL(PMariner)
        afs_mariner = 1;
        afs_marinerHost = newHostAddr;
     }
-    memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+
+    if (afs_pd_putInt(aout, oldHostAddr) != 0)
+       return E2BIG;
+
     return 0;
 }
 
+/*!
+ * VIOCCKSERV (10) - Check that servers are up
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      name of the cell
+ * \param[out] aout    current down server list
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \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)
+ */
 DECL_PIOCTL(PCheckServers)
 {
-    register char *cp = 0;
-    register int i;
-    register struct server *ts;
-    afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
+    int i;
+    struct server *ts;
+    afs_int32 temp;
+    char *cellName = NULL;
     struct cell *cellp;
     struct chservinfo *pcheck;
 
@@ -1920,37 +2515,47 @@ DECL_PIOCTL(PCheckServers)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (*lp == 0x12345678) {   /* For afs3.3 version */
-       pcheck = (struct chservinfo *)ain;
+    /* This is tricky, because we need to peak at the datastream to see
+     * what we're getting. For now, let's cheat. */
+
+    /* ain contains either an int32 or a string */
+    if (ain->remaining == 0)
+       return EINVAL;
+
+    if (*(afs_int32 *)ain->ptr == 0x12345678) {        /* For afs3.3 version */
+       pcheck = afs_pd_inline(ain, sizeof(*pcheck));
+        if (pcheck == NULL)
+           return EINVAL;
+
        if (pcheck->tinterval >= 0) {
-           cp = aout;
-           memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, afs_probe_interval) != 0)
+               return E2BIG;
            if (pcheck->tinterval > 0) {
                if (!afs_osi_suser(*acred))
                    return EACCES;
-               PROBE_INTERVAL = pcheck->tinterval;
+               afs_probe_interval = pcheck->tinterval;
            }
            return 0;
        }
-       if (pcheck->tsize)
-           havecell = 1;
        temp = pcheck->tflags;
-       cp = pcheck->tbuffer;
+       if (pcheck->tsize)
+           cellName = pcheck->tbuffer;
     } else {                   /* For pre afs3.3 versions */
-       memcpy((char *)&temp, ain, sizeof(afs_int32));
-       cp = ain + sizeof(afs_int32);
-       if (ainSize > sizeof(afs_int32))
-           havecell = 1;
+       if (afs_pd_getInt(ain, &temp) != 0)
+           return EINVAL;
+       if (afs_pd_remaining(ain) > 0) {
+           if (afs_pd_getStringPtr(ain, &cellName) != 0)
+               return EINVAL;
+       }
     }
 
     /*
      * 1: fast check, don't contact servers.
      * 2: local cell only.
      */
-    if (havecell) {
+    if (cellName) {
        /* have cell name, too */
-       cellp = afs_GetCellByName(cp, READ_LOCK);
+       cellp = afs_GetCellByName(cellName, READ_LOCK);
        if (!cellp)
            return ENOENT;
     } else
@@ -1964,7 +2569,6 @@ DECL_PIOCTL(PCheckServers)
        afs_CheckServers(0, cellp);     /* check up servers */
     }
     /* now return the current down server list */
-    cp = aout;
     ObtainReadLock(&afs_xserver);
     for (i = 0; i < NSERVERS; i++) {
        for (ts = afs_servers[i]; ts; ts = ts->next) {
@@ -1972,18 +2576,31 @@ DECL_PIOCTL(PCheckServers)
                continue;       /* cell spec'd and wrong */
            if ((ts->flags & SRVR_ISDOWN)
                && ts->addr->sa_portal != ts->cell->vlport) {
-               memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-               cp += sizeof(afs_int32);
+               afs_pd_putInt(aout, ts->addr->sa_ip);
            }
        }
     }
     ReleaseReadLock(&afs_xserver);
     if (cellp)
        afs_PutCell(cellp, READ_LOCK);
-    *aoutSize = cp - aout;
     return 0;
 }
 
+/*!
+ * VIOCCKBACK (11) - Check backup volume mappings
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \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
+ */
 DECL_PIOCTL(PCheckVolNames)
 {
     AFS_STATCNT(PCheckVolNames);
@@ -1996,11 +2613,29 @@ DECL_PIOCTL(PCheckVolNames)
     return 0;
 }
 
+/*!
+ * VIOCCKCONN (12) - Check connections for a user
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \post
+ *     check to see if a user has the correct authentication.
+ *     If so, allow access.
+ *
+ * \notes Check the connections to all the servers specified
+ */
 DECL_PIOCTL(PCheckAuth)
 {
     int i;
     struct srvAddr *sa;
-    struct conn *tc;
+    struct afs_conn *tc;
     struct unixuser *tu;
     afs_int32 retValue;
 
@@ -2033,17 +2668,17 @@ DECL_PIOCTL(PCheckAuth)
        ReleaseReadLock(&afs_xconn);
        afs_PutUser(tu, READ_LOCK);
     }
-    memcpy(aout, (char *)&retValue, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
+    if (afs_pd_putInt(aout, retValue) != 0)
+       return E2BIG;
     return 0;
 }
 
 static int
-Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
-        struct AFS_UCRED *acred)
+Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
+        afs_ucred_t *acred)
 {
-    register char *tp;
-    register afs_int32 code;
+    char *tp;
+    afs_int32 code;
 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     size_t bufferSize;
 #else
@@ -2064,55 +2699,89 @@ Prefetch(char *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;
 }
 
+/*!
+ * VIOCWHEREIS (14) - Find out where a volume is located
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    volume location
+ *
+ * \retval EINVAL      Error if some of the default arguments don't exist
+ * \retval ENODEV      Error if there is no such volume
+ *
+ * \post fine a volume, based on a volume file id
+ *
+ * \notes check each of the servers specified
+ */
 DECL_PIOCTL(PFindVolume)
 {
-    register struct volume *tvp;
-    register struct server *ts;
-    register afs_int32 i;
-    register char *cp;
+    struct volume *tvp;
+    struct server *ts;
+    afs_int32 i;
+    int code = 0;
 
     AFS_STATCNT(PFindVolume);
     if (!avc)
        return EINVAL;
-    tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
-    if (tvp) {
-       cp = aout;
-       for (i = 0; i < MAXHOSTS; i++) {
-           ts = tvp->serverHost[i];
-           if (!ts)
-               break;
-           memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
+    if (!tvp)
+       return ENODEV;
+
+    for (i = 0; i < AFS_MAXHOSTS; i++) {
+       ts = tvp->serverHost[i];
+       if (!ts)
+           break;
+       if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       if (i < MAXHOSTS) {
-           /* still room for terminating NULL, add it on */
-           ainSize = 0;        /* reuse vbl */
-           memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
-           cp += sizeof(afs_int32);
+    }
+    if (i < AFS_MAXHOSTS) {
+       /* still room for terminating NULL, add it on */
+       if (afs_pd_putInt(aout, 0) != 0) {
+           code = E2BIG;
+           goto out;
        }
-       *aoutSize = cp - aout;
-       afs_PutVolume(tvp, READ_LOCK);
-       return 0;
     }
-    return ENODEV;
+out:
+    afs_PutVolume(tvp, READ_LOCK);
+    return code;
 }
 
+/*!
+ * VIOCACCESS (20) - Access using PRS_FS bits
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      PRS_FS bits
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the initial arguments aren't set
+ * \retval EACCES      Error if access is denied
+ *
+ * \post check to make sure access is allowed
+ */
 DECL_PIOCTL(PViceAccess)
 {
-    register afs_int32 code;
+    afs_int32 code;
     afs_int32 temp;
 
     AFS_STATCNT(PViceAccess);
     if (!avc)
        return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
+
+    if (afs_pd_getInt(ain, &temp) != 0)
+       return EINVAL;
+
     code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
     if (code)
        return 0;
@@ -2120,18 +2789,72 @@ DECL_PIOCTL(PViceAccess)
        return EACCES;
 }
 
+/*!
+ * VIOC_GETPAG (13) - Get PAG value
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    PAG value or NOPAG
+ *
+ * \post get PAG value for the caller's cred
+ */
+DECL_PIOCTL(PGetPAG)
+{
+    afs_int32 pag;
+
+    pag = PagInCred(*acred);
+
+    return afs_pd_putInt(aout, pag);
+}
+
+DECL_PIOCTL(PPrecache)
+{
+    afs_int32 newValue;
+
+    /*AFS_STATCNT(PPrecache);*/
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
+
+    afs_preCache = newValue*1024;
+    return 0;
+}
+
+/*!
+ * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the size the venus cache should be set to
+ * \param[out] aout    not in use
+ *
+ * \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.
+ *
+ * \notes
+ *     recompute the general cache parameters for every single block allocated
+ */
 DECL_PIOCTL(PSetCacheSize)
 {
     afs_int32 newValue;
     int waitcnt = 0;
 
     AFS_STATCNT(PSetCacheSize);
+
     if (!afs_osi_suser(*acred))
        return EACCES;
     /* too many things are setup initially in mem cache version */
     if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
        return EROFS;
-    memcpy((char *)&newValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &newValue) != 0)
+       return EINVAL;
     if (newValue == 0)
        afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
     else {
@@ -2151,23 +2874,87 @@ DECL_PIOCTL(PSetCacheSize)
 }
 
 #define MAXGCSTATS     16
+/*!
+ * VIOCGETCACHEPARMS (40) - Get cache stats
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      afs index flags
+ * \param[out] aout    cache blocks, blocks used, blocks files (in an array)
+ *
+ * \post Get the cache blocks, and how many of the cache blocks there are
+ */
 DECL_PIOCTL(PGetCacheSize)
 {
     afs_int32 results[MAXGCSTATS];
+    afs_int32 flags;
+    struct dcache * tdc;
+    int i, size;
 
     AFS_STATCNT(PGetCacheSize);
-    memset((char *)results, 0, sizeof(results));
+
+    if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
+       afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
+    } else if (afs_pd_remaining(ain) == 0) {
+       flags = 0;
+    } else {
+       return EINVAL;
+    }
+
+    memset(results, 0, sizeof(results));
     results[0] = afs_cacheBlocks;
     results[1] = afs_blocksUsed;
-    memcpy(aout, (char *)results, sizeof(results));
-    *aoutSize = sizeof(results);
-    return 0;
+    results[2] = afs_cacheFiles;
+
+    if (1 == flags){
+        for (i = 0; i < afs_cacheFiles; i++) {
+           if (afs_indexFlags[i] & IFFree) results[3]++;
+       }
+    } else if (2 == flags){
+        for (i = 0; i < afs_cacheFiles; i++) {
+           if (afs_indexFlags[i] & IFFree) results[3]++;
+           if (afs_indexFlags[i] & IFEverUsed) results[4]++;
+           if (afs_indexFlags[i] & IFDataMod) results[5]++;
+           if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
+           if (afs_indexFlags[i] & IFAnyPages) results[7]++;
+           if (afs_indexFlags[i] & IFDiscarded) results[8]++;
+
+           tdc = afs_indexTable[i];
+           if (tdc){
+               results[9]++;
+               size = tdc->validPos;
+               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]++;
+               else if (size < (1<<20) ) results[14]++;
+               else if (size >= (1<<20) ) results[15]++;
+           }
+        }
+    }
+    return afs_pd_putBytes(aout, results, sizeof(results));
 }
 
+/*!
+ * VIOCFLUSHCB (25) - Flush callback only
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval 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.
+ */
 DECL_PIOCTL(PRemoveCallBack)
 {
-    register struct 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;
@@ -2176,17 +2963,17 @@ DECL_PIOCTL(PRemoveCallBack)
     AFS_STATCNT(PRemoveCallBack);
     if (!avc)
        return EINVAL;
-    if (avc->states & CRO)
+    if (avc->f.states & CRO)
        return 0;               /* read-only-ness can't change */
     ObtainWriteLock(&avc->lock, 229);
     theFids.AFSCBFids_len = 1;
     theCBs.AFSCBs_len = 1;
-    theFids.AFSCBFids_val = (struct AFSFid *)&avc->fid.Fid;
+    theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
     theCBs.AFSCBs_val = CallBacks_Array;
     CallBacks_Array[0].CallBackType = CB_DROPPED;
     if (avc->callback) {
        do {
-           tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+           tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
            if (tc) {
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
                RX_AFS_GUNLOCK();
@@ -2196,29 +2983,48 @@ DECL_PIOCTL(PRemoveCallBack)
            }
            /* don't set code on failure since we wouldn't use it */
        } while (afs_Analyze
-                (tc, code, &avc->fid, areq,
+                (tc, code, &avc->f.fid, areq,
                  AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
 
        ObtainWriteLock(&afs_xcbhash, 457);
        afs_DequeueCallback(avc);
        avc->callback = 0;
-       avc->states &= ~(CStatd | CUnique);
+       avc->f.states &= ~(CStatd | CUnique);
        ReleaseWriteLock(&afs_xcbhash);
-       if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
+       if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
            osi_dnlc_purgedp(avc);
     }
     ReleaseWriteLock(&avc->lock);
     return 0;
 }
 
+/*!
+ * VIOCNEWCELL (26) - Configure new cell
+ *
+ * \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
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \retval EACCES      Error if the user doesn't have super-user cedentials
+ * \retval EINVAL      Error if some 'magic' var doesn't have a certain bit set
+ *
+ * \post creates a new cell
+ */
 DECL_PIOCTL(PNewCell)
 {
-    /* create a new cell */
-    afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
-    char *newcell = 0, *linkedcell = 0, *tp = ain;
-    register afs_int32 code, linkedstate = 0, ls;
-    u_short fsport = 0, vlport = 0;
-    afs_int32 scount;
+    afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
+    char *newcell = NULL;
+    char *linkedcell = NULL;
+    afs_int32 code, ls;
+    afs_int32 linkedstate = 0;
+    afs_int32 fsport = 0, vlport = 0;
+    int skip;
 
     AFS_STATCNT(PNewCell);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2227,34 +3033,55 @@ DECL_PIOCTL(PNewCell)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    memcpy((char *)&magic, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &magic) != 0)
+       return EINVAL;
     if (magic != 0x12345678)
        return EINVAL;
 
-    /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
+    /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
      * server addresses while the 3.5 fs newcell command passes
-     * MAXHOSTS. To figure out which is which, check if the cellname
+     * AFS_MAXHOSTS. To figure out which is which, check if the cellname
      * is good.
+     *
+     * This whole logic is bogus, because it relies on the newer command
+     * sending its 12th address as 0.
      */
-    newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
-    scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
+    if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
+       return EINVAL;
 
-    /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
-    memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
-    tp += (scount * sizeof(afs_int32));
+    newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
+    if (newcell[0] != '\0') {
+       skip = 0;
+    } else {
+       skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
+    }
+
+    /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
+    if (afs_pd_getBytes(ain, &cellHosts,
+                       AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
+       return EINVAL;
+    if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
+       return EINVAL;
 
-    lp = (afs_int32 *) tp;
-    fsport = *lp++;
-    vlport = *lp++;
+    if (afs_pd_getInt(ain, &fsport) != 0)
+       return EINVAL;
     if (fsport < 1024)
        fsport = 0;             /* Privileged ports not allowed */
+
+    if (afs_pd_getInt(ain, &vlport) != 0)
+       return EINVAL;
     if (vlport < 1024)
        vlport = 0;             /* Privileged ports not allowed */
-    tp += (3 * sizeof(afs_int32));
-    newcell = tp;
-    if ((ls = *lp) & 1) {
-       linkedcell = tp + strlen(newcell) + 1;
+
+    if (afs_pd_getInt(ain, &ls) != 0)
+       return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &newcell) != 0)
+       return EINVAL;
+
+    if (ls & 1) {
+       if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
+           return EINVAL;
        linkedstate |= CLinkedCell;
     }
 
@@ -2268,8 +3095,6 @@ DECL_PIOCTL(PNewCell)
 DECL_PIOCTL(PNewAlias)
 {
     /* create a new cell alias */
-    char *tp = ain;
-    register afs_int32 code;
     char *realName, *aliasName;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2278,101 +3103,137 @@ DECL_PIOCTL(PNewAlias)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    aliasName = tp;
-    tp += strlen(aliasName) + 1;
-    realName = tp;
+    if (afs_pd_getStringPtr(ain, &aliasName) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &realName) != 0)
+       return EINVAL;
 
-    code = afs_NewCellAlias(aliasName, realName);
-    *aoutSize = 0;
-    return code;
+    return afs_NewCellAlias(aliasName, realName);
 }
 
+/*!
+ * VIOCGETCELL (27) - Get cell info
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      The cell index of a specific cell
+ * \param[out] aout    list of servers in the cell
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \retval EDOM                Error if there is no cell asked about
+ *
+ * \post Lists the cell's server names and and addresses
+ */
 DECL_PIOCTL(PListCells)
 {
     afs_int32 whichCell;
-    register struct cell *tcell = 0;
-    register afs_int32 i;
-    register char *cp, *tp = ain;
+    struct cell *tcell = 0;
+    afs_int32 i;
+    int code;
 
     AFS_STATCNT(PListCells);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    memcpy((char *)&whichCell, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichCell) != 0)
+       return EINVAL;
+
     tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
-    if (tcell) {
-       cp = aout;
-       memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
-       for (i = 0; i < MAXCELLHOSTS; i++) {
-           if (tcell->cellHosts[i] == 0)
-               break;
-           memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
-                  sizeof(afs_int32));
-           cp += sizeof(afs_int32);
-       }
-       cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
-       strcpy(cp, tcell->cellName);
-       cp += strlen(tcell->cellName) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCell(tcell, READ_LOCK);
-    }
-    if (tcell)
-       return 0;
-    else
+    if (!tcell)
        return EDOM;
+
+    code = E2BIG;
+
+    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
+       if (tcell->cellHosts[i] == 0)
+           break;
+       if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
+           goto out;
+    }
+    for (;i < AFS_MAXCELLHOSTS; i++) {
+       if (afs_pd_putInt(aout, 0) != 0)
+           goto out;
+    }
+    if (afs_pd_putString(aout, tcell->cellName) != 0)
+       goto out;
+    code = 0;
+
+out:
+    afs_PutCell(tcell, READ_LOCK);
+    return code;
 }
 
 DECL_PIOCTL(PListAliases)
 {
     afs_int32 whichAlias;
-    register struct cell_alias *tcalias = 0;
-    register char *cp, *tp = ain;
+    struct cell_alias *tcalias = 0;
+    int code;
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
-    if (ainSize < sizeof(afs_int32))
-       return EINVAL;
 
-    memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
-    tp += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &whichAlias) != 0)
+       return EINVAL;
 
     tcalias = afs_GetCellAlias(whichAlias);
-    if (tcalias) {
-       cp = aout;
-       strcpy(cp, tcalias->alias);
-       cp += strlen(tcalias->alias) + 1;
-       strcpy(cp, tcalias->cell);
-       cp += strlen(tcalias->cell) + 1;
-       *aoutSize = cp - aout;
-       afs_PutCellAlias(tcalias);
-    }
-    if (tcalias)
-       return 0;
-    else
+    if (tcalias == NULL)
        return EDOM;
+
+    code = E2BIG;
+    if (afs_pd_putString(aout, tcalias->alias) != 0)
+       goto out;
+    if (afs_pd_putString(aout, tcalias->cell) != 0)
+       goto out;
+
+    code = 0;
+out:
+    afs_PutCellAlias(tcalias);
+    return code;
 }
 
+/*!
+ * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
+ *
+ * \ingroup pioctl
+ *
+ * \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.
+ */
 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 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;
     XSTATS_DECLS;
 
-
     /* "ain" is the name of the file in this dir to remove */
 
     AFS_STATCNT(PRemoveMount);
     if (!avc)
        return EINVAL;
+    if (afs_pd_getStringPtr(ain, &name) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -2382,7 +3243,7 @@ DECL_PIOCTL(PRemoveMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);  /* test for error below */
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, name, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -2393,9 +3254,9 @@ DECL_PIOCTL(PRemoveMount)
        afs_PutDCache(tdc);
        goto out;
     }
-    tfid.Cell = avc->fid.Cell;
-    tfid.Fid.Volume = avc->fid.Fid.Volume;
-    if (!tfid.Fid.Unique && (avc->states & CForeign)) {
+    tfid.Cell = avc->f.fid.Cell;
+    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
+    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
     } else {
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
@@ -2430,19 +3291,19 @@ DECL_PIOCTL(PRemoveMount)
     ObtainWriteLock(&avc->lock, 231);
     osi_dnlc_remove(avc, bufp, tvc);
     do {
-       tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
        if (tc) {
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
            RX_AFS_GUNLOCK();
            code =
-               RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->fid.Fid, bufp,
+               RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
                                 &OutDirStatus, &tsync);
            RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &avc->fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
+            (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
              SHARED_LOCK, NULL));
 
     if (code) {
@@ -2465,7 +3326,7 @@ DECL_PIOCTL(PRemoveMount)
        ReleaseWriteLock(&tdc->lock);
        afs_PutDCache(tdc);     /* drop ref count */
     }
-    avc->states &= ~CUnique;   /* For the dfs xlator */
+    avc->f.states &= ~CUnique; /* For the dfs xlator */
     ReleaseWriteLock(&avc->lock);
     code = 0;
   out:
@@ -2474,45 +3335,81 @@ DECL_PIOCTL(PRemoveMount)
     return code;
 }
 
-DECL_PIOCTL(PVenusLogging)
-{
-    return EINVAL;             /* OBSOLETE */
-}
-
+/*!
+ * VIOC_GETCELLSTATUS (35) - Get cell status info
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      The cell you want status information on
+ * \param[out] aout    cell state (as a struct)
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \retval ENOENT      Error if the cell doesn't exist
+ *
+ * \post Returns the state of the cell as defined in a struct cell
+ */
 DECL_PIOCTL(PGetCellStatus)
 {
-    register struct cell *tcell;
+    struct cell *tcell;
+    char *cellName;
     afs_int32 temp;
 
     AFS_STATCNT(PGetCellStatus);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain, READ_LOCK);
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, READ_LOCK);
     if (!tcell)
        return ENOENT;
     temp = tcell->states;
     afs_PutCell(tcell, READ_LOCK);
-    memcpy(aout, (char *)&temp, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+
+    return afs_pd_putInt(aout, temp);
 }
 
+/*!
+ * VIOC_SETCELLSTATUS (36) - Set corresponding info
+ *
+ * \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
+ *
+ * \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
+ */
 DECL_PIOCTL(PSetCellStatus)
 {
-    register struct cell *tcell;
-    afs_int32 temp;
+    struct cell *tcell;
+    char *cellName;
+    afs_int32 flags0, flags1;
 
     if (!afs_osi_suser(*acred))
        return EACCES;
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
+    if (afs_pd_getInt(ain, &flags0) != 0)
+       return EINVAL;
+    if (afs_pd_getInt(ain, &flags1) != 0)
+       return EINVAL;
+    if (afs_pd_getStringPtr(ain, &cellName) != 0)
+       return EINVAL;
+
+    tcell = afs_GetCellByName(cellName, WRITE_LOCK);
     if (!tcell)
        return ENOENT;
-    memcpy((char *)&temp, ain, sizeof(afs_int32));
-    if (temp & CNoSUID)
+    if (flags0 & CNoSUID)
        tcell->states |= CNoSUID;
     else
        tcell->states &= ~CNoSUID;
@@ -2520,13 +3417,37 @@ DECL_PIOCTL(PSetCellStatus)
     return 0;
 }
 
+/*!
+ * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use (args in avc)
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ *
+ * \post
+ *     Flush all cached contents of a volume.  Exactly what stays and what
+ *     goes depends on the platform.
+ *
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
+ */
 DECL_PIOCTL(PFlushVolumeData)
 {
-    register afs_int32 i;
-    register struct dcache *tdc;
-    register struct vcache *tvc;
-    register struct volume *tv;
+    afs_int32 i;
+    struct dcache *tdc;
+    struct vcache *tvc;
+    struct volume *tv;
     afs_int32 cell, volume;
+    struct afs_q *tq, *uq;
+#ifdef AFS_DARWIN80_ENV
+    vnode_t vp;
+#endif
 
     AFS_STATCNT(PFlushVolumeData);
     if (!avc)
@@ -2534,25 +3455,49 @@ DECL_PIOCTL(PFlushVolumeData)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    volume = avc->fid.Fid.Volume;      /* who to zap */
-    cell = avc->fid.Cell;
+    volume = avc->f.fid.Fid.Volume;    /* who to zap */
+    cell = avc->f.fid.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->fid);
-    for (tvc = afs_vhashT[i]; tvc; tvc = tvc->vhnext) {
-           if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
-#if    defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)  || defined(AFS_SUN5_ENV)  || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
-               VN_HOLD(AFSTOV(tvc));
-#else
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
-               osi_vnhold(tvc, 0);
+    i = VCHashV(&avc->f.fid);
+    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 (tvc->f.states & CVInit) {
+                   ReleaseReadLock(&afs_xvcache);
+                   afs_osi_Sleep(&tvc->f.states);
+                   goto loop;
+               }
+#ifdef AFS_DARWIN80_ENV
+               if (tvc->f.states & CDeadVnode) {
+                   if (!(tvc->f.states & CBulkFetching)) {
+                       ReleaseReadLock(&afs_xvcache);
+                       afs_osi_Sleep(&tvc->f.states);
+                       goto loop;
+                   }
+               }
+               vp = AFSTOV(tvc);
+               if (vnode_get(vp))
+                   continue;
+               if (vnode_ref(vp)) {
+                   AFS_GUNLOCK();
+                   vnode_put(vp);
+                   AFS_GLOCK();
+                   continue;
+               }
+               if (tvc->f.states & (CBulkFetching|CDeadVnode)) {
+                   AFS_GUNLOCK();
+                   vnode_recycle(AFSTOV(tvc));
+                   AFS_GLOCK();
+               }
 #else
-               VREFCOUNT_INC(tvc); /* AIX, apparently */
-#endif
+               AFS_FAST_HOLD(tvc);
 #endif
                ReleaseReadLock(&afs_xvcache);
 #ifdef AFS_BOZONLOCK_ENV
@@ -2562,16 +3507,20 @@ DECL_PIOCTL(PFlushVolumeData)
 
                ObtainWriteLock(&afs_xcbhash, 458);
                afs_DequeueCallback(tvc);
-               tvc->states &= ~(CStatd | CDirty);
+               tvc->f.states &= ~(CStatd | CDirty);
                ReleaseWriteLock(&afs_xcbhash);
-               if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
+               if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
                    osi_dnlc_purgedp(tvc);
                afs_TryToSmush(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
                ObtainReadLock(&afs_xvcache);
+               uq = QPrev(tq);
                /* our tvc ptr is still good until now */
                AFS_FAST_RELE(tvc);
            }
@@ -2579,22 +3528,22 @@ DECL_PIOCTL(PFlushVolumeData)
     ReleaseReadLock(&afs_xvcache);
 
 
-    MObtainWriteLock(&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 */
+       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 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 */
                    afs_FlushDCache(tdc);
                }
            }
@@ -2603,7 +3552,7 @@ DECL_PIOCTL(PFlushVolumeData)
        }
        afs_PutDCache(tdc);     /* bumped by getdslot */
     }
-    MReleaseWriteLock(&afs_xdcache);
+    ReleaseWriteLock(&afs_xdcache);
 
     ObtainReadLock(&afs_xvolume);
     for (i = 0; i < NVOLS; i++) {
@@ -2623,10 +3572,31 @@ DECL_PIOCTL(PFlushVolumeData)
 }
 
 
-
+/*!
+ * VIOCGETVCXSTATUS (41) - gets vnode x status
+ *
+ * \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 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;
 
@@ -2644,15 +3614,15 @@ DECL_PIOCTL(PGetVnodeXStatus)
        return EACCES;
 
     memset(&stat, 0, sizeof(struct vcxstat));
-    stat.fid = avc->fid;
-    hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
+    stat.fid = avc->f.fid;
+    hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
     stat.lock = avc->lock;
-    stat.parentVnode = avc->parentVnode;
-    stat.parentUnique = avc->parentUnique;
+    stat.parentVnode = avc->f.parent.vnode;
+    stat.parentUnique = avc->f.parent.unique;
     hset(stat.flushDV, avc->flushDV);
     hset(stat.mapDV, avc->mapDV);
-    stat.truncPos = avc->truncPos;
-    {                          /* just grab the first two - won't break anything... */
+    stat.truncPos = avc->f.truncPos;
+    {                  /* 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) {
@@ -2662,21 +3632,19 @@ DECL_PIOCTL(PGetVnodeXStatus)
     }
     stat.callback = afs_data_pointer_to_int32(avc->callback);
     stat.cbExpires = avc->cbExpires;
-    stat.anyAccess = avc->anyAccess;
+    stat.anyAccess = avc->f.anyAccess;
     stat.opens = avc->opens;
     stat.execsOrWriters = avc->execsOrWriters;
     stat.flockCount = avc->flockCount;
     stat.mvstat = avc->mvstat;
-    stat.states = avc->states;
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
-    *aoutSize = sizeof(struct vcxstat);
-    return 0;
+    stat.states = avc->f.states;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
 }
 
 
 DECL_PIOCTL(PGetVnodeXStatus2)
 {
-    register afs_int32 code;
+    afs_int32 code;
     struct vcxstat2 stat;
     afs_int32 mode;
 
@@ -2695,28 +3663,52 @@ DECL_PIOCTL(PGetVnodeXStatus2)
     memset(&stat, 0, sizeof(struct vcxstat2));
 
     stat.cbExpires = avc->cbExpires;
-    stat.anyAccess = avc->anyAccess;
+    stat.anyAccess = avc->f.anyAccess;
     stat.mvstat = avc->mvstat;
     stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
 
-    memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
-    *aoutSize = sizeof(struct vcxstat2);
-    return 0;
+    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
 }
 
-/* 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 excercise */
- /* for the reader.  */
+
+/*!
+ * VIOC_AFS_SYSNAME (38) - Change @sys value
+ *
+ * \ingroup pioctl
+ *
+ * \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 . 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)
 {
-    char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
-    int setsysname, foundname = 0;
-    register struct afs_exporter *exporter;
-    register struct unixuser *au;
-    register afs_int32 pag, error;
-    int t, count, num = 0;
-    char **sysnamelist[MAXNUMSYSNAMES];
+    char *inname = NULL;
+    char outname[MAXSYSNAME];
+    afs_int32 setsysname;
+    int foundname = 0;
+    struct afs_exporter *exporter;
+    struct unixuser *au;
+    afs_int32 pag, error;
+    int t, count, num = 0, allpags = 0;
+    char **sysnamelist;
+    struct afs_pdata validate;
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
@@ -2727,34 +3719,40 @@ DECL_PIOCTL(PSetSysName)
        return (EINVAL);
 #endif
     }
-    memset(inname, 0, MAXSYSNAME);
-    memcpy((char *)&setsysname, ain, sizeof(afs_int32));
-    ain += sizeof(afs_int32);
+    if (afs_pd_getInt(ain, &setsysname) != 0)
+       return EINVAL;
+    if (setsysname & 0x8000) {
+       allpags = 1;
+       setsysname &= ~0x8000;
+    }
     if (setsysname) {
 
        /* Check my args */
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
            return EINVAL;
-       cp2 = ain;
-       for (cp = ain, count = 0; count < setsysname; count++) {
-           /* won't go past end of ain since maxsysname*num < ain length */
-           t = strlen(cp);
+       validate = *ain;
+       for (count = 0; count < setsysname; count++) {
+           if (afs_pd_getStringPtr(&validate, &inname) != 0)
+               return EINVAL;
+           t = strlen(inname);
            if (t >= MAXSYSNAME || t <= 0)
                return EINVAL;
            /* check for names that can shoot us in the foot */
-           if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
+           if (inname[0] == '.' && (inname[1] == 0
+               || (inname[1] == '.' && inname[2] == 0)))
                return EINVAL;
-           cp += t + 1;
        }
-       /* args ok */
+       /* args ok, so go back to the beginning of that section */
 
-       /* inname gets first entry in case we're being a translator */
-       t = strlen(ain);
-       memcpy(inname, ain, t + 1);     /* include terminating null */
-       ain += t + 1;
+       if (afs_pd_getStringPtr(ain, &inname) != 0)
+           return EINVAL;
        num = count;
     }
-    if ((*acred)->cr_gid == RMTUSER_REQ) {     /* Handles all exporters */
+    if (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;
+       }
        pag = PagInCred(*acred);
        if (pag == NOPAG) {
            return EINVAL;      /* Better than panicing */
@@ -2766,8 +3764,8 @@ DECL_PIOCTL(PSetSysName)
            afs_PutUser(au, READ_LOCK);
            return EINVAL;      /* Better than panicing */
        }
-       error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), sysnamelist,
-                           &num);
+       error = EXP_SYSNAME(exporter, inname, &sysnamelist,
+                           &num, allpags);
        if (error) {
            if (error == ENODEV)
                foundname = 0;  /* sysname not set yet! */
@@ -2777,9 +3775,11 @@ DECL_PIOCTL(PSetSysName)
            }
        } else {
            foundname = num;
-           strcpy(outname, (*sysnamelist)[0]);
+           strcpy(outname, sysnamelist[0]);
        }
        afs_PutUser(au, READ_LOCK);
+       if (setsysname)
+           afs_sysnamegen++;
     } else {
        /* Not xlating, so local case */
        if (!afs_sysname)
@@ -2787,48 +3787,54 @@ DECL_PIOCTL(PSetSysName)
        if (!setsysname) {      /* user just wants the info */
            strcpy(outname, afs_sysname);
            foundname = afs_sysnamecount;
-           *sysnamelist = afs_sysnamelist;
+           sysnamelist = afs_sysnamelist;
        } else {                /* Local guy; only root can change sysname */
            if (!afs_osi_suser(*acred))
                return EACCES;
 
+           /* allpags makes no sense for local use */
+           if (allpags)
+               return EINVAL;
+
            /* clear @sys entries from the dnlc, once afs_lookup can
             * do lookups of @sys entries and thinks it can trust them */
            /* privs ok, store the entry, ... */
+
+           if (strlen(inname) >= MAXSYSNAME-1)
+               return EINVAL;
            strcpy(afs_sysname, inname);
+
            if (setsysname > 1) {       /* ... or list */
-               cp = ain;
                for (count = 1; count < setsysname; ++count) {
                    if (!afs_sysnamelist[count])
                        osi_Panic
-                           ("PSetSysName: no afs_sysnamelist entry to write\n");
-                   t = strlen(cp);
-                   memcpy(afs_sysnamelist[count], cp, t + 1);  /* include null */
-                   cp += t + 1;
+                          ("PSetSysName: no afs_sysnamelist entry to write\n");
+                   if (afs_pd_getString(ain, afs_sysnamelist[count],
+                                        MAXSYSNAME) != 0)
+                       return EINVAL;
                }
            }
            afs_sysnamecount = setsysname;
+           afs_sysnamegen++;
        }
     }
     if (!setsysname) {
-       cp = aout;              /* not changing so report back the count and ... */
-       memcpy(cp, (char *)&foundname, sizeof(afs_int32));
-       cp += sizeof(afs_int32);
+       if (afs_pd_putInt(aout, foundname) != 0)
+           return E2BIG;
        if (foundname) {
-           strcpy(cp, outname);        /* ... the entry, ... */
-           cp += strlen(outname) + 1;
-           for (count = 1; count < foundname; ++count) {       /* ... or list. */
-               if (!(*sysnamelist)[count])
+           if (afs_pd_putString(aout, outname) != 0)
+               return E2BIG;
+           for (count = 1; count < foundname; ++count) {    /* ... or list. */
+               if (!sysnamelist[count])
                    osi_Panic
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
-               t = strlen((*sysnamelist)[count]);
+               t = strlen(sysnamelist[count]);
                if (t >= MAXSYSNAME)
                    osi_Panic("PSetSysName: sysname entry garbled\n");
-               strcpy(cp, (*sysnamelist)[count]);
-               cp += t + 1;
+               if (afs_pd_putString(aout, sysnamelist[count]) != 0)
+                   return E2BIG;
            }
        }
-       *aoutSize = cp - aout;
     }
     return 0;
 }
@@ -2852,7 +3858,7 @@ ReSortCells_cb(struct cell *cell, void *arg)
     for (i = 0; i < s; i++) {
        if (l[i] == cell->cellNum) {
            ObtainWriteLock(&cell->lock, 690);
-           afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
+           afs_SortServers(cell->cellHosts, AFS_MAXCELLHOSTS);
            ReleaseWriteLock(&cell->lock);
        }
     }
@@ -2865,7 +3871,7 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
 {
     int i;
     struct volume *j;
-    register int k;
+    int k;
 
     if (vlonly) {
        afs_int32 *p;
@@ -2883,7 +3889,7 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
            for (k = 0; k < s; k++)
                if (j->cell == l[k]) {
                    ObtainWriteLock(&j->lock, 233);
-                   afs_SortServers(j->serverHost, MAXHOSTS);
+                   afs_SortServers(j->serverHost, AFS_MAXHOSTS);
                    ReleaseWriteLock(&j->lock);
                    break;
                }
@@ -2895,10 +3901,7 @@ ReSortCells(int s, afs_int32 * l, int vlonly)
 
 static int debugsetsp = 0;
 static int
-afs_setsprefs(sp, num, vlonly)
-     struct spref *sp;
-     unsigned int num;
-     unsigned int vlonly;
+afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
 {
     struct srvAddr *sa;
     int i, j, k, matches, touchedSize;
@@ -2909,7 +3912,7 @@ afs_setsprefs(sp, num, 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);
@@ -2929,7 +3932,7 @@ afs_setsprefs(sp, num, 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);
@@ -2968,11 +3971,28 @@ afs_setsprefs(sp, num, vlonly)
     return 0;
 }
 
- /* Note that this may only be performed by the local root user.
-  */
+/*!
+ * VIOC_SETPREFS (46) - Set server ranks
+ *
+ * \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
+ *
+ * \post set the sprefs using the afs_setsprefs() function
+ */
 DECL_PIOCTL(PSetSPrefs)
 {
     struct setspref *ssp;
+    char *ainPtr;
+    size_t ainSize;
+
     AFS_STATCNT(PSetSPrefs);
 
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
@@ -2981,11 +4001,17 @@ DECL_PIOCTL(PSetSPrefs)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
+    /* The I/O handling here is ghastly, as it relies on overrunning the ends
+     * of arrays. But, i'm not quite brave enough to change it yet. */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
 
-    ssp = (struct setspref *)ain;
-    if (ainSize < sizeof(struct spref) * ssp->num_servers)
+    ssp = (struct setspref *)ainPtr;
+    if (ainSize < (sizeof(struct setspref)
+                  + sizeof(struct spref) * ssp->num_servers-1))
        return EINVAL;
 
     afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
@@ -2993,9 +4019,21 @@ DECL_PIOCTL(PSetSPrefs)
     return 0;
 }
 
+/*
+ * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
+ *
+ * \param[in] ain      the server preferences to be 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 server preferences, calling a function
+ *
+ * \notes this may only be performed by the local root user.
+ */
 DECL_PIOCTL(PSetSPrefs33)
 {
-    struct spref *sp;
     AFS_STATCNT(PSetSPrefs);
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
@@ -3004,21 +4042,35 @@ DECL_PIOCTL(PSetSPrefs33)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    sp = (struct spref *)ain;
-    afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
+    afs_setsprefs((struct spref *)afs_pd_where(ain),
+                 afs_pd_remaining(ain) / sizeof(struct spref),
+                 0 /*!vlonly */ );
     return 0;
 }
 
-/* some notes on the following code...
- * 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.
+/*
+ * VIOC_GETSPREFS (43) - Get server ranks
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the server preferences to get
+ * \param[out] aout    the server preferences information
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \retval ENOENT      Error if the sprefrequest is too large
+ *
+ * \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.
  */
 DECL_PIOCTL(PGetSPrefs)
 {
-    struct sprefrequest *spin; /* input */
+    struct sprefrequest spin;  /* input */
     struct sprefinfo *spout;   /* output */
     struct spref *srvout;      /* one output component */
     int i, j;                  /* counters for hash table traversal */
@@ -3031,31 +4083,35 @@ DECL_PIOCTL(PGetSPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-
-    if (ainSize < sizeof(struct sprefrequest_33)) {
-       return ENOENT;
+    /* Work out from the size whether we've got a new, or old, style pioctl */
+    if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
+          return ENOENT;
+       vlonly = 0;
+       spin.flags = 0;
     } else {
-       spin = ((struct sprefrequest *)ain);
+       if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
+          return EINVAL;
+       vlonly = (spin.flags & DBservers);
     }
 
-    if (ainSize > sizeof(struct sprefrequest_33)) {
-       vlonly = (spin->flags & DBservers);
-    } else
-       vlonly = 0;
+    /* This code relies on overflowing arrays. It's ghastly, but I'm not
+     * quite brave enough to tackle it yet ...
+     */
 
     /* struct sprefinfo includes 1 server struct...  that size gets added
      * in during the loop that follows.
      */
-    *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
-    spout = (struct sprefinfo *)aout;
-    spout->next_offset = spin->offset;
+    spout = afs_pd_inline(aout,
+                         sizeof(struct sprefinfo) - sizeof(struct spref));
+    spout->next_offset = spin.offset;
     spout->num_servers = 0;
     srvout = spout->servers;
 
     ObtainReadLock(&afs_xserver);
     for (i = 0, j = 0; j < NSERVERS; j++) {    /* sift through hash table */
        for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
-           if (spin->offset > (unsigned short)i) {
+           if (spin.offset > (unsigned short)i) {
                continue;       /* catch up to where we left off */
            }
            spout->next_offset++;
@@ -3069,34 +4125,56 @@ DECL_PIOCTL(PGetSPrefs)
                continue;
            }
 
+           /* Check we've actually got the space we're about to use */
+           if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
+               ReleaseReadLock(&afs_xserver);  /* no more room! */
+               return 0;
+           }
+
            srvout->host.s_addr = sa->sa_ip;
            srvout->rank = sa->sa_iprank;
-           *aoutSize += sizeof(struct spref);
            spout->num_servers++;
            srvout++;
-
-           if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
-               ReleaseReadLock(&afs_xserver);  /* no more room! */
-               return 0;
-           }
        }
     }
     ReleaseReadLock(&afs_xserver);
 
     spout->next_offset = 0;    /* start over from the beginning next time */
+
     return 0;
 }
 
 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
 int afs_NFSRootOnly = 1;
+/*!
+ * VIOC_EXPORTAFS (39) - Export afs to nfs clients
+ *
+ * \ingroup pioctl
+ *
+ * \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.
+ *
+ * \notes Legacy code obtained from IBM.
+ */
 DECL_PIOCTL(PExportAfs)
 {
-    afs_int32 export, newint =
-       0, type, changestate, handleValue, convmode, pwsync, smounts;
-    register struct afs_exporter *exporter;
+    afs_int32 export, newint = 0;
+    afs_int32 type, changestate, handleValue, convmode, pwsync, smounts;
+    afs_int32 rempags = 0, pagcb = 0;
+    struct afs_exporter *exporter;
 
     AFS_STATCNT(PExportAfs);
-    memcpy((char *)&handleValue, ain, sizeof(afs_int32));
+    if (afs_pd_getInt(ain, &handleValue) != 0)
+       return EINVAL;
     type = handleValue >> 24;
     if (type == 0x71) {
        newint = 1;
@@ -3105,10 +4183,12 @@ DECL_PIOCTL(PExportAfs)
     exporter = exporter_find(type);
     if (newint) {
        export = handleValue & 3;
-       changestate = handleValue & 0xff;
+       changestate = handleValue & 0xfff;
        smounts = (handleValue >> 2) & 3;
        pwsync = (handleValue >> 4) & 3;
        convmode = (handleValue >> 6) & 3;
+       rempags = (handleValue >> 8) & 3;
+       pagcb = (handleValue >> 10) & 3;
     } else {
        changestate = (handleValue >> 16) & 0x1;
        convmode = (handleValue >> 16) & 0x2;
@@ -3122,8 +4202,8 @@ DECL_PIOCTL(PExportAfs)
     }
     if (!changestate) {
        handleValue = exporter->exp_states;
-       memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-       *aoutSize = sizeof(afs_int32);
+       if (afs_pd_putInt(aout, handleValue) != 0)
+           return E2BIG;
     } else {
        if (!afs_osi_suser(*acred))
            return EACCES;      /* Only superuser can do this */
@@ -3155,9 +4235,21 @@ DECL_PIOCTL(PExportAfs)
                    exporter->exp_states &= ~EXP_SUBMOUNTS;
                }
            }
+           if (rempags & 2) {
+               if (rempags & 1)
+                   exporter->exp_states |= EXP_CLIPAGS;
+               else
+                   exporter->exp_states &= ~EXP_CLIPAGS;
+           }
+           if (pagcb & 2) {
+               if (pagcb & 1)
+                   exporter->exp_states |= EXP_CALLBACK;
+               else
+                   exporter->exp_states &= ~EXP_CALLBACK;
+           }
            handleValue = exporter->exp_states;
-           memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
-           *aoutSize = sizeof(afs_int32);
+           if (afs_pd_putInt(aout, handleValue) != 0)
+               return E2BIG;
        } else {
            if (export)
                exporter->exp_states |= EXP_EXPORTED;
@@ -3184,6 +4276,18 @@ DECL_PIOCTL(PExportAfs)
     return 0;
 }
 
+/*!
+ * VIOC_GAG (44) - Silence Cache Manager
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the flags to either gag or de-gag the cache manager
+ * \param[out] aout    not in use
+ *
+ * \retval EACCES      Error if the user doesn't have super-user credentials
+ *
+ * \post set the gag flags, then show these flags
+ */
 DECL_PIOCTL(PGag)
 {
     struct gaginfo *gagflags;
@@ -3191,13 +4295,26 @@ DECL_PIOCTL(PGag)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    gagflags = (struct gaginfo *)ain;
+    gagflags = afs_pd_inline(ain, sizeof(*gagflags));
+    if (gagflags == NULL)
+       return EINVAL;
     afs_showflags = gagflags->showflags;
 
     return 0;
 }
 
-
+/*!
+ * VIOC_TWIDDLE (45) - Adjust RX knobs
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the previous settings of the 'knobs'
+ * \param[out] aout    not in use
+ *
+ * \retval EACCES      Error if the user doesn't have super-user credentials
+ *
+ * \post build out the struct rxp, from a struct rx
+ */
 DECL_PIOCTL(PTwiddleRx)
 {
     struct rxparams *rxp;
@@ -3205,7 +4322,9 @@ DECL_PIOCTL(PTwiddleRx)
     if (!afs_osi_suser(*acred))
        return EACCES;
 
-    rxp = (struct rxparams *)ain;
+    rxp = afs_pd_inline(ain, sizeof(*rxp));
+    if (rxp == NULL)
+       return EINVAL;
 
     if (rxp->rx_initReceiveWindow)
        rx_initReceiveWindow = rxp->rx_initReceiveWindow;
@@ -3231,13 +4350,26 @@ DECL_PIOCTL(PTwiddleRx)
     return 0;
 }
 
+/*!
+ * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \post return the initial cache manager parameters
+ */
 DECL_PIOCTL(PGetInitParams)
 {
     if (sizeof(struct cm_initparams) > PIGGYSIZE)
        return E2BIG;
 
-    memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
-    *aoutSize = sizeof(struct cm_initparams);
+    return afs_pd_putBytes(aout, &cm_initParams,
+                          sizeof(struct cm_initparams));
     return 0;
 }
 
@@ -3248,7 +4380,7 @@ crget(void)
 {
     cred_t *cr;
     cr = crdup(get_current_cred());
-    memset((char *)cr, 0, sizeof(cred_t));
+    memset(cr, 0, sizeof(cred_t));
 #if CELL || CELL_PREPARE
     cr->cr_id = -1;
 #endif
@@ -3256,22 +4388,49 @@ crget(void)
 }
 #endif
 
+/*!
+ * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    value of cryptall
+ *
+ * \post Turns on, or disables, rxkad encryption by setting the cryptall global
+ */
 DECL_PIOCTL(PGetRxkcrypt)
 {
-    memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
-    *aoutSize = sizeof(afs_int32);
-    return 0;
+    return afs_pd_putInt(aout, cryptall);
 }
 
+/*!
+ * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
+ *
+ * \ingroup pioctl
+ *
+ * \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
+ *
+ * \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)
+ */
 DECL_PIOCTL(PSetRxkcrypt)
 {
     afs_int32 tmpval;
 
     if (!afs_osi_suser(*acred))
        return EPERM;
-    if (ainSize != sizeof(afs_int32) || ain == NULL)
+    if (afs_pd_getInt(ain, &tmpval) != 0)
        return EINVAL;
-    memcpy((char *)&tmpval, ain, sizeof(afs_int32));
     /* if new mappings added later this will need to be changed */
     if (tmpval != 0 && tmpval != 1)
        return EINVAL;
@@ -3290,21 +4449,27 @@ DECL_PIOCTL(PSetRxkcrypt)
 #define        PIOCTL_HEADER   6
 static int
 HandleClientContext(struct afs_ioctl *ablob, int *com,
-                   struct AFS_UCRED **acred, struct AFS_UCRED *credp)
+                   afs_ucred_t **acred, afs_ucred_t *credp)
 {
     char *ain, *inData;
     afs_uint32 hostaddr;
-    afs_int32 uid, g0, g1, i, code, pag, exporter_type;
+    afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
     struct afs_exporter *exporter, *outexporter;
-    struct AFS_UCRED *newcred;
+    afs_ucred_t *newcred;
     struct unixuser *au;
+    afs_uint32 comp = *com & 0xff00;
+    afs_uint32 h, l;
+#if defined(AFS_SUN510_ENV)
+    gid_t gids[2];
+#endif
 
 #if defined(AFS_SGIMP_ENV)
     osi_Assert(ISAFS_GLOCK());
 #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);
@@ -3325,7 +4490,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
@@ -3339,7 +4504,7 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        u.u_error = 0;
 #endif
        /* check for acceptable opcodes for normal folks, which are, so far,
-        * set tokens and unlog.
+        * get/set tokens, sysname, and unlog.
         */
        if (i != 9 && i != 3 && i != 38 && i != 8) {
            osi_FreeLargeSpace(inData);
@@ -3357,34 +4522,45 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
         * code fails for remote client roots.
         */
        uid = afs_nobody;       /* NFS_NOBODY == -2 */
+       isroot = 1;
     }
     newcred = crget();
-#if defined(AFS_LINUX26_ENV)
-    newcred->cr_group_info = groups_alloc(0);
-#endif
 #ifdef AFS_AIX41_ENV
     setuerror(0);
 #endif
-    newcred->cr_gid = RMTUSER_REQ;
+    afs_set_cr_gid(newcred, isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ);
 #ifdef AFS_AIX51_ENV
     newcred->cr_groupset.gs_union.un_groups[0] = g0;
     newcred->cr_groupset.gs_union.un_groups[1] = g1;
+#elif defined(AFS_LINUX26_ENV)
+# ifdef AFS_LINUX26_ONEGROUP_ENV
+    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(afs_cr_group_info(newcred), 0) = ((h << 28) | l);
+# else
+    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)
+    gids[0] = g0;
+    gids[1] = g1;
+    crsetgroups(newcred, 2, gids);
 #else
     newcred->cr_groups[0] = g0;
     newcred->cr_groups[1] = g1;
 #endif
 #ifdef AFS_AIX_ENV
     newcred->cr_ngrps = 2;
-#else
-#if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
+#elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
+# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
     newcred->cr_ngroups = 2;
-#else
+# else
     for (i = 2; i < NGROUPS; i++)
        newcred->cr_groups[i] = NOGROUP;
-#endif
-#endif
-#if    !defined(AFS_OSF_ENV) 
-    afs_nfsclient_init();      /* before looking for exporter, ensure one exists */
+# endif
 #endif
     if (!(exporter = exporter_find(exporter_type))) {
        /* Exporter wasn't initialized or an invalid exporter type */
@@ -3392,21 +4568,21 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
        return EINVAL;
     }
     if (exporter->exp_states & EXP_PWSYNC) {
-       if (uid != credp->cr_uid) {
+       if (uid != afs_cr_uid(credp)) {
            crfree(newcred);
            return ENOEXEC;     /* XXX Find a better errno XXX */
        }
     }
-    newcred->cr_uid = uid;     /* Only temporary  */
+    afs_set_cr_uid(newcred, uid);      /* Only temporary  */
     code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
     /* The client's pag is the only unique identifier for it */
-    newcred->cr_uid = pag;
+    afs_set_cr_uid(newcred, pag);
     *acred = newcred;
     if (!code && *com == PSETPAG) {
        /* 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
@@ -3423,12 +4599,28 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     } else if (!code) {
        EXP_RELE(outexporter);
     }
+    if (!code)
+       *com = (*com) | comp;
     return code;
 }
 #endif /* AFS_NEED_CLIENTCONTEXT */
 
-/* get all interface addresses of this client */
 
+/*!
+ * VIOC_GETCPREFS (50) - Get client interface
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      sprefrequest input
+ * \param[out] aout    spref information
+ *
+ * \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
+ */
 DECL_PIOCTL(PGetCPrefs)
 {
     struct sprefrequest *spin; /* input */
@@ -3441,11 +4633,13 @@ DECL_PIOCTL(PGetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    if (ainSize < sizeof(struct sprefrequest))
+    spin = afs_pd_inline(ain, sizeof(*spin));
+    if (spin == NULL)
        return EINVAL;
 
-    spin = (struct sprefrequest *)ain;
-    spout = (struct sprefinfo *)aout;
+    /* Output spout relies on writing past the end of arrays. It's horrible,
+     * but I'm not quite brave enough to tackle it yet */
+    spout = (struct sprefinfo *)aout->ptr;
 
     maxNumber = spin->num_servers;     /* max addrs this time */
     srvout = spout->servers;
@@ -3453,14 +4647,14 @@ 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++)
        srvout->host.s_addr = afs_cb_interface.addr_in[i];
 
     spout->num_servers = j;
-    *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
+    aout->ptr += sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
 
     if (i >= afs_cb_interface.numberOfInterfaces)
        spout->next_offset = 0; /* start from beginning again */
@@ -3471,8 +4665,24 @@ DECL_PIOCTL(PGetCPrefs)
     return 0;
 }
 
+/*!
+ * VIOC_SETCPREFS (51) - Set client interface
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the interfaces you want set
+ * \param[out] aout    not in use
+ *
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ * \retval EINVAL      Error if the input is too large for the struct
+ * \retval ENOMEM      Error if there are too many servers
+ *
+ * \post set the callbak interfaces addresses to those of the hosts
+ */
 DECL_PIOCTL(PSetCPrefs)
 {
+    char *ainPtr;
+    size_t ainSize;
     struct setspref *sin;
     int i;
 
@@ -3480,7 +4690,13 @@ DECL_PIOCTL(PSetCPrefs)
     if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
        return EIO;             /* Inappropriate ioctl for device */
 
-    sin = (struct setspref *)ain;
+    /* Yuck. Input to this function relies on reading past the end of
+     * structures. Bodge it for now.
+     */
+    ainPtr = ain->ptr;
+    ainSize = ain->remaining;
+
+    sin = (struct setspref *)ainPtr;
 
     if (ainSize < sizeof(struct setspref))
        return EINVAL;
@@ -3500,19 +4716,45 @@ DECL_PIOCTL(PSetCPrefs)
     return 0;
 }
 
+/*!
+ * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
+ *
+ * \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
+ *
+ * \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
+ */
 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;
     struct sysname_info sysState;
     afs_size_t offset, len;
 
     AFS_STATCNT(PFlushMount);
     if (!avc)
        return EINVAL;
+
+    if (afs_pd_getStringPtr(ain, &mount) != 0)
+       return EINVAL;
+
     code = afs_VerifyVCache(avc, areq);
     if (code)
        return code;
@@ -3522,7 +4764,7 @@ DECL_PIOCTL(PFlushMount)
     tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
     if (!tdc)
        return ENOENT;
-    Check_AtSys(avc, ain, &sysState, areq);
+    Check_AtSys(avc, mount, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
@@ -3533,9 +4775,9 @@ DECL_PIOCTL(PFlushMount)
     if (code) {
        goto out;
     }
-    tfid.Cell = avc->fid.Cell;
-    tfid.Fid.Volume = avc->fid.Fid.Volume;
-    if (!tfid.Fid.Unique && (avc->states & CForeign)) {
+    tfid.Cell = avc->f.fid.Cell;
+    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
+    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
     } else {
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
@@ -3555,12 +4797,12 @@ DECL_PIOCTL(PFlushMount)
     ObtainWriteLock(&tvc->lock, 649);
     ObtainWriteLock(&afs_xcbhash, 650);
     afs_DequeueCallback(tvc);
-    tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
+    tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
     ReleaseWriteLock(&afs_xcbhash);
     /* now find the disk cache entries */
     afs_TryToSmush(tvc, *acred, 1);
     osi_dnlc_purgedp(tvc);
-    if (tvc->linkData && !(tvc->states & CCore)) {
+    if (tvc->linkData && !(tvc->f.states & CCore)) {
        afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
        tvc->linkData = NULL;
     }
@@ -3575,24 +4817,34 @@ DECL_PIOCTL(PFlushMount)
     return code;
 }
 
+/*!
+ * VIOC_RXSTAT_PROC (53) - Control process RX statistics
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the flags that control which stats to use
+ * \param[out] aout    not in use
+ *
+ * \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
+ */
 DECL_PIOCTL(PRxStatProc)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enableProcessRPCStats();
     }
@@ -3602,30 +4854,38 @@ DECL_PIOCTL(PRxStatProc)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 
+/*!
+ * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      the flags that control which statistics to use
+ * \param[out] aout    not in use
+ *
+ * \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
+ */
 DECL_PIOCTL(PRxStatPeer)
 {
-    int code = 0;
     afs_int32 flags;
 
-    if (!afs_osi_suser(*acred)) {
-       code = EACCES;
-       goto out;
-    }
-    if (ainSize != sizeof(afs_int32)) {
-       code = EINVAL;
-       goto out;
-    }
-    memcpy((char *)&flags, ain, sizeof(afs_int32));
-    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
-       code = EINVAL;
-       goto out;
-    }
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    if (afs_pd_getInt(ain, &flags) != 0)
+       return EINVAL;
+
+    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
+       return EINVAL;
+
     if (flags & AFSCALL_RXSTATS_ENABLE) {
        rx_enablePeerRPCStats();
     }
@@ -3635,16 +4895,14 @@ DECL_PIOCTL(PRxStatPeer)
     if (flags & AFSCALL_RXSTATS_CLEAR) {
        rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
     }
-  out:
-    *aoutSize = 0;
-    return code;
+    return 0;
 }
 
 DECL_PIOCTL(PPrefetchFromTape)
 {
-    register afs_int32 code, code1;
-    afs_int32 bytes;
-    struct conn *tc;
+    afs_int32 code, code1;
+    afs_int32 bytes, outval;
+    struct afs_conn *tc;
     struct rx_call *tcall;
     struct AFSVolSync tsync;
     struct AFSFetchStatus OutStatus;
@@ -3657,11 +4915,11 @@ DECL_PIOCTL(PPrefetchFromTape)
     if (!avc)
        return EINVAL;
 
-    if (ain && (ainSize == 3 * sizeof(afs_int32)))
-       Fid = (struct AFSFid *)ain;
-    else
-       Fid = &avc->fid.Fid;
-    tfid.Cell = avc->fid.Cell;
+    Fid = afs_pd_inline(ain, sizeof(struct AFSFid));
+    if (Fid == NULL)
+       Fid = &avc->f.fid.Fid;
+
+    tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = Fid->Volume;
     tfid.Fid.Vnode = Fid->Vnode;
     tfid.Fid.Unique = Fid->Unique;
@@ -3669,23 +4927,23 @@ DECL_PIOCTL(PPrefetchFromTape)
     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
     if (!tvc) {
        afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
-                  ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->fid);
+                  ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
        return ENOENT;
     }
     afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
-              ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->fid);
+              ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
 
     do {
-       tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+       tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
        if (tc) {
 
            RX_AFS_GUNLOCK();
            tcall = rx_NewCall(tc->id);
            code =
-               StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->fid.Fid, 0,
+               StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
                                     0);
            if (!code) {
-               bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
+               bytes = rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
                code =
                    EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
            }
@@ -3694,40 +4952,44 @@ DECL_PIOCTL(PPrefetchFromTape)
        } else
            code = -1;
     } while (afs_Analyze
-            (tc, code, &tvc->fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
+            (tc, 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);
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(afs_int32);
-    }
-    return code;
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, outval);
 }
 
-DECL_PIOCTL(PResidencyCmd)
+DECL_PIOCTL(PFsCmd)
 {
-    register afs_int32 code;
-    struct conn *tc;
+    afs_int32 code;
+    struct afs_conn *tc;
     struct vcache *tvc;
-    struct ResidencyCmdInputs *Inputs;
-    struct ResidencyCmdOutputs *Outputs;
+    struct FsCmdInputs *Inputs;
+    struct FsCmdOutputs *Outputs;
     struct VenusFid tfid;
     struct AFSFid *Fid;
 
-    Inputs = (struct ResidencyCmdInputs *)ain;
-    Outputs = (struct ResidencyCmdOutputs *)aout;
     if (!avc)
        return EINVAL;
-    if (!ain || ainSize != sizeof(struct ResidencyCmdInputs))
+
+    Inputs = afs_pd_inline(ain, sizeof(*Inputs));
+    if (Inputs == NULL)
        return EINVAL;
 
+    Outputs = afs_pd_inline(aout, sizeof(*Outputs));
+    if (Outputs == NULL)
+       return E2BIG;
+
     Fid = &Inputs->fid;
     if (!Fid->Volume)
-       Fid = &avc->fid.Fid;
+       Fid = &avc->f.fid.Fid;
 
-    tfid.Cell = avc->fid.Cell;
+    tfid.Cell = avc->f.fid.Cell;
     tfid.Fid.Volume = Fid->Volume;
     tfid.Fid.Vnode = Fid->Vnode;
     tfid.Fid.Unique = Fid->Unique;
@@ -3740,21 +5002,21 @@ DECL_PIOCTL(PResidencyCmd)
 
     if (Inputs->command) {
        do {
-           tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+           tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
            if (tc) {
                RX_AFS_GUNLOCK();
                code =
-                   RXAFS_ResidencyCmd(tc->id, Fid, Inputs,
-                                      (struct ResidencyCmdOutputs *)aout);
+                   RXAFS_FsCmd(tc->id, Fid, Inputs,
+                                       (struct FsCmdOutputs *)aout);
                RX_AFS_GLOCK();
            } else
                code = -1;
        } while (afs_Analyze
-                (tc, code, &tvc->fid, areq,
+                (tc, 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;
@@ -3768,12 +5030,63 @@ DECL_PIOCTL(PResidencyCmd)
 
     afs_PutVCache(tvc);
 
-    if (!code) {
-       *aoutSize = sizeof(struct ResidencyCmdOutputs);
-    }
     return code;
 }
 
+DECL_PIOCTL(PNewUuid)
+{
+    /*AFS_STATCNT(PNewUuid); */
+    if (!afs_resourceinit_flag)        /* afs deamons havn't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    if (!afs_osi_suser(*acred))
+       return EACCES;
+
+    ObtainWriteLock(&afs_xinterface, 555);
+    afs_uuid_create(&afs_cb_interface.uuid);
+    ReleaseWriteLock(&afs_xinterface);
+    ForceAllNewConnections();
+    return 0;
+}
+
+#if defined(AFS_CACHE_BYPASS)
+
+DECL_PIOCTL(PSetCachingThreshold)
+{
+    afs_int32 getting = 1;
+    afs_int32 setting = 1;
+    afs_int32 threshold = AFS_CACHE_BYPASS_DISABLED;
+
+    if (afs_pd_getInt(ain, &threshold) != 0)
+       setting = 0;
+
+    if (aout == NULL)
+       getting = 0;
+
+    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);
+       /* TODO:  move to separate pioctl, or enhance pioctl */
+       cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
+    }
+
+    /* Return the current size threshold */
+    if (getting)
+       return afs_pd_putInt(aout, cache_bypass_threshold);
+
+    return(0);
+}
+
+#endif /* defined(AFS_CACHE_BYPASS) */
+
 DECL_PIOCTL(PCallBackAddr)
 {
 #ifndef UKERNEL
@@ -3781,7 +5094,7 @@ DECL_PIOCTL(PCallBackAddr)
     int srvAddrCount;
     struct server *ts;
     struct srvAddr *sa;
-    struct conn *tc;
+    struct afs_conn *tc;
     afs_int32 i, j;
     struct unixuser *tu;
     struct srvAddr **addrs;
@@ -3793,11 +5106,9 @@ DECL_PIOCTL(PCallBackAddr)
     if (!afs_osi_suser(acred))
        return EACCES;
 
-    if (ainSize < sizeof(afs_int32))
+    if (afs_pd_getInt(ain, &addr) != 0)
        return EINVAL;
 
-    memcpy(&addr, ain, sizeof(afs_int32));
-
     ObtainReadLock(&afs_xinterface);
     for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
        if (afs_cb_interface.addr_in[i] == addr)
@@ -3871,3 +5182,308 @@ DECL_PIOCTL(PCallBackAddr)
 #endif /* UKERNEL */
     return 0;
 }
+
+DECL_PIOCTL(PDiscon)
+{
+    static afs_int32 mode = 1; /* Start up in 'off' */
+    afs_int32 force = 0;
+    int code = 0;
+    char flags[4];
+    struct vrequest lreq;
+
+    if (afs_pd_getBytes(ain, &flags, 4) == 0) {
+       if (!afs_osi_suser(*acred))
+           return EPERM;
+
+       if (flags[0])
+           mode = flags[0] - 1;
+       if (flags[1])
+           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
+        * change here, they should change there and vice versa
+        */
+       switch (mode) {
+       case 0: /* Disconnect ("offline" mode), breaking all callbacks */
+           if (!AFS_IS_DISCONNECTED) {
+               ObtainWriteLock(&afs_discon_lock, 999);
+               afs_DisconGiveUpCallbacks();
+               afs_RemoveAllConns();
+               afs_is_disconnected = 1;
+               afs_is_discon_rw = 1;
+               ReleaseWriteLock(&afs_discon_lock);
+           }
+           break;
+       case 1: /* Fully connected, ("online" mode). */
+           ObtainWriteLock(&afs_discon_lock, 998);
+
+           afs_in_sync = 1;
+           afs_MarkAllServersUp();
+           code = afs_ResyncDisconFiles(areq, *acred);
+           afs_in_sync = 0;
+
+           if (code && !force) {
+               afs_warnuser("Files not synchronized properly, still in discon state. \n"
+                      "Please retry or use \"force\".\n");
+               mode = 0;
+           } else {
+               if (force) {
+                   afs_DisconDiscardAll(*acred);
+               }
+               afs_ClearAllStatdFlag();
+               afs_is_disconnected = 0;
+               afs_is_discon_rw = 0;
+               afs_warnuser("\nSync succeeded. You are back online.\n");
+           }
+
+           ReleaseWriteLock(&afs_discon_lock);
+           break;
+       default:
+           return EINVAL;
+       }
+    } else {
+       return EINVAL;
+    }
+
+    if (code)
+       return code;
+
+    return afs_pd_putInt(aout, mode);
+}
+
+#define MAX_PIOCTL_TOKENS 10
+
+DECL_PIOCTL(PSetTokens2)
+{
+    int code =0;
+    int i, cellNum, primaryFlag;
+    XDR xdrs;
+    struct unixuser *tu;
+    struct vrequest treq;
+    struct ktc_setTokenData tokenSet;
+    struct ktc_tokenUnion decodedToken;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    AFS_STATCNT(PSetTokens2);
+    if (!afs_resourceinit_flag)
+       return EIO;
+
+    afs_pd_xdrStart(ain, &xdrs, XDR_DECODE);
+
+    if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+       afs_pd_xdrEnd(ain, &xdrs);
+       return EINVAL;
+    }
+
+    afs_pd_xdrEnd(ain, &xdrs);
+
+    /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
+     * process from using up the whole of the kernel memory by allocating
+     * tokens.
+     */
+    if (tokenSet.tokens.tokens_len > MAX_PIOCTL_TOKENS) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return E2BIG;
+    }
+
+    code = _settok_tokenCell(tokenSet.cell, &cellNum, &primaryFlag);
+    if (code) {
+       xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+       return code;
+    }
+
+    if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
+       if (_settok_setParentPag(acred) == 0) {
+           afs_InitReq(&treq, *acred);
+           areq = &treq;
+       }
+    }
+
+    tu = afs_GetUser(areq->uid, cellNum, WRITE_LOCK);
+    /* Free any tokens that we've already got */
+    afs_FreeTokens(&tu->tokens);
+
+    /* Iterate across the set of tokens we've received, and stuff them
+     * into this user's tokenJar
+     */
+    for (i=0; i < tokenSet.tokens.tokens_len; i++) {
+       xdrmem_create(&xdrs,
+                     tokenSet.tokens.tokens_val[i].token_opaque_val,
+                     tokenSet.tokens.tokens_val[i].token_opaque_len,
+                     XDR_DECODE);
+
+       memset(&decodedToken, 0, sizeof(decodedToken));
+       if (!xdr_ktc_tokenUnion(&xdrs, &decodedToken)) {
+           xdr_destroy(&xdrs);
+           code = EINVAL;
+           goto out;
+       }
+
+       xdr_destroy(&xdrs);
+
+       afs_AddTokenFromPioctl(&tu->tokens, &decodedToken);
+       /* This is untidy - the old token interface supported passing
+        * the primaryFlag as part of the token interface. Current
+        * OpenAFS userland never sets this, but it's specified as being
+        * part of the XG interface, so we should probably still support
+        * it. Rather than add it to our AddToken interface, just handle
+        * it here.
+        */
+       if (decodedToken.at_type == AFSTOKEN_UNION_KAD) {
+           if (decodedToken.ktc_tokenUnion_u.at_kad.rk_primary_flag)
+               primaryFlag = 1;
+       }
+
+       /* XXX - We should think more about destruction here. It's likely that
+        * there is key material in what we're about to throw away, which
+        * we really should zero out before giving back to the allocator */
+       xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &decodedToken);
+    }
+
+    tu->states |= UHasTokens;
+    tu->states &= ~UTokensBad;
+    afs_SetPrimary(tu, primaryFlag);
+    tu->tokenTime = osi_Time();
+
+    xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+
+out:
+    afs_ResetUserConns(tu);
+    afs_PutUser(tu, WRITE_LOCK);
+
+    return code;
+}
+
+DECL_PIOCTL(PGetTokens2)
+{
+    struct cell *cell;
+    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;
+    afs_int32 i;
+    struct unixuser *tu;
+
+    AFS_STATCNT(PUnlog);
+    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    if (afs_pd_getUint(ain, &addr) != 0)
+       return EINVAL;
+
+    if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
+       tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
+       if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
+           afs_PutUser(tu, SHARED_LOCK);
+           return EACCES;
+       }
+       afs_PutUser(tu, SHARED_LOCK);
+    } else if (!afs_osi_suser(acred)) {
+       return EACCES;
+    }
+
+    ObtainWriteLock(&afs_xuser, 227);
+    for (i = 0; i < NUSERS; i++) {
+       for (tu = afs_users[i]; tu; tu = tu->next) {
+           if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
+               tu->states &= ~UHasTokens;
+               afs_FreeTokens(&tu->tokens);
+               tu->refCount++;
+               ReleaseWriteLock(&afs_xuser);
+               afs_ResetUserConns(tu);
+               tu->refCount--;
+               ObtainWriteLock(&afs_xuser, 228);
+#ifdef UKERNEL
+               /* set the expire times to 0, causes
+                * afs_GCUserData to remove this entry
+                */
+               tu->tokenTime = 0;
+#endif /* UKERNEL */
+           }
+       }
+    }
+    ReleaseWriteLock(&afs_xuser);
+    return 0;
+}