Detect realloc failure
[openafs.git] / src / volser / volprocs.c
index 965a417..832f5d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#include <winsock2.h>
-#else
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <unistd.h>
+#include <afs/opr.h>
+#ifdef AFS_PTHREAD_ENV
+# include <opr/lock.h>
 #endif
 
-#include <dirent.h>
-#include <sys/stat.h>
-#include <rx/xdr.h>
 #include <rx/rx.h>
 #include <rx/rxkad.h>
+#include <rx/rx_queue.h>
 #include <afs/afsint.h>
-#include <signal.h>
-#ifdef AFS_PTHREAD_ENV
-#include <assert.h>
-#else /* AFS_PTHREAD_ENV */
-#include <afs/assert.h>
-#endif /* AFS_PTHREAD_ENV */
 #include <afs/prs_fs.h>
 #include <afs/nfs.h>
 #include <lwp.h>
@@ -61,18 +44,24 @@ RCSID
 #include <afs/acl.h>
 #include "afs/audit.h"
 #include <afs/dir.h>
+#include <afs/afsutil.h>
+#include <afs/com_err.h>
+#include <afs/vol_prototypes.h>
+#include <afs/errors.h>
 
 #include "volser.h"
+#include "voltrans_inline.h"
 #include "volint.h"
 
-#include "volser_prototypes.h"
+#include "volser_internal.h"
+#include "physio.h"
+#include "dumpstuff.h"
 
 extern int DoLogging;
-extern struct volser_trans *FindTrans(), *NewTrans(), *TransList();
 extern struct afsconf_dir *tdir;
-
-/* Needed by Irix. Leave, or include a header */
-extern char *volutil_PartitionName();
+extern int DoPreserveVolumeStats;
+extern int restrictedQueryLevel;
+extern enum vol_s2s_crypt doCrypt;
 
 extern void LogError(afs_int32 errcode);
 
@@ -86,76 +75,96 @@ static int GetPartName(afs_int32 partid, char *pname);
 #endif
 
 afs_int32 localTid = 1;
-afs_int32 VolPartitionInfo(), VolNukeVolume(), VolCreateVolume(),
-VolDeleteVolume(), VolClone();
-afs_int32 VolReClone(), VolTransCreate(), VolGetNthVolume(), VolGetFlags(),
-VolForward(), VolDump();
-afs_int32 VolRestore(), VolEndTrans(), VolSetForwarding(), VolGetStatus(),
-VolSetInfo(), VolGetName();
-afs_int32 VolListPartitions(), VolListOneVolume(),
-VolXListOneVolume(), VolXListVolumes();
-afs_int32 VolListVolumes(), XVolListPartitions(), VolMonitor(),
-VolSetIdsTypes(), VolSetDate(), VolSetFlags();
+
+static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
+                                 struct diskPartition64 *);
+static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
+static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
+                                afs_int32, afs_uint32, afs_uint32 *,
+                                afs_int32 *);
+static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
+static afs_int32 VolClone(struct rx_call *, afs_int32, VolumeId,
+                         afs_int32, char *, VolumeId *);
+static afs_int32 VolReClone(struct rx_call *, afs_int32, VolumeId);
+static afs_int32 VolTransCreate(struct rx_call *, VolumeId, afs_int32,
+                               afs_int32, afs_int32 *);
+static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
+                                afs_int32 *);
+static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
+static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
+static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
+                           struct destServer *destination, afs_int32,
+                           struct restoreCookie *cookie);
+static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
+static afs_int32 VolRestore(struct rx_call *, afs_int32, struct restoreCookie *);
+static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
+static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
+static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
+                             struct volser_status *);
+static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
+static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
+static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
+static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
+static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, VolumeId,
+                                 volEntries *);
+static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, VolumeId,
+                                  volXEntries *);
+static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
+                               volEntries *);
+static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
+                               volXEntries *);
+static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
+static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
+                               afs_int32, VolumeId, VolumeId,
+                               VolumeId);
+static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
+
+/**
+ * Return the host address of the caller as a string.
+ *
+ * @param[in]  acid    incoming rx call
+ * @param[out] buffer  buffer to be filled with the addess string
+ *
+ * @return address as formatted by inet_ntoa
+ */
+static_inline char *
+callerAddress(struct rx_call *acid, char *buffer)
+{
+    afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
+    return afs_inet_ntoa_r(ip, buffer);
+}
 
 /* this call unlocks all of the partition locks we've set */
-int 
-VPFullUnlock()
+int
+VPFullUnlock_r(void)
 {
-    register struct DiskPartition64 *tp;
+    struct DiskPartition64 *tp;
     for (tp = DiskPartitionList; tp; tp = tp->next) {
-       if (tp->lock_fd != -1) {
-           close(tp->lock_fd); /* releases flock held on this partition */
-           tp->lock_fd = -1;
+       if (tp->lock_fd != INVALID_FD) {
+            OS_CLOSE(tp->lock_fd);
+           tp->lock_fd = INVALID_FD;
        }
     }
     return 0;
 }
 
-/* get partition id from a name */
-afs_int32
-PartitionID(char *aname)
+int
+VPFullUnlock(void)
 {
-    register char tc;
-    register int code = 0;
-    char ascii[3];
-
-    tc = *aname;
-    if (tc == 0)
-       return -1;              /* unknown */
-
-    /* otherwise check for vicepa or /vicepa, or just plain "a" */
-    ascii[2] = 0;
-    if (!strncmp(aname, "/vicep", 6)) {
-       strncpy(ascii, aname + 6, 2);
-    } else
-       return -1;              /* bad partition name */
-    /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
-     * from 0.  Do the appropriate conversion */
-    if (ascii[1] == 0) {
-       /* one char name, 0..25 */
-       if (ascii[0] < 'a' || ascii[0] > 'z')
-           return -1;          /* wrongo */
-       return ascii[0] - 'a';
-    } else {
-       /* two char name, 26 .. <whatever> */
-       if (ascii[0] < 'a' || ascii[0] > 'z')
-           return -1;          /* wrongo */
-       if (ascii[1] < 'a' || ascii[1] > 'z')
-           return -1;          /* just as bad */
-       code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
-       if (code > VOLMAXPARTS)
-           return -1;
-       return code;
-    }
+    int code;
+    VOL_LOCK;
+    code = VPFullUnlock_r();
+    VOL_UNLOCK;
+    return code;
 }
 
 static int
-ConvertVolume(afs_int32 avol, char *aname, afs_int32 asize)
+ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
 {
     if (asize < 18)
        return -1;
     /* It's better using the Generic VFORMAT since otherwise we have to make changes to too many places... The 14 char limitation in names hits us again in AIX; print in field of 9 digits (still 10 for the rest), right justified with 0 padding */
-    (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
+    snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
     return 0;
 }
 
@@ -179,12 +188,92 @@ ConvertPartition(int apartno, char *aname, int asize)
     return 0;
 }
 
+#ifdef AFS_DEMAND_ATTACH_FS
+/* normally we should use the regular salvaging functions from the volume
+ * package, but this is a special case where we have a volume ID, but no
+ * volume structure to give the volume package */
+static void
+SalvageUnknownVolume(VolumeId volid, char *part)
+{
+    afs_int32 code;
+
+    Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
+        afs_printable_uint32_lu(volid), part);
+
+    code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
+                       FSYNC_SALVAGE, NULL);
+    if (code) {
+       Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
+           afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
+           part);
+    }
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+static struct Volume *
+VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
+{
+    struct Volume *vp;
+
+    *ec = 0;
+    vp = VAttachVolumeByName(ec, partition, name, mode);
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    {
+        int i;
+        /*
+         * The fileserver will take care of keeping track of how many
+         * demand-salvages have been performed, and will force the volume to
+         * ERROR if we've done too many. The limit on This loop is just a
+         * failsafe to prevent trying to salvage forever. We want to attempt
+         * attachment at least SALVAGE_COUNT_MAX times, since we want to
+         * avoid prematurely exiting this loop, if we can.
+         */
+        for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
+            sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
+            vp = VAttachVolumeByName(ec, partition, name, mode);
+        }
+
+        if (*ec == VSALVAGING) {
+            *ec = VSALVAGE;
+        }
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+    return vp;
+}
+
+static struct Volume *
+VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
+{
+    struct Volume *vp;
+
+    *ec = 0;
+    vp = VAttachVolume(ec, avolid, amode);
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    {
+        int i;
+        /* see comment above in VAttachVolumeByName_retry */
+        for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
+            sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
+            vp = VAttachVolume(ec, avolid, amode);
+        }
+
+        if (*ec == VSALVAGING) {
+            *ec = VSALVAGE;
+        }
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+    return vp;
+}
+
 /* the only attach function that takes a partition is "...ByName", so we use it */
-struct Volume *
-XAttachVolume(afs_int32 *error, afs_int32 avolid, afs_int32 apartid, int amode)
+static struct Volume *
+XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
 {
     char pbuf[30], vbuf[20];
-    register struct Volume *tv;
 
     if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
        *error = EINVAL;
@@ -194,46 +283,49 @@ XAttachVolume(afs_int32 *error, afs_int32 avolid, afs_int32 apartid, int amode)
        *error = EINVAL;
        return NULL;
     }
-    tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
-    return tv;
+
+    return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
 }
 
 /* Adapted from the file server; create a root directory for this volume */
-static int
+static Error
 ViceCreateRoot(Volume *vp)
 {
     DirHandle dir;
     struct acl_accessList *ACL;
-    ViceFid did;
-    Inode inodeNumber, nearInode;
+    AFSFid did;
+    Inode inodeNumber, AFS_UNUSED nearInode;
     struct VnodeDiskObject *vnode;
     struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
     IHandle_t *h;
     FdHandle_t *fdP;
-    int code;
     afs_fsize_t length;
+    ssize_t nBytes;
 
-    vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
+    vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
     if (!vnode)
        return ENOMEM;
-    memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
 
     V_pref(vp, nearInode);
     inodeNumber =
        IH_CREATE(V_linkHandle(vp), V_device(vp),
                  VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
                  1, 1, 0);
-    assert(VALID_INO(inodeNumber));
+    if (!VALID_INO(inodeNumber)) {
+       Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
+       free(vnode);
+       return EIO;
+    }
 
     SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
     did.Volume = V_id(vp);
     did.Vnode = (VnodeId) 1;
     did.Unique = 1;
 
-    assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
+    opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
     DFlush();                  /* flush all modified dir buffers out */
-    DZap((afs_int32 *)&dir);                   /* Remove all buffers for this dir */
-    length = Length(&dir);     /* Remember size of this directory */
+    DZap(&dir);                        /* Remove all buffers for this dir */
+    length = afs_dir_Length(&dir);     /* Remember size of this directory */
 
     FidZap(&dir);              /* Done with the dir handle obtained via SetSalvageDirHandle() */
 
@@ -270,28 +362,26 @@ ViceCreateRoot(Volume *vp)
     IH_INIT(h, vp->device, V_parentId(vp),
            vp->vnodeIndex[vLarge].handle->ih_ino);
     fdP = IH_OPEN(h);
-    assert(fdP != NULL);
-    code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
-    assert(code >= 0);
-    code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
-    assert(code == SIZEOF_LARGEDISKVNODE);
+    opr_Assert(fdP != NULL);
+    nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
+    opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
     FDH_REALLYCLOSE(fdP);
     IH_RELEASE(h);
     VNDISK_GET_LEN(length, vnode);
     V_diskused(vp) = nBlocks(length);
 
     free(vnode);
-    return 1;
+    return 0;
 }
 
 afs_int32
-SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition 
+SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
                     *partition)
 {
     afs_int32 code;
-    struct diskPartition64 *dp = (struct diskPartition64 *)
-       malloc(sizeof(struct diskPartition64));
+    struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
 
+    memset(partition, 0, sizeof(*partition));
     code = VolPartitionInfo(acid, pname, dp);
     if (!code) {
        strncpy(partition->name, dp->name, 32);
@@ -306,31 +396,32 @@ SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
 }
 
 afs_int32
-SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64 
+SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
                     *partition)
 {
     afs_int32 code;
 
+    memset(partition, 0, sizeof(*partition));
     code = VolPartitionInfo(acid, pname, partition);
     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
     return code;
 }
 
 afs_int32
-VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64 
+VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
                 *partition)
 {
-    register struct DiskPartition64 *dp;
+    struct DiskPartition64 *dp;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
-/*
-    if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
-*/
     VResetDiskUsage();
     dp = VGetPartition(pname, 0);
     if (dp) {
        strncpy(partition->name, dp->name, 32);
        strncpy(partition->devName, dp->devName, 32);
-       partition->lock_fd = dp->lock_fd;
+       partition->lock_fd = (int)dp->lock_fd;
        partition->free = dp->free;
        partition->minFree = dp->totalUsable;
        return 0;
@@ -340,7 +431,7 @@ VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
 
 /* obliterate a volume completely, and slowly. */
 afs_int32
-SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
+SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
 {
     afs_int32 code;
 
@@ -349,20 +440,24 @@ SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
     return code;
 }
 
-afs_int32
-VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
+static afs_int32
+VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
 {
     char partName[50];
     afs_int32 error;
-    register afs_int32 code;
+    Error verror;
+    afs_int32 code;
     struct Volume *tvp;
     char caller[MAXKTCNAMELEN];
 
     /* check for access */
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;
-    if (DoLogging)
-       Log("%s is executing VolNukeVolume %u\n", caller, avolID);
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing VolNukeVolume %u\n", caller,
+           callerAddress(acid, buffer), avolID);
+    }
 
     if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
        return VOLSERNOVOL;
@@ -373,7 +468,7 @@ VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
     tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
     code = nuke(partName, avolID);
     if (tvp)
-       VDetachVolume(&error, tvp);
+       VDetachVolume(&verror, tvp);
     return code;
 }
 
@@ -384,8 +479,8 @@ VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
  * Return the new volume id in *avolid.
  */
 afs_int32
-SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname, 
-                   afs_int32 atype, afs_int32 aparent, afs_int32 *avolid, 
+SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
+                   afs_int32 atype, VolumeId aparent, VolumeId *avolid,
                    afs_int32 *atrans)
 {
     afs_int32 code;
@@ -398,16 +493,17 @@ SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
     return code;
 }
 
-afs_int32
-VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname, 
-                   afs_int32 atype, afs_int32 aparent, afs_int32 *avolid, 
+static afs_int32
+VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
+                   afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
                    afs_int32 *atrans)
 {
-    afs_int32 error;
-    register Volume *vp;
-    afs_int32 junk;            /* discardable error code */
-    register afs_int32 volumeID, doCreateRoot = 1;
-    register struct volser_trans *tt;
+    Error error;
+    Volume *vp;
+    Error junk;                /* discardable error code */
+    afs_uint32 volumeID;
+    afs_int32 doCreateRoot = 1;
+    struct volser_trans *tt;
     char ppath[30];
     char caller[MAXKTCNAMELEN];
 
@@ -415,8 +511,11 @@ VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
        return VOLSERBADNAME;
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;
-    if (DoLogging)
-       Log("%s is executing CreateVolume '%s'\n", caller, aname);
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing CreateVolume '%s'\n", caller,
+           callerAddress(acid, buffer), aname);
+    }
     if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
        return error;           /*a standard unix error */
     if (atype != readwriteVolume && atype != readonlyVolume
@@ -440,6 +539,11 @@ VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
     }
     vp = VCreateVolume(&error, ppath, volumeID, aparent);
     if (error) {
+#ifdef AFS_DEMAND_ATTACH_FS
+       if (error != VVOLEXISTS && error != EXDEV) {
+           SalvageUnknownVolume(volumeID, ppath);
+       }
+#endif
        Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
        LogError(error);
        DeleteTrans(tt, 1);
@@ -450,8 +554,17 @@ VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
     V_inService(vp) = V_blessed(vp) = 1;
     V_type(vp) = atype;
     AssignVolumeName(&V_disk(vp), aname, 0);
-    if (doCreateRoot)
-       ViceCreateRoot(vp);
+    if (doCreateRoot) {
+       error = ViceCreateRoot(vp);
+       if (error) {
+           Log("1 Volser: CreateVolume: Unable to create volume root dir; "
+               "error code %u\n", (unsigned)error);
+           DeleteTrans(tt, 1);
+           V_needsSalvaged(vp) = 1;
+           VDetachVolume(&junk, vp);
+           return EIO;
+       }
+    }
     V_destroyMe(vp) = DESTROY_ME;
     V_inService(vp) = 0;
     V_maxquota(vp) = 5000;     /* set a quota of 5000 at init time */
@@ -463,12 +576,13 @@ VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
        VDetachVolume(&junk, vp);       /* rather return the real error code */
        return error;
     }
+    VTRANS_OBJ_LOCK(tt);
     tt->volume = vp;
     *atrans = tt->tid;
-    strcpy(tt->lastProcName, "CreateVolume");
-    tt->rxCallPtr = acid;
+    TSetRxCall_r(tt, acid, "CreateVolume");
+    VTRANS_OBJ_UNLOCK(tt);
     Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
     return 0;
@@ -485,11 +599,11 @@ SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
 {
-    register struct volser_trans *tt;
-    afs_int32 error;
+    struct volser_trans *tt;
+    Error error;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -498,41 +612,50 @@ VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
+       Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
+           afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    if (DoLogging)
-       Log("%s is executing Delete Volume %u\n", caller, tt->volid);
-    strcpy(tt->lastProcName, "DeleteVolume");
-    tt->rxCallPtr = acid;
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
+           callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
+    }
+    TSetRxCall(tt, acid, "DeleteVolume");
     VPurgeVolume(&error, tt->volume);  /* don't check error code, it is not set! */
-    V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
+    V_destroyMe(tt->volume) = DESTROY_ME;
+    if (tt->volume->needsPutBack) {
+       tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
+    }
+    VTRANS_OBJ_LOCK(tt);
     tt->vflags |= VTDeleted;   /* so we know not to do anything else to it */
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall_r(tt);
+    VTRANS_OBJ_UNLOCK(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
-    Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
+    Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
+       afs_printable_VolumeId_lu(tt->volid));
     return 0;                  /* vpurgevolume doesn't set an error code */
 }
 
 /* make a clone of the volume associated with atrans, possibly giving it a new
  * number (allocate a new number if *newNumber==0, otherwise use *newNumber
- * for the clone's id).  The new clone is given the name newName.  Finally, due to
- * efficiency considerations, if purgeId is non-zero, we purge that volume when doing
- * the clone operation.  This may be useful when making new backup volumes, for instance
- * since the net result of a clone and a purge generally leaves many inode ref counts
- * the same, while doing them separately would result in far more iincs and idecs being
- * peformed (and they are slow operations).
+ * for the clone's id).  The new clone is given the name newName.  Finally,
+ * due to efficiency considerations, if purgeId is non-zero, we purge that
+ * volume when doing the clone operation.  This may be useful when making
+ * new backup volumes, for instance since the net result of a clone and a
+ * purge generally leaves many inode ref counts the same, while doing them
+ * separately would result in far more iincs and idecs being peformed
+ * (and they are slow operations).
  */
 /* for efficiency reasons, sometimes faster to piggyback a purge here */
 afs_int32
-SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId, 
-            afs_int32 newType, char *newName, afs_int32 *newNumber)
+SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
+            afs_int32 newType, char *newName, VolumeId *newNumber)
 {
     afs_int32 code;
-
     code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
     osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
               AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
@@ -540,24 +663,29 @@ SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
     return code;
 }
 
-afs_int32
-VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId, 
-            afs_int32 newType, char *newName, afs_int32 *newNumber)
+static afs_int32
+VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
+            afs_int32 newType, char *newName, VolumeId *newNumber)
 {
     VolumeId newId;
-    register struct Volume *originalvp, *purgevp, *newvp;
+    struct Volume *originalvp, *purgevp, *newvp;
     Error error, code;
-    register struct volser_trans *tt, *ttc;
+    struct volser_trans *tt, *ttc;
     char caller[MAXKTCNAMELEN];
+#ifdef AFS_DEMAND_ATTACH_FS
+    struct Volume *salv_vp = NULL;
+#endif
 
     if (strlen(newName) > 31)
        return VOLSERBADNAME;
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;        /*not a super user */
-    if (DoLogging)
-       Log("%s is executing Clone Volume new name=%s\n", caller, newName);
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing Clone Volume new name=%s\n", caller,
+           callerAddress(acid, buffer), newName);
+    }
     error = 0;
-    originalvp = (Volume *) 0;
     purgevp = (Volume *) 0;
     newvp = (Volume *) 0;
     tt = ttc = (struct volser_trans *)0;
@@ -568,50 +696,41 @@ VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
     }
     newId = *newNumber;
 
-    if (newType != readonlyVolume && newType != backupVolume)
-       return EINVAL;
     tt = FindTrans(atrans);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
     ttc = NewTrans(newId, tt->partition);
     if (!ttc) {                        /* someone is messing with the clone already */
        TRELE(tt);
-       return VBUSY;
+       return VOLSERVOLBUSY;
     }
-    strcpy(tt->lastProcName, "Clone");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "Clone");
 
 
     if (purgeId) {
-       purgevp = VAttachVolume(&error, purgeId, V_VOLUPD);
+       purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
        if (error) {
-           Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
+           Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
            goto fail;
        }
     } else {
        purgevp = NULL;
     }
     originalvp = tt->volume;
-    if ((V_type(originalvp) == backupVolume)
-       || (V_type(originalvp) == readonlyVolume)) {
-       Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
-       error = EROFS;
-       goto fail;
-    }
     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
-       Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
-           V_id(originalvp));
+       Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
+           afs_printable_VolumeId_lu(V_id(originalvp)));
        error = VOFFLINE;
        goto fail;
     }
     if (purgevp) {
        if (originalvp->device != purgevp->device) {
-           Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
+           Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n", afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(purgeId));
            error = EXDEV;
            goto fail;
        }
@@ -620,36 +739,37 @@ VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
            error = EINVAL;
            goto fail;
        }
-       if (V_type(originalvp) == readonlyVolume
-           && V_parentId(originalvp) != V_parentId(purgevp)) {
-           Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
-           error = EXDEV;
-           goto fail;
-       }
-       if (V_type(originalvp) == readwriteVolume
-           && tt->volid != V_parentId(purgevp)) {
-           Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
+       if (V_parentId(originalvp) != V_parentId(purgevp)) {
+           Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " and volume %" AFS_VOLID_FMT " were not originally cloned from the same parent; aborted\n", afs_printable_VolumeId_lu(purgeId), afs_printable_VolumeId_lu(tt->volid));
            error = EXDEV;
            goto fail;
        }
     }
 
     error = 0;
+#ifdef AFS_DEMAND_ATTACH_FS
+    salv_vp = originalvp;
+#endif
 
-    newvp =
-       VCreateVolume(&error, originalvp->partition->name, newId,
-                     V_parentId(originalvp));
-    if (error) {
-       Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
-       newvp = (Volume *) 0;
-       goto fail;
+    if (purgeId == newId) {
+       newvp = purgevp;
+    } else {
+       newvp =
+           VCreateVolume(&error, originalvp->partition->name, newId,
+                         V_parentId(originalvp));
+       if (error) {
+           Log("1 Volser: Clone: Couldn't create new volume %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
+               afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
+           newvp = (Volume *) 0;
+           goto fail;
+       }
     }
     if (newType == readonlyVolume)
        V_cloneId(originalvp) = newId;
-    Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
-       newId);
+    Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
+       afs_printable_VolumeId_lu(newId));
     if (purgevp)
-       Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
+       Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
     CloneVolume(&error, originalvp, newvp, purgevp);
     purgevp = NULL;            /* clone releases it, maybe even if error */
     if (error) {
@@ -658,14 +778,12 @@ VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
        goto fail;
     }
     if (newType == readonlyVolume) {
-       AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
        V_type(newvp) = readonlyVolume;
     } else if (newType == backupVolume) {
-       AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
        V_type(newvp) = backupVolume;
        V_backupId(originalvp) = newId;
     }
-    strcpy(newvp->header->diskstuff.name, newName);
+    strcpy(V_name(newvp), newName);
     V_creationDate(newvp) = V_copyDate(newvp);
     ClearVolumeStats(&V_disk(newvp));
     V_destroyMe(newvp) = DESTROY_ME;
@@ -689,7 +807,14 @@ VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
        LogError(error);
        goto fail;
     }
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
+#ifdef AFS_DEMAND_ATTACH_FS
+    salv_vp = NULL;
+#endif
+
+    /* Clients could have callbacks to the clone ID */
+    FSYNC_VolOp(newId, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
+
     if (TRELE(tt)) {
        tt = (struct volser_trans *)0;
        error = VOLSERTRELE_ERROR;
@@ -704,17 +829,22 @@ VolClone(struct rx_call *acid, afs_int32 atrans, afs_int32 purgeId,
     if (newvp)
        VDetachVolume(&code, newvp);
     if (tt) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
     }
     if (ttc)
        DeleteTrans(ttc, 1);
+#ifdef AFS_DEMAND_ATTACH_FS
+    if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
+       V_needsSalvaged(salv_vp) = 1;
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
     return error;
 }
 
 /* reclone this volume into the specified id */
 afs_int32
-SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
+SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
 {
     afs_int32 code;
 
@@ -724,89 +854,77 @@ SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
     return code;
 }
 
-afs_int32
-VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
+static afs_int32
+VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
 {
-    register struct Volume *originalvp, *clonevp;
+    struct Volume *originalvp, *clonevp;
     Error error, code;
     afs_int32 newType;
-    register struct volser_trans *tt, *ttc;
+    struct volser_trans *tt, *ttc;
     char caller[MAXKTCNAMELEN];
+    VolumeDiskData saved_header;
 
     /*not a super user */
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;
-    if (DoLogging)
-       Log("%s is executing Reclone Volume %u\n", caller, cloneId);
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
+           callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
+    }
     error = 0;
     clonevp = originalvp = (Volume *) 0;
-    tt = (struct volser_trans *)0;
 
     tt = FindTrans(atrans);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
     ttc = NewTrans(cloneId, tt->partition);
     if (!ttc) {                        /* someone is messing with the clone already */
        TRELE(tt);
-       return VBUSY;
+       return VOLSERVOLBUSY;
     }
-    strcpy(tt->lastProcName, "ReClone");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "ReClone");
 
     originalvp = tt->volume;
-    if ((V_type(originalvp) == backupVolume)
-       || (V_type(originalvp) == readonlyVolume)) {
-       Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
-       error = EROFS;
-       goto fail;
-    }
     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
-       Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
-           V_id(originalvp));
+       Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
+           afs_printable_VolumeId_lu(V_id(originalvp)));
        error = VOFFLINE;
        goto fail;
     }
 
-    clonevp = VAttachVolume(&error, cloneId, V_VOLUPD);
+    clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
     if (error) {
-       Log("1 Volser: can't attach clone %d\n", cloneId);
+       Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
        goto fail;
     }
 
     newType = V_type(clonevp); /* type of the new volume */
 
     if (originalvp->device != clonevp->device) {
-       Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
-           tt->volid, cloneId);
+       Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
+           afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
        error = EXDEV;
        goto fail;
     }
-    if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
-       Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
-       error = EINVAL;
-       goto fail;
-    }
-    if (V_type(originalvp) == readonlyVolume
-       && V_parentId(originalvp) != V_parentId(clonevp)) {
-       Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
+    if (V_parentId(originalvp) != V_parentId(clonevp)) {
+       Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " was not originally cloned from volume %" AFS_VOLID_FMT "; aborted\n", afs_printable_VolumeId_lu(cloneId), afs_printable_VolumeId_lu(tt->volid));
        error = EXDEV;
        goto fail;
     }
-    if (V_type(originalvp) == readwriteVolume
-       && tt->volid != V_parentId(clonevp)) {
-       Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
-       error = EXDEV;
-       goto fail;
+
+    if (DoPreserveVolumeStats) {
+       CopyVolumeStats(&V_disk(clonevp), &saved_header);
     }
 
     error = 0;
-    Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
-       cloneId);
+    Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
+       afs_printable_VolumeId_lu(cloneId));
     CloneVolume(&error, originalvp, clonevp, clonevp);
     if (error) {
        Log("1 Volser: Clone: reclone operation failed with code %d\n",
@@ -826,15 +944,20 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
     }
     /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
 
-    /* pretend recloned volume is a totally new instance */
-    V_copyDate(clonevp) = time(0);
-    V_creationDate(clonevp) = V_copyDate(clonevp);
-    ClearVolumeStats(&V_disk(clonevp));
+    /* update the creationDate, since this represents the last cloning date
+     * for ROs. But do not update copyDate; let it stay so we can identify
+     * when the clone was first created. */
+    V_creationDate(clonevp) = time(0);
+    if (DoPreserveVolumeStats) {
+       CopyVolumeStats(&saved_header, &V_disk(clonevp));
+    } else {
+       ClearVolumeStats(&V_disk(clonevp));
+    }
     V_destroyMe(clonevp) = 0;
     V_inService(clonevp) = 0;
     if (newType == backupVolume) {
-       V_backupDate(originalvp) = V_copyDate(clonevp);
-       V_backupDate(clonevp) = V_copyDate(clonevp);
+       V_backupDate(originalvp) = V_creationDate(clonevp);
+       V_backupDate(clonevp) = V_creationDate(clonevp);
     }
     V_inUse(clonevp) = 0;
     VUpdateVolume(&error, clonevp);
@@ -843,9 +966,9 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
        LogError(error);
        goto fail;
     }
-    /* VUpdateVolume succeeded. Mark it in service so there's no window 
-     * between FSYNC_VOL_ON and VolSetFlags where it's offline with no  
-     * specialStatus; this is a reclone and this volume started online  
+    /* VUpdateVolume succeeded. Mark it in service so there's no window
+     * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
+     * specialStatus; this is a reclone and this volume started online
      */
     V_inService(clonevp) = 1;
     VDetachVolume(&error, clonevp);    /* allow file server to get it's hands on it */
@@ -856,7 +979,7 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
        LogError(error);
        goto fail;
     }
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt)) {
        tt = (struct volser_trans *)0;
        error = VOLSERTRELE_ERROR;
@@ -875,7 +998,7 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
     if (clonevp)
        VDetachVolume(&code, clonevp);
     if (tt) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
     }
     if (ttc)
@@ -888,7 +1011,7 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
  * See volser.h for definition of iflags (the constants are named IT*).
  */
 afs_int32
-SAFSVolTransCreate(struct rx_call *acid, afs_int32 volume, afs_int32 partition,
+SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
                   afs_int32 iflags, afs_int32 *ttid)
 {
     afs_int32 code;
@@ -899,13 +1022,14 @@ SAFSVolTransCreate(struct rx_call *acid, afs_int32 volume, afs_int32 partition,
     return code;
 }
 
-afs_int32
-VolTransCreate(struct rx_call *acid, afs_int32 volume, afs_int32 partition,
+static afs_int32
+VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
                   afs_int32 iflags, afs_int32 *ttid)
 {
-    register struct volser_trans *tt;
-    register Volume *tv;
-    afs_int32 error, code;
+    struct volser_trans *tt;
+    Volume *tv;
+    afs_int32 error;
+    Error code;
     afs_int32 mode;
     char caller[MAXKTCNAMELEN];
 
@@ -939,11 +1063,13 @@ VolTransCreate(struct rx_call *acid, afs_int32 volume, afs_int32 partition,
        DeleteTrans(tt, 1);
        return error;
     }
+    VTRANS_OBJ_LOCK(tt);
     tt->volume = tv;
     *ttid = tt->tid;
     tt->iflags = iflags;
     tt->vflags = 0;
-    strcpy(tt->lastProcName, "TransCreate");
+    TSetRxCall_r(tt, NULL, "TransCreate");
+    VTRANS_OBJ_UNLOCK(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -954,7 +1080,7 @@ VolTransCreate(struct rx_call *acid, afs_int32 volume, afs_int32 partition,
  * Both the volume number and partition number (one-based) are returned.
  */
 afs_int32
-SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_int32 *avolume,
+SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
                    afs_int32 *apart)
 {
     afs_int32 code;
@@ -964,10 +1090,13 @@ SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_int32 *avolume,
     return code;
 }
 
-afs_int32
-VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_int32 *avolume,
+static afs_int32
+VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
                    afs_int32 *apart)
 {
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     Log("1 Volser: GetNthVolume: Not yet implemented\n");
     return VOLSERNO_OP;
 }
@@ -985,24 +1114,26 @@ SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
 {
-    register struct volser_trans *tt;
+    struct volser_trans *tt;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     tt = FindTrans(atid);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
-           tt->volid);
+       Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
+           afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "GetFlags");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "GetFlags");
     *aflags = tt->vflags;
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -1024,12 +1155,12 @@ SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
 {
-    register struct volser_trans *tt;
-    register struct Volume *vp;
-    afs_int32 error;
+    struct volser_trans *tt;
+    struct Volume *vp;
+    Error error;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -1039,13 +1170,12 @@ VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
-           tt->volid);
+       Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
+           afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "SetFlags");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "SetFlags");
     vp = tt->volume;           /* pull volume out of transaction */
 
     /* check if we're allowed to make any updates */
@@ -1067,7 +1197,10 @@ VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
        V_inService(vp) = 1;
     }
     VUpdateVolume(&error, vp);
+    VTRANS_OBJ_LOCK(tt);
     tt->vflags = aflags;
+    TClearRxCall_r(tt);
+    VTRANS_OBJ_UNLOCK(tt);
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
 
@@ -1080,7 +1213,7 @@ VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
  */
 afs_int32
 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
-              struct destServer *destination, afs_int32 destTrans, 
+              struct destServer *destination, afs_int32 destTrans,
               struct restoreCookie *cookie)
 {
     afs_int32 code;
@@ -1088,44 +1221,70 @@ SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
     code =
        VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
     osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
-              destination->destHost, AUD_LONG, destTrans, AUD_END);
+              htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
     return code;
 }
 
-afs_int32
+static_inline afs_int32
+MakeClient(struct rx_call *acid, struct rx_securityClass **securityObject,
+          afs_int32 *securityIndex)
+{
+    rxkad_level enc_level = rxkad_clear;
+    int docrypt;
+    int code;
+
+    switch (doCrypt) {
+    case VS2SC_ALWAYS:
+       docrypt = 1;
+       break;
+    case VS2SC_INHERIT:
+       rxkad_GetServerInfo(rx_ConnectionOf(acid), &enc_level, 0, 0, 0, 0, 0);
+       docrypt = (enc_level == rxkad_crypt ? 1 : 0);
+       break;
+    case VS2SC_NEVER:
+       docrypt = 0;
+       break;
+    default:
+       opr_Assert(0 && "doCrypt corrupt?");
+    }
+    if (docrypt)
+       code = afsconf_ClientAuthSecure(tdir, securityObject, securityIndex);
+    else
+       code = afsconf_ClientAuth(tdir, securityObject, securityIndex);
+    return code;
+}
+
+static afs_int32
 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
-              struct destServer *destination, afs_int32 destTrans, 
+              struct destServer *destination, afs_int32 destTrans,
               struct restoreCookie *cookie)
 {
-    register struct volser_trans *tt;
-    register afs_int32 code;
-    register struct rx_connection *tcon;
+    struct volser_trans *tt;
+    afs_int32 code;
+    struct rx_connection *tcon;
     struct rx_call *tcall;
-    register struct Volume *vp;
+    struct Volume *vp;
     struct rx_securityClass *securityObject;
     afs_int32 securityIndex;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;        /*not a super user */
-    /* initialize things */
-    tcon = (struct rx_connection *)0;
-    tt = (struct volser_trans *)0;
 
     /* find the local transaction */
     tt = FindTrans(fromTrans);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
     vp = tt->volume;
-    strcpy(tt->lastProcName, "Forward");
+    TSetRxCall(tt, NULL, "Forward");
 
     /* get auth info for the this connection (uses afs from ticket file) */
-    code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
+    code = MakeClient(acid, &securityObject, &securityIndex);
     if (code) {
        TRELE(tt);
        return code;
@@ -1136,13 +1295,16 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
        rx_NewConnection(htonl(destination->destHost),
                         htons(destination->destPort), VOLSERVICE_ID,
                         securityObject, securityIndex);
+
+    RXS_Close(securityObject); /* will be freed after connection destroyed */
+
     if (!tcon) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return ENOTCONN;
     }
     tcall = rx_NewCall(tcon);
-    tt->rxCallPtr = tcall;
+    TSetRxCall(tt, tcall, "Forward");
     /* start restore going.  fromdate == 0 --> doing an incremental dump/restore */
     code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
     if (code) {
@@ -1154,7 +1316,7 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
     if (code)
        goto fail;
     EndAFSVolRestore(tcall);   /* probably doesn't do much */
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     code = rx_EndCall(tcall, 0);
     rx_DestroyConnection(tcon);        /* done with the connection */
     tcon = NULL;
@@ -1171,7 +1333,7 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
        rx_DestroyConnection(tcon);
     }
     if (tt) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
     }
     return code;
@@ -1179,16 +1341,16 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
 
 /* Start a dump and send it to multiple places simultaneously.
  * If this returns an error (eg, return ENOENT), it means that
- * none of the releases worked.  If this returns 0, that means 
+ * none of the releases worked.  If this returns 0, that means
  * that one or more of the releases worked, and the caller has
  * to examine the results array to see which one(s).
  * This will only do EITHER incremental or full, not both, so it's
  * the caller's responsibility to be sure that all the destinations
- * need just an incremental (and from the same time), if that's 
- * what we're doing. 
+ * need just an incremental (and from the same time), if that's
+ * what we're doing.
  */
 afs_int32
-SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32 
+SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
                       fromDate, manyDests *destinations, afs_int32 spare,
                       struct restoreCookie *cookie, manyResults *results)
 {
@@ -1205,9 +1367,8 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
     if (results) {
        memset(results, 0, sizeof(manyResults));
        i = results->manyResults_len = destinations->manyDests_len;
-       results->manyResults_val = codes =
-         (afs_int32 *) malloc(i * sizeof(afs_int32));
-    }  
+       results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
+    }
     if (!results || !results->manyResults_val)
        return ENOMEM;
 
@@ -1217,29 +1378,28 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
     vp = tt->volume;
-    strcpy(tt->lastProcName, "ForwardMulti");
+    TSetRxCall(tt, NULL, "ForwardMulti");
 
     /* (fromDate == 0) ==> full dump */
     is_incremental = (fromDate ? 1 : 0);
 
-    tcons =
-       (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
+    tcons = malloc(i * sizeof(struct rx_connection *));
     if (!tcons) {
        return ENOMEM;
     }
-    tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
+    tcalls = malloc(i * sizeof(struct rx_call *));
     if (!tcalls) {
        free(tcons);
        return ENOMEM;
     }
 
     /* get auth info for this connection (uses afs from ticket file) */
-    code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
+    code = MakeClient(acid, &securityObject, &securityIndex);
     if (code) {
        goto fail;              /* in order to audit each failure */
     }
@@ -1270,6 +1430,9 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
        }
     }
 
+    /* Security object will be freed when all connections destroyed */
+    RXS_Close(securityObject);
+
     /* these next calls implictly call rx_Write when writing out data */
     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
 
@@ -1291,14 +1454,14 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
        }
 
        osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
-                  fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
+                  fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
                   dest->trans, AUD_END);
     }
     free(tcons);
     free(tcalls);
 
     if (tt) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        if (TRELE(tt) && !code) /* return the first code if it's set */
            return VOLSERTRELE_ERROR;
     }
@@ -1317,7 +1480,8 @@ SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
 }
 
 afs_int32
-SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
+SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
+             afs_int32 flags)
 {
     afs_int32 code;
 
@@ -1326,11 +1490,12 @@ SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs
     return code;
 }
 
-afs_int32
-VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
+static afs_int32
+VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
+       afs_int32 flags)
 {
     int code = 0;
-    register struct volser_trans *tt;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -1339,20 +1504,19 @@ VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "Dump");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "Dump");
     code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
                      ? 0 : 1); /* squirt out the volume's data, too */
     if (code) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return code;
     }
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
 
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
@@ -1360,26 +1524,25 @@ VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32
     return 0;
 }
 
-/* 
+/*
  * Ha!  No more helper process!
  */
 afs_int32
-SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
+SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
               struct restoreCookie *cookie)
 {
     afs_int32 code;
 
-    code = VolRestore(acid, atrans, aflags, cookie);
+    code = VolRestore(acid, atrans, cookie);
     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
     return code;
 }
 
-afs_int32
-VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
-              struct restoreCookie *cookie)
+static afs_int32
+VolRestore(struct rx_call *acid, afs_int32 atrans, struct restoreCookie *cookie)
 {
-    register struct volser_trans *tt;
-    register afs_int32 code, tcode;
+    struct volser_trans *tt;
+    afs_int32 code, tcode;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -1388,18 +1551,22 @@ VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "Restore");
-    tt->rxCallPtr = acid;
+    if (DoLogging) {
+       char buffer[16];
+       Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
+           callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
+    }
+    TSetRxCall(tt, acid, "Restore");
 
     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
 
-    code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);      /* last is incrementalp */
+    code = RestoreVolume(acid, tt->volume, cookie);
     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     tcode = TRELE(tt);
 
     return (code ? code : tcode);
@@ -1416,10 +1583,10 @@ SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
 {
-    register struct volser_trans *tt;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -1441,14 +1608,14 @@ SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
 
     code = VolSetForwarding(acid, atid, anewsite);
     osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
-              anewsite, AUD_END);
+              htonl(anewsite), AUD_END);
     return code;
 }
 
-afs_int32
+static afs_int32
 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
 {
-    register struct volser_trans *tt;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
     char partName[16];
 
@@ -1458,18 +1625,17 @@ VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
-           tt->volid);
+       Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
+           afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "SetForwarding");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "SetForwarding");
     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
        partName[0] = '\0';
     }
     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -1477,8 +1643,8 @@ VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
 }
 
 afs_int32
-SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans, 
-                register struct volser_status *astatus)
+SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
+                struct volser_status *astatus)
 {
     afs_int32 code;
 
@@ -1487,34 +1653,35 @@ SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
     return code;
 }
 
-afs_int32
-VolGetStatus(struct rx_call *acid, afs_int32 atrans, 
-                register struct volser_status *astatus)
+static afs_int32
+VolGetStatus(struct rx_call *acid, afs_int32 atrans,
+            struct volser_status *astatus)
 {
-    register struct Volume *tv;
-    register struct VolumeDiskData *td;
+    struct Volume *tv;
+    struct VolumeDiskData *td;
     struct volser_trans *tt;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     tt = FindTrans(atrans);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
-           tt->volid);
+       Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
+           afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "GetStatus");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "GetStatus");
     tv = tt->volume;
     if (!tv) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return ENOENT;
     }
 
-    td = &tv->header->diskstuff;
+    td = &(V_disk(tv));
     astatus->volID = td->id;
     astatus->nextUnique = td->uniquifier;
     astatus->type = td->type;
@@ -1531,7 +1698,7 @@ VolGetStatus(struct rx_call *acid, afs_int32 atrans,
     astatus->expirationDate = td->expirationDate;
     astatus->backupDate = td->backupDate;
     astatus->copyDate = td->copyDate;
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -1539,8 +1706,8 @@ VolGetStatus(struct rx_call *acid, afs_int32 atrans,
 }
 
 afs_int32
-SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans, 
-              register struct volintInfo *astatus)
+SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
+              struct volintInfo *astatus)
 {
     afs_int32 code;
 
@@ -1549,15 +1716,15 @@ SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
     return code;
 }
 
-afs_int32
-VolSetInfo(struct rx_call *acid, afs_int32 atrans, 
-              register struct volintInfo *astatus)
+static afs_int32
+VolSetInfo(struct rx_call *acid, afs_int32 atrans,
+              struct volintInfo *astatus)
 {
-    register struct Volume *tv;
-    register struct VolumeDiskData *td;
+    struct Volume *tv;
+    struct VolumeDiskData *td;
     struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
-    afs_int32 error;
+    Error error;
 
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;        /*not a super user */
@@ -1565,20 +1732,19 @@ VolSetInfo(struct rx_call *acid, afs_int32 atrans,
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "SetStatus");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "SetStatus");
     tv = tt->volume;
     if (!tv) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return ENOENT;
     }
 
-    td = &tv->header->diskstuff;
+    td = &(V_disk(tv));
     /*
      * Add more fields as necessary
      */
@@ -1593,7 +1759,7 @@ VolSetInfo(struct rx_call *acid, afs_int32 atrans,
     if (astatus->spare2 != -1)
        td->volUpdateCounter = (unsigned int)astatus->spare2;
     VUpdateVolume(&error, tv);
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
     return 0;
@@ -1610,45 +1776,47 @@ SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
 {
-    register struct Volume *tv;
-    register struct VolumeDiskData *td;
+    struct Volume *tv;
+    struct VolumeDiskData *td;
     struct volser_trans *tt;
-    register int len;
+    int len;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     /* We need to at least fill it in */
-    *aname = (char *)malloc(1);
+    *aname = malloc(1);
     if (!*aname)
        return ENOMEM;
     tt = FindTrans(atrans);
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "GetName");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "GetName");
     tv = tt->volume;
     if (!tv) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return ENOENT;
     }
 
-    td = &tv->header->diskstuff;
+    td = &(V_disk(tv));
     len = strlen(td->name) + 1;        /* don't forget the null */
     if (len >= SIZE) {
-       tt->rxCallPtr = (struct rx_call *)0;
+        TClearRxCall(tt);
        TRELE(tt);
        return E2BIG;
     }
-    *aname = (char *)realloc(*aname, len);
+    *aname = realloc(*aname, len);
     strcpy(*aname, td->name);
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -1658,8 +1826,8 @@ VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
 /*this is a handshake to indicate that the next call will be SAFSVolRestore
  * - a noop now !*/
 afs_int32
-SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType, 
-                    afs_int32 parentId, afs_int32 cloneId)
+SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
+                    VolumeId parentId, VolumeId cloneId)
 {
     return 0;
 }
@@ -1677,11 +1845,14 @@ SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
 {
     char namehead[9];
-    char i;
+    int i;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     strcpy(namehead, "/vicep");        /*7 including null terminator */
 
@@ -1707,14 +1878,16 @@ SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
     return code;
 }
 
-afs_int32
+static afs_int32
 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
 {
-    struct stat rbuf, pbuf;
     char namehead[9];
     struct partList partList;
     struct DiskPartition64 *dp;
-    int i, j = 0, k;
+    int i, j = 0;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     strcpy(namehead, "/vicep");        /*7 including null terminator */
 
@@ -1727,6 +1900,8 @@ XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
            namehead[6] = i + 'a';
            namehead[7] = '\0';
        } else {
+           int k;
+
            k = i - 26;
            namehead[6] = 'a' + (k / 26);
            namehead[7] = 'a' + (k % 26);
@@ -1737,54 +1912,45 @@ XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
        if (dp)
            partList.partId[j++] = i;
     }
-    pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
-    if (!pEntries->partEntries_val)
-       return ENOMEM;
-    memcpy((char *)pEntries->partEntries_val, (char *)&partList,
-          j * sizeof(int));
-    pEntries->partEntries_len = j;
+    if (j > 0) {
+       pEntries->partEntries_val = malloc(j * sizeof(int));
+       if (!pEntries->partEntries_val)
+           return ENOMEM;
+       memcpy(pEntries->partEntries_val, partList.partId,
+               j * sizeof(int));
+       pEntries->partEntries_len = j;
+    } else {
+       pEntries->partEntries_val = NULL;
+       pEntries->partEntries_len = 0;
+    }
     return 0;
 
 }
 
-/*extract the volume id from string vname. Its of the form " V0*<id>.vol  "*/
-afs_int32
-ExtractVolId(char vname[])
-{
-    int i;
-    char name[VOLSER_MAXVOLNAME + 1];
-
-    strcpy(name, vname);
-    i = 0;
-    while (name[i] == 'V' || name[i] == '0')
-       i++;
-
-    name[11] = '\0';           /* smash the "." */
-    return (atol(&name[i]));
-}
-
-/*return the name of the next volume header in the directory associated with dirp and dp.
-*the volume id is  returned in volid, and volume header name is returned in volname*/
-int
-GetNextVol(DIR * dirp, char *volname, afs_int32 * volid)
+/*
+ * Scan a directory for possible volume headers.
+ * in: DIR *dirp               -- a directory handle from opendir()
+ * out: char *volname          -- set to name of directory entry
+ *      afs_uint32 *volid      -- set to volume ID parsed from name
+ * returns:
+ *  true if volname and volid have been set to valid values
+ *  false if we got to the end of the directory
+ */
+static int
+GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
 {
     struct dirent *dp;
 
-    dp = readdir(dirp);                /*read next entry in the directory */
-    if (dp) {
-       if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
-           *volid = ExtractVolId(dp->d_name);
+    while ((dp = readdir(dirp)) != NULL) {
+       /* could be optimized on platforms with dp->d_namlen */
+       if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
+               && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
+           *volid = VolumeNumber(dp->d_name);
            strcpy(volname, dp->d_name);
-           return 0;           /*return the name of the file representing a volume */
-       } else {
-           strcpy(volname, "");
-           return 0;           /*volname doesnot represent a volume */
+           return 1;
        }
-    } else {
-       strcpy(volname, "EOD");
-       return 0;               /*end of directory */
     }
-
+    return 0;
 }
 
 /**
@@ -1847,7 +2013,7 @@ static int
 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
 {
     unsigned int numStatBytes, now;
-    register struct VolumeDiskData *hdr = &vp->header->diskstuff;
+    struct VolumeDiskData *hdr = &(V_disk(vp));
 
     /*read in the relevant info */
     strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
@@ -1882,13 +2048,13 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
      *   -- tkeiser 11/27/2007
      */
 
-    /* Conditions that offline status is based on: 
+    /* Conditions that offline status is based on:
                volume is unattached state
                volume state is in (one of several error states)
                volume not in service
                volume is not marked as blessed (not on hold)
                volume in salvage req. state
-               volume needsSalvaged 
+               volume needsSalvaged
                next op would set volume offline
                next op would not leave volume online (based on several conditions)
     */
@@ -1896,11 +2062,11 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
        (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
        VIsErrorState(V_attachState(vp)) ||
        !hdr->inService ||
-       !hdr->blessed || 
+       !hdr->blessed ||
        (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
        hdr->needsSalvaged ||
-       (vp->pending_vol_op && 
-               (vp->pending_vol_op->com.command == FSYNC_VOL_OFF || 
+       (vp->pending_vol_op &&
+               (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
                !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
        )
        ) {
@@ -1924,7 +2090,7 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
 
 #ifdef AFS_DEMAND_ATTACH_FS
        /* see comment above where we set inUse bit */
-       if (hdr->needsSalvaged || 
+       if (hdr->needsSalvaged ||
            (vp && VIsErrorState(V_attachState(vp)))) {
            handle->volinfo_ptr.base->needsSalvaged = 1;
        } else {
@@ -1935,7 +2101,7 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
 #endif
        handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
        handle->volinfo_ptr.base->spare0 = hdr->minquota;
-       handle->volinfo_ptr.base->spare1 = 
+       handle->volinfo_ptr.base->spare1 =
            (long)hdr->weekUse[0] +
            (long)hdr->weekUse[1] +
            (long)hdr->weekUse[2] +
@@ -1958,11 +2124,11 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
         * Copy out the stat fields in a single operation.
         */
        if ((now - hdr->dayUseDate) > OneDay) {
-           memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
+           memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
                   0, numStatBytes);
        } else {
            memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
-                  (char *)&(hdr->stat_reads[0]), 
+                  (char *)&(hdr->stat_reads[0]),
                   numStatBytes);
        }
        break;
@@ -1971,12 +2137,14 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
     return 0;
 }
 
+#ifdef AFS_DEMAND_ATTACH_FS
+
 /**
  * get struct Volume out of the fileserver.
  *
  * @param[in] volumeId  volumeId for which we want state information
  * @param[in] pname     partition name string
- * @param[inout] vp     pointer to pointer to Volume object which 
+ * @param[inout] vp     pointer to pointer to Volume object which
  *                      will be populated (see note)
  *
  * @return operation status
@@ -1988,7 +2156,7 @@ FillVolInfo(Volume * vp, volint_info_handle_t * handle)
  * @internal
  */
 static int
-GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
+GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
 {
     int code;
     SYNC_response res;
@@ -2016,6 +2184,8 @@ GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
     return code;
 }
 
+#endif
+
 /**
  * mode of volume list operation.
  */
@@ -2042,15 +2212,14 @@ typedef enum {
  */
 static int
 GetVolInfo(afs_uint32 partId,
-          afs_uint32 volumeId,
-          char * pname, 
-          char * volname, 
+          VolumeId volumeId,
+          char * pname,
+          char * volname,
           volint_info_handle_t * handle,
           vol_info_list_mode_t mode)
 {
     int code = -1;
-    int reason;
-    afs_int32 error;
+    Error error;
     struct volser_trans *ttc = NULL;
     struct Volume *fill_tv, *tv = NULL;
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -2074,10 +2243,20 @@ GetVolInfo(afs_uint32 partId,
     }
 
     /* Get volume from volserver */
-    tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
+    if (mode == VOL_INFO_LIST_MULTIPLE)
+       tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
+    else {
+#ifdef AFS_DEMAND_ATTACH_FS
+       int mode = V_PEEK;
+#else
+       int mode = V_READONLY;   /* informs the fileserver to update the volume headers. */
+#endif
+       tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
+    }
+
     if (error) {
-       Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n", 
-           volumeId, pname, volname, error);
+       Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
+           afs_printable_VolumeId_lu(volumeId), pname, volname, error);
        goto drop;
     }
 
@@ -2088,35 +2267,37 @@ GetVolInfo(afs_uint32 partId,
      *   -- tkeiser 11/28/2007
      */
 
-    if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
+    if (V_destroyMe(tv) == DESTROY_ME) {
        switch (mode) {
        case VOL_INFO_LIST_MULTIPLE:
            code = -2;
            goto drop;
 
        case VOL_INFO_LIST_SINGLE:
-           Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n", 
-               volumeId, pname, volname);
+           Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
+               afs_printable_VolumeId_lu(volumeId), pname, volname);
+           goto drop;
 
        default:
            goto drop;
        }
     }
 
-    if (tv->header->diskstuff.needsSalvaged) {
+    if (V_needsSalvaged(tv)) {
        /*this volume will be salvaged */
-       Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n", 
-           volumeId, pname, volname);
+       Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
+           afs_printable_VolumeId_lu(volumeId), pname, volname);
     }
 
 #ifdef AFS_DEMAND_ATTACH_FS
     /* If using DAFS, get volume from fsserver */
-    if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
+    if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
+
        goto drop;
     }
 
     /* fs_tv is a shallow copy, must populate certain structures before passing along */
-    if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) { 
+    if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
        /* If we if the pending vol op */
        memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
        fs_tv->pending_vol_op=&pending_vol_op_res;
@@ -2129,7 +2310,7 @@ GetVolInfo(afs_uint32 partId,
 
     /* When using DAFS, use the fs volume info, populated with required structures */
     fill_tv = fs_tv;
-#else 
+#else
     /* When not using DAFS, just use the local volume info */
     fill_tv = tv;
 #endif
@@ -2149,8 +2330,8 @@ GetVolInfo(afs_uint32 partId,
        if (error) {
            VOLINT_INFO_STORE(handle, status, 0);
            strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
-           Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
-               volumeId, pname, volname);
+           Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
+               afs_printable_VolumeId_lu(volumeId), pname, volname);
        }
     }
     if (ttc) {
@@ -2163,8 +2344,8 @@ GetVolInfo(afs_uint32 partId,
 
 /*return the header information about the <volid> */
 afs_int32
-SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32 
-                    volumeId, volEntries *volumeInfo)
+SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
+                     VolumeId volumeId, volEntries *volumeInfo)
 {
     afs_int32 code;
 
@@ -2173,27 +2354,24 @@ SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
     return code;
 }
 
-afs_int32
-VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32 
-                    volumeId, volEntries *volumeInfo)
+static afs_int32
+VolListOneVolume(struct rx_call *acid, afs_int32 partid,
+                 VolumeId volumeId, volEntries *volumeInfo)
 {
-    volintInfo *pntr;
     struct DiskPartition64 *partP;
     char pname[9], volname[20];
-    afs_int32 error = 0;
     DIR *dirp;
-    afs_int32 volid;
+    VolumeId volid;
     int found = 0;
-    unsigned int now;
-    int code;
     volint_info_handle_t handle;
 
-    volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
+    volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
     if (!volumeInfo->volEntries_val)
        return ENOMEM;
-    memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
 
-    pntr = volumeInfo->volEntries_val;
     volumeInfo->volEntries_len = 1;
     if (GetPartName(partid, pname))
        return VOLSERILLEGAL_PARTITION;
@@ -2203,21 +2381,11 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
 
-    strcpy(volname, "");
-
-    while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
-
-       if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
-           GetNextVol(dirp, volname, &volid);
-           continue;           /*back to while loop */
-       }
-
+    while (GetNextVol(dirp, volname, &volid)) {
        if (volid == volumeId) {        /*copy other things too */
            found = 1;
            break;
        }
-
-       GetNextVol(dirp, volname, &volid);
     }
 
     if (found) {
@@ -2227,13 +2395,17 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
 
        handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
        handle.volinfo_ptr.base = volumeInfo->volEntries_val;
-       
-       code = GetVolInfo(partid, 
-                         volid, 
-                         pname, 
-                         volname,
-                         &handle,
-                         VOL_INFO_LIST_SINGLE);
+
+       /* The return code from GetVolInfo is ignored; there is no error from
+        * it that results in the whole call being aborted. Any volume
+        * attachment failures are reported in 'status' field in the
+        * volumeInfo payload. */
+       GetVolInfo(partid,
+                  volid,
+                  pname,
+                  volname,
+                  &handle,
+                  VOL_INFO_LIST_SINGLE);
     }
 
     closedir(dirp);
@@ -2264,8 +2436,8 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
  *------------------------------------------------------------------------*/
 
 afs_int32
-SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
-                     afs_int32 a_volID, volXEntries *a_volumeXInfoP)
+SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
+                     VolumeId a_volID, volXEntries *a_volumeXInfoP)
 {
     afs_int32 code;
 
@@ -2274,35 +2446,30 @@ SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
     return code;
 }
 
-afs_int32
-VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
-                     afs_int32 a_volID, volXEntries *a_volumeXInfoP)
+static afs_int32
+VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
+                  VolumeId a_volID, volXEntries *a_volumeXInfoP)
 {                              /*SAFSVolXListOneVolume */
 
-    volintXInfo *xInfoP;       /*Ptr to the extended vol info */
     struct DiskPartition64 *partP;     /*Ptr to partition */
     char pname[9], volname[20];        /*Partition, volume names */
-    afs_int32 error;           /*Error code */
     DIR *dirp;                 /*Partition directory ptr */
-    afs_int32 currVolID;       /*Current volume ID */
+    VolumeId currVolID;                /*Current volume ID */
     int found = 0;             /*Did we find the volume we need? */
-    unsigned int now;
-    int code;
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     /*
      * Set up our pointers for action, marking our structure to hold exactly
      * one entry.  Also, assume we'll fail in our quest.
      */
-    a_volumeXInfoP->volXEntries_val =
-       (volintXInfo *) malloc(sizeof(volintXInfo));
+    a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
     if (!a_volumeXInfoP->volXEntries_val)
        return ENOMEM;
-    memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
 
-    xInfoP = a_volumeXInfoP->volXEntries_val;
     a_volumeXInfoP->volXEntries_len = 1;
-    code = ENODEV;
 
     /*
      * If the partition name we've been given is bad, bogue out.
@@ -2320,23 +2487,13 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
     if (dirp == NULL)
        return (VOLSERILLEGAL_PARTITION);
 
-    strcpy(volname, "");
 
     /*
      * Sweep through the partition directory, looking for the desired entry.
      * First, of course, figure out how many stat bytes to copy out of each
      * volume.
      */
-    while (strcmp(volname, "EOD") && !found) {
-       /*
-        * If this is not a volume, move on to the next entry in the
-        * partition's directory.
-        */
-       if (!strcmp(volname, "")) {
-           GetNextVol(dirp, volname, &currVolID);
-           continue;
-       }
-
+    while (GetNextVol(dirp, volname, &currVolID)) {
        if (currVolID == a_volID) {
            /*
             * We found the volume entry we're interested.  Pull out the
@@ -2346,8 +2503,6 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
            found = 1;
            break;
        }                       /*Found desired volume */
-
-       GetNextVol(dirp, volname, &currVolID);
     }
 
     if (found) {
@@ -2358,13 +2513,16 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
        handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
        handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
 
-       code = GetVolInfo(a_partID,
-                         a_volID,
-                         pname,
-                         volname,
-                         &handle,
-                         VOL_INFO_LIST_SINGLE);
-
+       /* The return code from GetVolInfo is ignored; there is no error from
+        * it that results in the whole call being aborted. Any volume
+        * attachment failures are reported in 'status' field in the
+        * volumeInfo payload. */
+       GetVolInfo(a_partID,
+                  a_volID,
+                  pname,
+                  volname,
+                  &handle,
+                  VOL_INFO_LIST_SINGLE);
     }
 
     /*
@@ -2375,10 +2533,10 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
     return (found) ? 0 : ENODEV;
 }                              /*SAFSVolXListOneVolume */
 
-/*returns all the volumes on partition partid. If flags = 1 then all the 
+/*returns all the volumes on partition partid. If flags = 1 then all the
 * relevant info about the volumes  is also returned */
 afs_int32
-SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
+SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
                   volEntries *volumeInfo)
 {
     afs_int32 code;
@@ -2388,26 +2546,25 @@ SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
     return code;
 }
 
-afs_int32
-VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
+static afs_int32
+VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
                   volEntries *volumeInfo)
 {
     volintInfo *pntr;
     struct DiskPartition64 *partP;
     afs_int32 allocSize = 1000;        /*to be changed to a larger figure */
     char pname[9], volname[20];
-    afs_int32 error = 0;
     DIR *dirp;
-    afs_int32 volid;
-    unsigned int now;
+    VolumeId volid;
     int code;
     volint_info_handle_t handle;
 
-    volumeInfo->volEntries_val =
-       (volintInfo *) malloc(allocSize * sizeof(volintInfo));
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
+    volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
     if (!volumeInfo->volEntries_val)
        return ENOMEM;
-    memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
 
     pntr = volumeInfo->volEntries_val;
     volumeInfo->volEntries_len = 0;
@@ -2418,15 +2575,8 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
     dirp = opendir(VPartitionPath(partP));
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
-    strcpy(volname, "");
-
-    while (strcmp(volname, "EOD")) {   /*while there are more partitions in the partition */
-
-       if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
-           GetNextVol(dirp, volname, &volid);
-           continue;           /*back to while loop */
-       }
 
+    while (GetNextVol(dirp, volname, &volid)) {
        if (flags) {            /*copy other things too */
 #ifndef AFS_PTHREAD_ENV
            IOMGR_Poll();       /*make sure that the client does not time out */
@@ -2442,36 +2592,28 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
                              volname,
                              &handle,
                              VOL_INFO_LIST_MULTIPLE);
-           if (code == -2) { /* DESTROY_ME flag set */
-               goto drop2;
-           }
+           if (code == -2)     /* DESTROY_ME flag set */
+               continue;
        } else {
            pntr->volid = volid;
            /*just volids are needed */
        }
 
-      drop:
        pntr++;
        volumeInfo->volEntries_len += 1;
        if ((allocSize - volumeInfo->volEntries_len) < 5) {
            /*running out of space, allocate more space */
            allocSize = (allocSize * 3) / 2;
-           pntr =
-               (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
-                                      allocSize * sizeof(volintInfo));
+           pntr = realloc(volumeInfo->volEntries_val,
+                          allocSize * sizeof(volintInfo));
            if (pntr == NULL) {
-               closedir(dirp); 
+               closedir(dirp);
                return VOLSERNO_MEMORY;
            }
            volumeInfo->volEntries_val = pntr;  /* point to new block */
            /* set pntr to the right position */
            pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
-
        }
-
-      drop2:
-       GetNextVol(dirp, volname, &volid);
-
     }
 
     closedir(dirp);
@@ -2516,7 +2658,7 @@ SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
     return code;
 }
 
-afs_int32
+static afs_int32
 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
                    afs_int32 a_flags, volXEntries *a_volumeXInfoP)
 {                              /*SAFSVolXListVolumes */
@@ -2525,22 +2667,21 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
     struct DiskPartition64 *partP;     /*Ptr to partition */
     afs_int32 allocSize = 1000;        /*To be changed to a larger figure */
     char pname[9], volname[20];        /*Partition, volume names */
-    afs_int32 error = 0;       /*Return code */
     DIR *dirp;                 /*Partition directory ptr */
-    afs_int32 volid;           /*Current volume ID */
-    unsigned int now;
+    VolumeId volid;            /*Current volume ID */
     int code;
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     /*
      * Allocate a large array of extended volume info structures, then
      * set it up for action.
      */
-    a_volumeXInfoP->volXEntries_val =
-       (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
+    a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
     if (!a_volumeXInfoP->volXEntries_val)
        return ENOMEM;
-    memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
 
     xInfoP = a_volumeXInfoP->volXEntries_val;
     a_volumeXInfoP->volXEntries_len = 0;
@@ -2560,23 +2701,7 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
     dirp = opendir(VPartitionPath(partP));
     if (dirp == NULL)
        return (VOLSERILLEGAL_PARTITION);
-    strcpy(volname, "");
-
-    /*
-     * Sweep through the partition directory, acting on each entry.  First,
-     * of course, figure out how many stat bytes to copy out of each volume.
-     */
-    while (strcmp(volname, "EOD")) {
-
-       /*
-        * If this is not a volume, move on to the next entry in the
-        * partition's directory.
-        */
-       if (!strcmp(volname, "")) {
-           GetNextVol(dirp, volname, &volid);
-           continue;
-       }
-
+    while (GetNextVol(dirp, volname, &volid)) {
        if (a_flags) {
            /*
             * Full info about the volume desired.  Poll to make sure the
@@ -2595,9 +2720,8 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
                              volname,
                              &handle,
                              VOL_INFO_LIST_MULTIPLE);
-           if (code == -2) { /* DESTROY_ME flag set */
-               goto drop2;
-           }
+           if (code == -2)     /* DESTROY_ME flag set */
+               continue;
        } else {
            /*
             * Just volume IDs are needed.
@@ -2605,7 +2729,6 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
            xInfoP->volid = volid;
        }
 
-      drop:
        /*
         * Bump the pointer in the data area we're building, along with
         * the count of the number of entries it contains.
@@ -2638,10 +2761,7 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
                a_volumeXInfoP->volXEntries_val +
                a_volumeXInfoP->volXEntries_len;
        }
-
-      drop2:
-       GetNextVol(dirp, volname, &volid);
-    }                          /*Sweep through the partition directory */
+    }
 
     /*
      * We've examined all entries in the partition directory.  Close it,
@@ -2664,23 +2784,32 @@ SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
 {
     transDebugInfo *pntr;
     afs_int32 allocSize = 50;
-    struct volser_trans *tt, *allTrans;
+    afs_int32 code = 0;
+    struct volser_trans *tt, *nt, *allTrans;
+
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     transInfo->transDebugEntries_val =
-       (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
+       malloc(allocSize * sizeof(transDebugInfo));
     if (!transInfo->transDebugEntries_val)
        return ENOMEM;
     pntr = transInfo->transDebugEntries_val;
     transInfo->transDebugEntries_len = 0;
+
+    VTRANS_LOCK;
     allTrans = TransList();
     if (allTrans == (struct volser_trans *)0)
-       return 0;               /*no active transactions */
-    for (tt = allTrans; tt; tt = tt->next) {   /*copy relevant info into pntr */
+       goto done;              /*no active transactions */
+    for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
+       nt = tt->next;
+       memset(pntr, 0, sizeof(*pntr));
+        VTRANS_OBJ_LOCK(tt);
        pntr->tid = tt->tid;
        pntr->time = tt->time;
        pntr->creationTime = tt->creationTime;
@@ -2694,20 +2823,20 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
        pntr->callValid = 0;
        if (tt->rxCallPtr) {    /*record call related info */
            pntr->callValid = 1;
-           pntr->readNext = tt->rxCallPtr->rnext;
-           pntr->transmitNext = tt->rxCallPtr->tnext;
-           pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
-           pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
+           rx_GetCallStatus(tt->rxCallPtr, &(pntr->readNext), &(pntr->transmitNext),
+                               &(pntr->lastSendTime), &(pntr->lastReceiveTime));
        }
+        VTRANS_OBJ_UNLOCK(tt);
        pntr++;
        transInfo->transDebugEntries_len += 1;
        if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
            allocSize = (allocSize * 3) / 2;
-           pntr =
-               (transDebugInfo *) realloc((char *)transInfo->
-                                          transDebugEntries_val,
-                                          allocSize *
-                                          sizeof(transDebugInfo));
+           pntr = realloc(transInfo->transDebugEntries_val,
+                          allocSize * sizeof(transDebugInfo));
+           if (pntr == NULL) {
+               code = ENOMEM;
+               goto done;
+           }
            transInfo->transDebugEntries_val = pntr;
            pntr =
                transInfo->transDebugEntries_val +
@@ -2716,12 +2845,16 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
        }
 
     }
+done:
+    VTRANS_UNLOCK;
 
-    return 0;
+    return code;
 }
 
 afs_int32
-SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_int32 pId, afs_int32 cloneId, afs_int32 backupId)
+SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
+                  afs_int32 type, afs_uint32 pId, VolumeId cloneId,
+                  VolumeId backupId)
 {
     afs_int32 code;
 
@@ -2732,12 +2865,14 @@ SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32
     return code;
 }
 
-afs_int32
-VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_int32 pId, afs_int32 cloneId, afs_int32 backupId)
+static afs_int32
+VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
+              afs_int32 type, VolumeId pId, VolumeId cloneId,
+              VolumeId backupId)
 {
     struct Volume *tv;
-    afs_int32 error = 0;
-    register struct volser_trans *tt;
+    Error error = 0;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
 
     if (strlen(name) > 31)
@@ -2749,12 +2884,11 @@ VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "SetIdsTypes");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "SetIdsTypes");
     tv = tt->volume;
 
     V_type(tv) = type;
@@ -2768,13 +2902,13 @@ VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type
        LogError(error);
        goto fail;
     }
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
 
     return error;
   fail:
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
     return error;
@@ -2791,12 +2925,12 @@ SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
     return code;
 }
 
-afs_int32
+static afs_int32
 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
 {
     struct Volume *tv;
-    afs_int32 error = 0;
-    register struct volser_trans *tt;
+    Error error = 0;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -2806,12 +2940,11 @@ VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
     if (!tt)
        return ENOENT;
     if (tt->vflags & VTDeleted) {
-       Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
+       Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "SetDate");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "SetDate");
     tv = tt->volume;
 
     V_creationDate(tv) = cdate;
@@ -2821,13 +2954,13 @@ VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
        LogError(error);
        goto fail;
     }
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
 
     return error;
   fail:
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
     return error;
@@ -2835,18 +2968,18 @@ VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
 
 afs_int32
 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
-                          afs_int32 volumeId)
+                          VolumeId volumeId)
 {
 #ifdef AFS_NT40_ENV
     return EXDEV;
 #else
     char caller[MAXKTCNAMELEN];
     DIR *dirp;
-    register struct volser_trans *ttc;
+    struct volser_trans *ttc;
     char pname[16], volname[20];
     struct DiskPartition64 *partP;
     afs_int32 ret = ENODEV;
-    afs_int32 volid;
+    VolumeId volid;
 
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;        /*not a super user */
@@ -2857,22 +2990,17 @@ SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
     dirp = opendir(VPartitionPath(partP));
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
-    strcpy(volname, "");
     ttc = (struct volser_trans *)0;
 
-    while (strcmp(volname, "EOD")) {
-       if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
-            GetNextVol(dirp, volname, &volid);
-            continue;           /*back to while loop */
-        }
-       
+    while (GetNextVol(dirp, volname, &volid)) {
        if (volid == volumeId) {        /*copy other things too */
 #ifndef AFS_PTHREAD_ENV
             IOMGR_Poll();       /*make sure that the client doesnot time out */
 #endif
             ttc = NewTrans(volumeId, partId);
             if (!ttc) {
-               return VBUSY;
+               ret = VOLSERVOLBUSY;
+               goto done;
             }
 #ifdef AFS_NAMEI_ENV
            ret = namei_ConvertROtoRWvolume(pname, volumeId);
@@ -2881,14 +3009,11 @@ SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
 #endif
            break;
        }
-       GetNextVol(dirp, volname, &volid);
     }
-    
-    if (ttc) {
+  done:
+    if (ttc)
         DeleteTrans(ttc, 1);
-        ttc = (struct volser_trans *)0;
-    }
-    
+
     closedir(dirp);
     return ret;
 #endif
@@ -2896,10 +3021,10 @@ SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
 
 afs_int32
 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
-              register struct volintSize *size)
+              struct volintSize *size)
 {
     int code = 0;
-    register struct volser_trans *tt;
+    struct volser_trans *tt;
     char caller[MAXKTCNAMELEN];
 
     if (!afsconf_SuperUser(tdir, acid, caller))
@@ -2911,10 +3036,9 @@ SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
        TRELE(tt);
        return ENOENT;
     }
-    strcpy(tt->lastProcName, "GetSize");
-    tt->rxCallPtr = acid;
+    TSetRxCall(tt, acid, "GetSize");
     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size);        /* measure volume's data */
-    tt->rxCallPtr = (struct rx_call *)0;
+    TClearRxCall(tt);
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
 
@@ -2922,6 +3046,101 @@ SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
     return code;
 }
 
+afs_int32
+SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 ovid, afs_uint32 onew,
+                  afs_uint32 where, afs_int32 verbose)
+{
+#if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
+    Error code, code2;
+    Volume *vol=0, *newvol=0;
+    struct volser_trans *tt = 0, *tt2 = 0;
+    char caller[MAXKTCNAMELEN];
+    char line[128];
+    VolumeId new = onew;
+    VolumeId vid = ovid;
+
+    if (!afsconf_SuperUser(tdir, acall, caller))
+        return EPERM;
+
+    vol = VAttachVolume(&code, vid, V_VOLUPD);
+    if (!vol) {
+        if (!code)
+            code = ENOENT;
+        return code;
+    }
+    newvol = VAttachVolume(&code, new, V_VOLUPD);
+    if (!newvol) {
+        VDetachVolume(&code2, vol);
+        if (!code)
+            code = ENOENT;
+        return code;
+    }
+    if (V_device(vol) != V_device(newvol)
+       || V_uniquifier(newvol) != 2) {
+        if (V_device(vol) != V_device(newvol)) {
+            sprintf(line, "Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are not in the same partition, aborted.\n",
+                   afs_printable_VolumeId_lu(vid),
+                   afs_printable_VolumeId_lu(new));
+            rx_Write(acall, line, strlen(line));
+        }
+        if (V_uniquifier(newvol) != 2) {
+            sprintf(line, "Volume %" AFS_VOLID_FMT " is not freshly created, aborted.\n",
+                   afs_printable_VolumeId_lu(new));
+            rx_Write(acall, line, strlen(line));
+        }
+        line[0] = 0;
+        rx_Write(acall, line, 1);
+        VDetachVolume(&code2, vol);
+        VDetachVolume(&code2, newvol);
+        return EINVAL;
+    }
+    tt = NewTrans(vid, V_device(vol));
+    if (!tt) {
+        sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
+               afs_printable_VolumeId_lu(vid));
+        rx_Write(acall, line, strlen(line));
+        line[0] = 0;
+        rx_Write(acall, line, 1);
+        VDetachVolume(&code2, vol);
+        VDetachVolume(&code2, newvol);
+        return VOLSERVOLBUSY;
+    }
+    VTRANS_OBJ_LOCK(tt);
+    tt->iflags = ITBusy;
+    tt->vflags = 0;
+    TSetRxCall_r(tt, NULL, "SplitVolume");
+    VTRANS_OBJ_UNLOCK(tt);
+
+    tt2 = NewTrans(new, V_device(newvol));
+    if (!tt2) {
+        sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
+               afs_printable_VolumeId_lu(new));
+        rx_Write(acall, line, strlen(line));
+        line[0] = 0;
+        rx_Write(acall, line, 1);
+        DeleteTrans(tt, 1);
+        VDetachVolume(&code2, vol);
+        VDetachVolume(&code2, newvol);
+        return VOLSERVOLBUSY;
+    }
+    VTRANS_OBJ_LOCK(tt2);
+    tt2->iflags = ITBusy;
+    tt2->vflags = 0;
+    TSetRxCall_r(tt2, NULL, "SplitVolume");
+    VTRANS_OBJ_UNLOCK(tt2);
+
+    code = split_volume(acall, vol, newvol, where, verbose);
+
+    VDetachVolume(&code2, vol);
+    DeleteTrans(tt, 1);
+    VDetachVolume(&code2, newvol);
+    DeleteTrans(tt2, 1);
+    return code;
+#else
+    return VOLSERBADOP;
+#endif
+}
+
 /* GetPartName - map partid (a decimal number) into pname (a string)
  * Since for NT we actually want to return the drive name, we map through the
  * partition struct.