dafs-vol-updates-20080210
[openafs.git] / src / volser / volprocs.c
index ae1664f..c020648 100644 (file)
@@ -5,6 +5,8 @@
  * 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
+ *
+ * Portions Copyright (c) 2007-2008 Sine Nomine Associates
  */
 
 #include <afsconfig.h>
@@ -15,6 +17,7 @@ RCSID
 
 #include <stdio.h>
 #include <sys/types.h>
+#include <string.h>
 #include <errno.h>
 #ifdef AFS_NT40_ENV
 #include <fcntl.h>
@@ -25,14 +28,6 @@ RCSID
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-
 #include <dirent.h>
 #include <sys/stat.h>
 #include <rx/xdr.h>
@@ -49,7 +44,6 @@ RCSID
 #include <afs/nfs.h>
 #include <lwp.h>
 #include <lock.h>
-#include <afs/auth.h>
 #include <afs/cellconfig.h>
 #include <afs/keys.h>
 #include <ubik.h>
@@ -59,8 +53,10 @@ RCSID
 #endif
 #include <afs/vnode.h>
 #include <afs/volume.h>
+#include <afs/volume_inline.h>
 #include <afs/partition.h>
 #include "vol.h"
+#include <afs/daemon_com.h>
 #include <afs/fssync.h>
 #include <afs/acl.h>
 #include "afs/audit.h"
@@ -198,7 +194,7 @@ XAttachVolume(afs_int32 *error, afs_int32 avolid, afs_int32 apartid, int amode)
        *error = EINVAL;
        return NULL;
     }
-    tv = VAttachVolumeByName(error, pbuf, vbuf, amode);
+    tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
     return tv;
 }
 
@@ -210,14 +206,14 @@ ViceCreateRoot(Volume *vp)
     struct acl_accessList *ACL;
     ViceFid did;
     Inode inodeNumber, nearInode;
-    char buf[SIZEOF_LARGEDISKVNODE];
-    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
+    struct VnodeDiskObject *vnode;
     struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
     IHandle_t *h;
     FdHandle_t *fdP;
     int code;
     afs_fsize_t length;
 
+    vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
     memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
 
     V_pref(vp, nearInode);
@@ -282,6 +278,7 @@ ViceCreateRoot(Volume *vp)
     VNDISK_GET_LEN(length, vnode);
     V_diskused(vp) = nBlocks(length);
 
+    free(vnode);
     return 1;
 }
 
@@ -490,6 +487,7 @@ VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
     strcpy(tt->lastProcName, "DeleteVolume");
     tt->rxCallPtr = acid;
     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 */
     tt->vflags |= VTDeleted;   /* so we know not to do anything else to it */
     tt->rxCallPtr = (struct rx_call *)0;
     if (TRELE(tt))
@@ -844,7 +842,7 @@ VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
 
     {
        struct DiskPartition *tpartp = originalvp->partition;
-       FSYNC_askfs(cloneId, tpartp->name, FSYNC_RESTOREVOLUME, 0);
+       FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
     }
     return 0;
 
@@ -1045,7 +1043,6 @@ VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
     }
     VUpdateVolume(&error, vp);
     tt->vflags = aflags;
-    tt->rxCallPtr = (struct rx_call *)0;
     if (TRELE(tt) && !error)
        return VOLSERTRELE_ERROR;
 
@@ -1196,7 +1193,7 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
     vp = tt->volume;
     strcpy(tt->lastProcName, "ForwardMulti");
 
-    /* (fromDate == 0) ==> incremental dump */
+    /* (fromDate == 0) ==> full dump */
     is_incremental = (fromDate ? 1 : 0);
 
     i = results->manyResults_len = destinations->manyDests_len;
@@ -1279,13 +1276,23 @@ SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
 {
     afs_int32 code;
 
-    code = VolDump(acid, fromTrans, fromDate);
+    code = VolDump(acid, fromTrans, fromDate, 0);
+    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
+    return code;
+}
+
+afs_int32
+SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
+{
+    afs_int32 code;
+
+    code = VolDump(acid, fromTrans, fromDate, flags);
     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
     return code;
 }
 
 afs_int32
-VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
+VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
 {
     int code = 0;
     register struct volser_trans *tt;
@@ -1303,7 +1310,8 @@ VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
     }
     strcpy(tt->lastProcName, "Dump");
     tt->rxCallPtr = acid;
-    code = DumpVolume(acid, tt->volume, fromDate, 1);  /* squirt out the volume's data, too */
+    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;
        TRELE(tt);
@@ -1355,8 +1363,7 @@ VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
 
     code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);      /* last is incrementalp */
-    FSYNC_askfs(tt->volid, NULL, FSYNC_RESTOREVOLUME, 0l);     /*break call backs on the
-                                                                * restored volume */
+    FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
     tt->rxCallPtr = (struct rx_call *)0;
     tcode = TRELE(tt);
 
@@ -1422,7 +1429,7 @@ VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
     }
     strcpy(tt->lastProcName, "SetForwarding");
     tt->rxCallPtr = acid;
-    FSYNC_askfs(tt->volid, NULL, FSYNC_MOVEVOLUME, anewsite);
+    FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_MOVE, anewsite, NULL);
     tt->rxCallPtr = (struct rx_call *)0;
     if (TRELE(tt))
        return VOLSERTRELE_ERROR;
@@ -1640,8 +1647,7 @@ VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
     namehead[7] = '\0';
     for (i = 0; i < 26; i++) {
        namehead[6] = i + 'a';
-       if (VGetPartition(namehead, 0))
-           partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
+       partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
     }
 
     return 0;
@@ -1672,6 +1678,9 @@ XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
 
     /* Only report attached partitions */
     for (i = 0; i < VOLMAXPARTS; i++) {
+#ifdef AFS_DEMAND_ATTACH_FS
+       dp = VGetPartitionById(i, 0);
+#else
        if (i < 26) {
            namehead[6] = i + 'a';
            namehead[7] = '\0';
@@ -1682,6 +1691,7 @@ XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
            namehead[8] = '\0';
        }
        dp = VGetPartition(namehead, 0);
+#endif
        if (dp)
            partList.partId[j++] = i;
     }
@@ -1733,6 +1743,304 @@ GetNextVol(DIR * dirp, char *volname, afs_int32 * volid)
 
 }
 
+/**
+ * volint vol info structure type.
+ */
+typedef enum {
+    VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
+    VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
+} volint_info_type_t;
+
+/**
+ * handle to various on-wire vol info types.
+ */
+typedef struct {
+    volint_info_type_t volinfo_type;
+    union {
+       void * opaque;
+       volintInfo * base;
+       volintXInfo * ext;
+    } volinfo_ptr;
+} volint_info_handle_t;
+
+/**
+ * store value to a field at the appropriate location in on-wire structure.
+ */
+#define VOLINT_INFO_STORE(handle, name, val) \
+    do { \
+        if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
+            (handle)->volinfo_ptr.base->name = (val); \
+        } else { \
+            (handle)->volinfo_ptr.ext->name = (val); \
+        } \
+    } while(0)
+
+/**
+ * get pointer to appropriate offset of field in on-wire structure.
+ */
+#define VOLINT_INFO_PTR(handle, name) \
+    (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
+     &((handle)->volinfo_ptr.base->name) : \
+     &((handle)->volinfo_ptr.ext->name))
+
+/**
+ * fill in appropriate type of on-wire volume metadata structure.
+ *
+ * @param vp      pointer to volume object
+ * @param hdr     pointer to volume disk data object
+ * @param handle  pointer to wire format handle object
+ *
+ * @pre handle object must have a valid pointer and enumeration value
+ *
+ * @return operation status
+ *   @retval 0 success
+ *   @retval 1 failure
+ */
+static int
+FillVolInfo(Volume * vp, VolumeDiskData * hdr, volint_info_handle_t * handle)
+{
+    unsigned int numStatBytes, now;
+
+    /*read in the relevant info */
+    strcpy(VOLINT_INFO_PTR(handle, name), hdr->name);
+    VOLINT_INFO_STORE(handle, status, VOK);    /*its ok */
+    VOLINT_INFO_STORE(handle, volid, hdr->id);
+    VOLINT_INFO_STORE(handle, type, hdr->type);        /*if ro volume */
+    VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);  /*if rw volume */
+    VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
+    VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
+    VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
+    VOLINT_INFO_STORE(handle, size, hdr->diskused);
+    VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
+    VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
+    now = FT_ApproxTime();
+    if ((now - hdr->dayUseDate) > OneDay) {
+       VOLINT_INFO_STORE(handle, dayUse, 0);
+    } else {
+       VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
+    }
+    VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
+    VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
+    VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
+    VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    /*
+     * for DAFS, we "lie" about volume state --
+     * instead of returning the raw state from the disk header,
+     * we compute state based upon the fileserver's internal
+     * in-core state enumeration value reported to us via fssync,
+     * along with the blessed and inService flags from the header.
+     *   -- tkeiser 11/27/2007
+     */
+    if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
+       VIsErrorState(V_attachState(vp)) ||
+       !hdr->inService ||
+       !hdr->blessed) {
+       VOLINT_INFO_STORE(handle, inUse, 0);
+    } else {
+       VOLINT_INFO_STORE(handle, inUse, 1);
+    }
+#else
+    VOLINT_INFO_STORE(handle, inUse, hdr->inUse);
+#endif
+
+
+    switch(handle->volinfo_type) {
+    case VOLINT_INFO_TYPE_BASE:
+
+#ifdef AFS_DEMAND_ATTACH_FS
+       /* see comment above where we set inUse bit */
+       if (hdr->needsSalvaged || VIsErrorState(V_attachState(vp))) {
+           handle->volinfo_ptr.base->needsSalvaged = 1;
+       } else {
+           handle->volinfo_ptr.base->needsSalvaged = 0;
+       }
+#else
+       handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
+#endif
+       handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
+       handle->volinfo_ptr.base->spare0 = hdr->minquota;
+       handle->volinfo_ptr.base->spare1 = 
+           (long)hdr->weekUse[0] +
+           (long)hdr->weekUse[1] +
+           (long)hdr->weekUse[2] +
+           (long)hdr->weekUse[3] +
+           (long)hdr->weekUse[4] +
+           (long)hdr->weekUse[5] +
+           (long)hdr->weekUse[6];
+       handle->volinfo_ptr.base->flags = 0;
+       handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
+       handle->volinfo_ptr.base->spare3 = 0;
+       break;
+
+
+    case VOLINT_INFO_TYPE_EXT:
+       numStatBytes =
+           4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
+                (4 * VOLINT_STATS_NUM_TIME_FIELDS));
+
+       /*
+        * Copy out the stat fields in a single operation.
+        */
+       if ((now - hdr->dayUseDate) > OneDay) {
+           memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
+                  0, numStatBytes);
+       } else {
+           memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
+                  (char *)&(hdr->stat_reads[0]), 
+                  numStatBytes);
+       }
+       break;
+    }
+
+    return 0;
+}
+
+/**
+ * get struct Volume out of the fileserver.
+ *
+ * @param[in] volumeId  volumeId for which we want state information
+ * @param[out] vp       pointer to Volume object
+ *
+ * @return operation status
+ *   @retval 0 success
+ *   @retval nonzero failure
+ */
+static int
+GetVolObject(afs_uint32 volumeId, Volume * vp)
+{
+    int code;
+    SYNC_response res;
+
+    res.hdr.response_len = sizeof(res.hdr);
+    res.payload.buf = vp;
+    res.payload.len = sizeof(*vp);
+
+    code = FSYNC_VolOp(volumeId,
+                      "",
+                      FSYNC_VOL_QUERY,
+                      0,
+                      &res);
+
+    return code;
+}
+
+/**
+ * mode of volume list operation.
+ */
+typedef enum {
+    VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
+    VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
+} vol_info_list_mode_t;
+
+/**
+ * abstract interface to populate wire-format volume metadata structures.
+ *
+ * @param[in]  partId    partition id
+ * @param[in]  volumeId  volume id
+ * @param[in]  pname     partition name
+ * @param[in]  volname   volume file name
+ * @param[in]  handle    handle to on-wire volume metadata object
+ * @param[in]  mode      listing mode
+ *
+ * @return operation status
+ *   @retval 0      success
+ *   @retval -2     DESTROY_ME flag is set
+ *   @retval -1     general failure; some data filled in
+ *   @retval -3     couldn't create vtrans; some data filled in
+ */
+static int
+GetVolInfo(afs_uint32 partId,
+          afs_uint32 volumeId,
+          char * pname, 
+          char * volname, 
+          volint_info_handle_t * handle,
+          vol_info_list_mode_t mode)
+{
+    int code = -1;
+    afs_int32 error;
+    struct volser_trans *ttc = NULL;
+    struct Volume fs_tv, *tv = NULL;
+
+    ttc = NewTrans(volumeId, partId);
+    if (!ttc) {
+       code = -3;
+       VOLINT_INFO_STORE(handle, status, VBUSY);
+       VOLINT_INFO_STORE(handle, volid, volumeId);
+       goto drop;
+    }
+
+    tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
+    if (error) {
+       Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n", 
+           volumeId, pname, volname, error);
+       goto drop;
+    }
+
+    /*
+     * please note that destroyMe and needsSalvaged checks used to be ordered
+     * in the opposite manner for ListVolumes and XListVolumes.  I think it's
+     * more correct to check destroyMe before needsSalvaged.
+     *   -- tkeiser 11/28/2007
+     */
+
+    if (tv->header->diskstuff.destroyMe == 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);
+
+       default:
+           goto drop;
+       }
+    }
+
+    if (tv->header->diskstuff.needsSalvaged) {
+       /*this volume will be salvaged */
+       Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n", 
+           volumeId, pname, volname);
+       goto drop;
+    }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    if (GetVolObject(volumeId, &fs_tv)) {
+       goto drop;
+    }
+#endif
+
+    /* ok, we have all the data we need; fill in the on-wire struct */
+    code = FillVolInfo(&fs_tv, &tv->header->diskstuff, handle);
+
+
+ drop:
+    if (code == -1) {
+       VOLINT_INFO_STORE(handle, status, 0);
+       strcpy(VOLINT_INFO_PTR(handle, name), volname);
+       VOLINT_INFO_STORE(handle, volid, volumeId);
+    }
+    if (tv) {
+       VDetachVolume(&error, tv);
+       tv = NULL;
+       if (error) {
+           VOLINT_INFO_STORE(handle, status, 0);
+           strcpy(VOLINT_INFO_PTR(handle, name), volname);
+           Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
+               volumeId, pname, volname);
+       }
+    }
+    if (ttc) {
+       DeleteTrans(ttc, 1);
+       ttc = NULL;
+    }
+    return code;
+}
+
+
 /*return the header information about the <volid> */
 afs_int32
 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32 
@@ -1750,15 +2058,15 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
                     volumeId, volEntries *volumeInfo)
 {
     volintInfo *pntr;
-    register struct Volume *tv;
     struct DiskPartition *partP;
-    struct volser_trans *ttc;
     char pname[9], volname[20];
     afs_int32 error = 0;
     DIR *dirp;
     afs_int32 volid;
     int found = 0;
     unsigned int now;
+    int code;
+    volint_info_handle_t handle;
 
     volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
     pntr = volumeInfo->volEntries_val;
@@ -1770,9 +2078,8 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
     dirp = opendir(VPartitionPath(partP));
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
+
     strcpy(volname, "");
-    ttc = (struct volser_trans *)0;
-    tv = (Volume *) 0;         /* volume not attached */
 
     while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
 
@@ -1783,103 +2090,30 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32
 
        if (volid == volumeId) {        /*copy other things too */
            found = 1;
-#ifndef AFS_PTHREAD_ENV
-           IOMGR_Poll();       /*make sure that the client doesnot time out */
-#endif
-           ttc = NewTrans(volid, partid);
-           if (!ttc) {
-               pntr->status = VBUSY;
-               pntr->volid = volid;
-               goto drop;
-           }
-           tv = VAttachVolumeByName(&error, pname, volname, V_READONLY);
-           if (error) {
-               pntr->status = 0;       /*things are messed up */
-               strcpy(pntr->name, volname);
-               pntr->volid = volid;
-               Log("1 Volser: ListVolumes: Could not attach volume %u (%s:%s), error=%d\n", volid, pname, volname, error);
-               goto drop;
-           }
-           if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
-               /*this volume will be salvaged */
-               pntr->status = 0;
-               strcpy(pntr->name, volname);
-               pntr->volid = volid;
-               Log("1 Volser: ListVolumes: Volume %u (%s) will be destroyed on next salvage\n", volid, volname);
-               goto drop;
-           }
-
-           if (tv->header->diskstuff.needsSalvaged) {
-               /*this volume will be salvaged */
-               pntr->status = 0;
-               strcpy(pntr->name, volname);
-               pntr->volid = volid;
-               Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n", volid, volname);
-               goto drop;
-           }
-
-           /*read in the relevant info */
-           pntr->status = VOK; /*its ok */
-           pntr->volid = tv->header->diskstuff.id;
-           strcpy(pntr->name, tv->header->diskstuff.name);
-           pntr->type = tv->header->diskstuff.type;    /*if ro volume */
-           pntr->cloneID = tv->header->diskstuff.cloneId;      /*if rw volume */
-           pntr->backupID = tv->header->diskstuff.backupId;
-           pntr->parentID = tv->header->diskstuff.parentId;
-           pntr->copyDate = tv->header->diskstuff.copyDate;
-           pntr->inUse = tv->header->diskstuff.inUse;
-           pntr->size = tv->header->diskstuff.diskused;
-           pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged;
-           pntr->destroyMe = tv->header->diskstuff.destroyMe;
-           pntr->maxquota = tv->header->diskstuff.maxquota;
-           pntr->filecount = tv->header->diskstuff.filecount;
-           now = FT_ApproxTime();
-           if (now - tv->header->diskstuff.dayUseDate > OneDay)
-               pntr->dayUse = 0;
-           else
-               pntr->dayUse = tv->header->diskstuff.dayUse;
-           pntr->creationDate = tv->header->diskstuff.creationDate;
-           pntr->accessDate = tv->header->diskstuff.accessDate;
-           pntr->updateDate = tv->header->diskstuff.updateDate;
-           pntr->backupDate = tv->header->diskstuff.backupDate;
-           pntr->spare0 = tv->header->diskstuff.minquota;
-           pntr->spare1 =
-               (long)tv->header->diskstuff.weekUse[0] +
-               (long)tv->header->diskstuff.weekUse[1] +
-               (long)tv->header->diskstuff.weekUse[2] +
-               (long)tv->header->diskstuff.weekUse[3] +
-               (long)tv->header->diskstuff.weekUse[4] +
-               (long)tv->header->diskstuff.weekUse[5] +
-               (long)tv->header->diskstuff.weekUse[6];
-           pntr->spare2 = V_volUpCounter(tv);
-           pntr->flags = pntr->spare3 = (long)0;
-           VDetachVolume(&error, tv);  /*free the volume */
-           tv = (Volume *) 0;
-           if (error) {
-               pntr->status = 0;       /*things are messed up */
-               strcpy(pntr->name, volname);
-               Log("1 Volser: ListVolumes: Could not detach volume %s\n",
-                   volname);
-               goto drop;
-           }
+           break;
        }
+
        GetNextVol(dirp, volname, &volid);
     }
-  drop:
-    if (tv) {
-       VDetachVolume(&error, tv);
-       tv = (Volume *) 0;
-    }
-    if (ttc) {
-       DeleteTrans(ttc, 1);
-       ttc = (struct volser_trans *)0;
+
+    if (found) {
+#ifndef AFS_PTHREAD_ENV
+       IOMGR_Poll();   /*make sure that the client does not time out */
+#endif
+
+       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);
     }
 
     closedir(dirp);
-    if (found)
-       return 0;
-    else
-       return ENODEV;
+    return (found) ? 0 : ENODEV;
 }
 
 /*------------------------------------------------------------------------
@@ -1922,18 +2156,15 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
 {                              /*SAFSVolXListOneVolume */
 
     volintXInfo *xInfoP;       /*Ptr to the extended vol info */
-    register struct Volume *tv;        /*Volume ptr */
-    struct volser_trans *ttc;  /*Volume transaction ptr */
     struct DiskPartition *partP;       /*Ptr to partition */
     char pname[9], volname[20];        /*Partition, volume names */
     afs_int32 error;           /*Error code */
-    afs_int32 code;            /*Return code */
     DIR *dirp;                 /*Partition directory ptr */
     afs_int32 currVolID;       /*Current volume ID */
     int found = 0;             /*Did we find the volume we need? */
-    struct VolumeDiskData *volDiskDataP;       /*Ptr to on-disk volume data */
-    int numStatBytes;          /*Num stat bytes to copy per volume */
     unsigned int now;
+    int code;
+    volint_info_handle_t handle;
 
     /*
      * Set up our pointers for action, marking our structure to hold exactly
@@ -1961,18 +2192,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.
      */
-    numStatBytes =
-       4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
-            (4 * VOLINT_STATS_NUM_TIME_FIELDS));
-    strcpy(volname, "");
-    ttc = (struct volser_trans *)0;    /*No transaction yet */
-    tv = (Volume *) 0;         /*Volume not yet attached */
-
     while (strcmp(volname, "EOD") && !found) {
        /*
         * If this is not a volume, move on to the next entry in the
@@ -1990,120 +2216,27 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
             * doesn't time out) and to set up a transaction on the volume.
             */
            found = 1;
-#ifndef AFS_PTHREAD_ENV
-           IOMGR_Poll();
-#endif
-           ttc = NewTrans(currVolID, a_partID);
-           if (!ttc) {
-               /*
-                * Couldn't get a transaction on this volume; let our caller
-                * know it's busy.
-                */
-               xInfoP->status = VBUSY;
-               xInfoP->volid = currVolID;
-               goto drop;
-           }
-
-           /*
-            * Attach the volume, give up on the volume if we can't.
-            */
-           tv = VAttachVolumeByName(&error, pname, volname, V_READONLY);
-           if (error) {
-               xInfoP->status = 0;     /*things are messed up */
-               strcpy(xInfoP->name, volname);
-               xInfoP->volid = currVolID;
-               Log("1 Volser: XListOneVolume: Could not attach volume %u\n",
-                   currVolID);
-               goto drop;
-           }
-
-           /*
-            * Also bag out on this volume if it's been marked as needing a
-            * salvage or to-be-destroyed.
-            */
-           volDiskDataP = &(tv->header->diskstuff);
-           if (volDiskDataP->destroyMe == DESTROY_ME) {
-               xInfoP->status = 0;
-               strcpy(xInfoP->name, volname);
-               xInfoP->volid = currVolID;
-               Log("1 Volser: XListOneVolume: Volume %u will be destroyed on next salvage\n", currVolID);
-               goto drop;
-           }
+           break;
+       }                       /*Found desired volume */
 
-           if (volDiskDataP->needsSalvaged) {
-               xInfoP->status = 0;
-               strcpy(xInfoP->name, volname);
-               xInfoP->volid = currVolID;
-               Log("1 Volser: XListOneVolume: Volume %u needs to be salvaged\n", currVolID);
-               goto drop;
-           }
+       GetNextVol(dirp, volname, &currVolID);
+    }
 
-           /*
-            * Pull out the desired info and stuff it into the area we'll be
-            * returning to our caller.
-            */
-           strcpy(xInfoP->name, volDiskDataP->name);
-           xInfoP->volid = volDiskDataP->id;
-           xInfoP->type = volDiskDataP->type;
-           xInfoP->backupID = volDiskDataP->backupId;
-           xInfoP->parentID = volDiskDataP->parentId;
-           xInfoP->cloneID = volDiskDataP->cloneId;
-           xInfoP->status = VOK;
-           xInfoP->copyDate = volDiskDataP->copyDate;
-           xInfoP->inUse = volDiskDataP->inUse;
-           xInfoP->creationDate = volDiskDataP->creationDate;
-           xInfoP->accessDate = volDiskDataP->accessDate;
-           xInfoP->updateDate = volDiskDataP->updateDate;
-           xInfoP->backupDate = volDiskDataP->backupDate;
-           now = FT_ApproxTime();
-           if (now - volDiskDataP->dayUseDate > OneDay)
-               xInfoP->dayUse = 0;
-           else
-               xInfoP->dayUse = volDiskDataP->dayUse;
-           xInfoP->filecount = volDiskDataP->filecount;
-           xInfoP->maxquota = volDiskDataP->maxquota;
-           xInfoP->size = volDiskDataP->diskused;
+    if (found) {
+#ifndef AFS_PTHREAD_ENV
+       IOMGR_Poll();
+#endif
 
-           /*
-            * Copy out the stat fields in a single operation.
-            */
-           memcpy((char *)&(xInfoP->stat_reads[0]),
-                  (char *)&(volDiskDataP->stat_reads[0]), numStatBytes);
+       handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
+       handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
 
-           /*
-            * We're done copying.  Detach the volume and iterate (at this
-            * point, since we found our volume, we'll then drop out of the
-            * loop).
-            */
-           VDetachVolume(&error, tv);
-           tv = (Volume *) 0;
-           if (error) {
-               xInfoP->status = 0;
-               strcpy(xInfoP->name, volname);
-               Log("1 Volser: XListOneVolumes Couldn't detach volume %s\n",
-                   volname);
-               goto drop;
-           }
+       code = GetVolInfo(a_partID,
+                         a_volID,
+                         pname,
+                         volname,
+                         &handle,
+                         VOL_INFO_LIST_SINGLE);
 
-           /*
-            * At this point, we're golden.
-            */
-           code = 0;
-       }                       /*Found desired volume */
-       GetNextVol(dirp, volname, &currVolID);
-    }
-
-    /*
-     * Drop the transaction we have for this volume.
-     */
-  drop:
-    if (tv) {
-       VDetachVolume(&error, tv);
-       tv = (Volume *) 0;
-    }
-    if (ttc) {
-       DeleteTrans(ttc, 1);
-       ttc = (struct volser_trans *)0;
     }
 
     /*
@@ -2111,8 +2244,7 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
      * return the proper value.
      */
     closedir(dirp);
-    return (code);
-
+    return (found) ? 0 : ENODEV;
 }                              /*SAFSVolXListOneVolume */
 
 /*returns all the volumes on partition partid. If flags = 1 then all the 
@@ -2133,15 +2265,15 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
                   volEntries *volumeInfo)
 {
     volintInfo *pntr;
-    register struct Volume *tv;
     struct DiskPartition *partP;
-    struct volser_trans *ttc;
     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;
+    int code;
+    volint_info_handle_t handle;
 
     volumeInfo->volEntries_val =
        (volintInfo *) malloc(allocSize * sizeof(volintInfo));
@@ -2155,9 +2287,8 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
     strcpy(volname, "");
+
     while (strcmp(volname, "EOD")) {   /*while there are more partitions in the partition */
-       ttc = (struct volser_trans *)0; /* new one for each pass */
-       tv = (Volume *) 0;      /* volume not attached */
 
        if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
            GetNextVol(dirp, volname, &volid);
@@ -2166,88 +2297,28 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
 
        if (flags) {            /*copy other things too */
 #ifndef AFS_PTHREAD_ENV
-           IOMGR_Poll();       /*make sure that the client doesnot time out */
+           IOMGR_Poll();       /*make sure that the client does not time out */
 #endif
-           ttc = NewTrans(volid, partid);
-           if (!ttc) {
-               pntr->status = VBUSY;
-               pntr->volid = volid;
-               goto drop;
-           }
-           tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
-           if (error) {
-               pntr->status = 0;       /*things are messed up */
-               strcpy(pntr->name, volname);
-               pntr->volid = volid;
-               Log("1 Volser: ListVolumes: Could not attach volume %u (%s) error=%d\n", volid, volname, error);
-               goto drop;
-           }
-           if (tv->header->diskstuff.needsSalvaged) {
-               /*this volume will be salvaged */
-               pntr->status = 0;
-               strcpy(pntr->name, volname);
-               pntr->volid = volid;
-               Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n", volid, volname);
-               goto drop;
-           }
 
-           if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
-               /*this volume will be salvaged */
+           handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
+           handle.volinfo_ptr.base = pntr;
+
+
+           code = GetVolInfo(partid,
+                             volid,
+                             pname,
+                             volname,
+                             &handle,
+                             VOL_INFO_LIST_MULTIPLE);
+           if (code == -2) { /* DESTROY_ME flag set */
                goto drop2;
            }
-           /*read in the relevant info */
-           pntr->status = VOK; /*its ok */
-           pntr->volid = tv->header->diskstuff.id;
-           strcpy(pntr->name, tv->header->diskstuff.name);
-           pntr->type = tv->header->diskstuff.type;    /*if ro volume */
-           pntr->cloneID = tv->header->diskstuff.cloneId;      /*if rw volume */
-           pntr->backupID = tv->header->diskstuff.backupId;
-           pntr->parentID = tv->header->diskstuff.parentId;
-           pntr->copyDate = tv->header->diskstuff.copyDate;
-           pntr->inUse = tv->header->diskstuff.inUse;
-           pntr->size = tv->header->diskstuff.diskused;
-           pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged;
-           pntr->maxquota = tv->header->diskstuff.maxquota;
-           pntr->filecount = tv->header->diskstuff.filecount;
-           now = FT_ApproxTime();
-           if (now - tv->header->diskstuff.dayUseDate > OneDay)
-               pntr->dayUse = 0;
-           else
-               pntr->dayUse = tv->header->diskstuff.dayUse;
-           pntr->creationDate = tv->header->diskstuff.creationDate;
-           pntr->accessDate = tv->header->diskstuff.accessDate;
-           pntr->updateDate = tv->header->diskstuff.updateDate;
-           pntr->backupDate = tv->header->diskstuff.backupDate;
-           pntr->spare0 = tv->header->diskstuff.minquota;
-           pntr->spare1 =
-               (long)tv->header->diskstuff.weekUse[0] +
-               (long)tv->header->diskstuff.weekUse[1] +
-               (long)tv->header->diskstuff.weekUse[2] +
-               (long)tv->header->diskstuff.weekUse[3] +
-               (long)tv->header->diskstuff.weekUse[4] +
-               (long)tv->header->diskstuff.weekUse[5] +
-               (long)tv->header->diskstuff.weekUse[6];
-           pntr->spare2 = V_volUpCounter(tv);
-           pntr->flags = pntr->spare3 = (long)0;
-           VDetachVolume(&error, tv);  /*free the volume */
-           tv = (Volume *) 0;
-           if (error) {
-               pntr->status = 0;       /*things are messed up */
-               strcpy(pntr->name, volname);
-               Log("1 Volser: ListVolumes: Could not detach volume %s\n",
-                   volname);
-               goto drop;
-           }
        } else {
            pntr->volid = volid;
            /*just volids are needed */
        }
 
       drop:
-       if (ttc) {
-           DeleteTrans(ttc, 1);
-           ttc = (struct volser_trans *)0;
-       }
        pntr++;
        volumeInfo->volEntries_len += 1;
        if ((allocSize - volumeInfo->volEntries_len) < 5) {
@@ -2257,15 +2328,7 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
                (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
                                       allocSize * sizeof(volintInfo));
            if (pntr == NULL) {
-               if (tv) {
-                   VDetachVolume(&error, tv);
-                   tv = (Volume *) 0;
-               }
-               if (ttc) {
-                   DeleteTrans(ttc, 1);
-                   ttc = (struct volser_trans *)0;
-               }
-               closedir(dirp);
+               closedir(dirp); 
                return VOLSERNO_MEMORY;
            }
            volumeInfo->volEntries_val = pntr;  /* point to new block */
@@ -2275,21 +2338,11 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
        }
 
       drop2:
-       if (tv) {
-           VDetachVolume(&error, tv);
-           tv = (Volume *) 0;
-       }
-       if (ttc) {
-           DeleteTrans(ttc, 1);
-           ttc = (struct volser_trans *)0;
-       }
        GetNextVol(dirp, volname, &volid);
 
     }
-    closedir(dirp);
-    if (ttc)
-       DeleteTrans(ttc, 1);
 
+    closedir(dirp);
     return 0;
 }
 
@@ -2337,17 +2390,15 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
 {                              /*SAFSVolXListVolumes */
 
     volintXInfo *xInfoP;       /*Ptr to the extended vol info */
-    register struct Volume *tv;        /*Volume ptr */
     struct DiskPartition *partP;       /*Ptr to partition */
-    struct volser_trans *ttc;  /*Volume transaction ptr */
     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 */
-    struct VolumeDiskData *volDiskDataP;       /*Ptr to on-disk volume data */
-    int numStatBytes;          /*Num stat bytes to copy per volume */
     unsigned int now;
+    int code;
+    volint_info_handle_t handle;
 
     /*
      * Allocate a large array of extended volume info structures, then
@@ -2373,18 +2424,13 @@ 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.
      */
-    numStatBytes =
-       4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
-            (4 * VOLINT_STATS_NUM_TIME_FIELDS));
-    strcpy(volname, "");
     while (strcmp(volname, "EOD")) {
-       ttc = (struct volser_trans *)0; /*New one for each pass */
-       tv = (Volume *) 0;      /*Volume not yet attached */
 
        /*
         * If this is not a volume, move on to the next entry in the
@@ -2403,106 +2449,27 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
 #ifndef AFS_PTHREAD_ENV
            IOMGR_Poll();
 #endif
-           ttc = NewTrans(volid, a_partID);
-           if (!ttc) {
-               /*
-                * Couldn't get a transaction on this volume; let our caller
-                * know it's busy.
-                */
-               xInfoP->status = VBUSY;
-               xInfoP->volid = volid;
-               goto drop;
-           }
-
-           /*
-            * Attach the volume, give up on this volume if we can't.
-            */
-           tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
-           if (error) {
-               xInfoP->status = 0;     /*things are messed up */
-               strcpy(xInfoP->name, volname);
-               xInfoP->volid = volid;
-               Log("1 Volser: XListVolumes: Could not attach volume %u\n",
-                   volid);
-               goto drop;
-           }
 
-           /*
-            * Also bag out on this volume if it's been marked as needing a
-            * salvage or to-be-destroyed.
-            */
-           volDiskDataP = &(tv->header->diskstuff);
-           if (volDiskDataP->needsSalvaged) {
-               xInfoP->status = 0;
-               strcpy(xInfoP->name, volname);
-               xInfoP->volid = volid;
-               Log("1 Volser: XListVolumes: Volume %u needs to be salvaged\n", volid);
-               goto drop;
-           }
+           handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
+           handle.volinfo_ptr.ext = xInfoP;
 
-           if (volDiskDataP->destroyMe == DESTROY_ME)
+           code = GetVolInfo(a_partID,
+                             volid,
+                             pname,
+                             volname,
+                             &handle,
+                             VOL_INFO_LIST_MULTIPLE);
+           if (code == -2) { /* DESTROY_ME flag set */
                goto drop2;
-
-           /*
-            * Pull out the desired info and stuff it into the area we'll be
-            * returning to our caller.
-            */
-           strcpy(xInfoP->name, volDiskDataP->name);
-           xInfoP->volid = volDiskDataP->id;
-           xInfoP->type = volDiskDataP->type;
-           xInfoP->backupID = volDiskDataP->backupId;
-           xInfoP->parentID = volDiskDataP->parentId;
-           xInfoP->cloneID = volDiskDataP->cloneId;
-           xInfoP->status = VOK;
-           xInfoP->copyDate = volDiskDataP->copyDate;
-           xInfoP->inUse = volDiskDataP->inUse;
-           xInfoP->creationDate = volDiskDataP->creationDate;
-           xInfoP->accessDate = volDiskDataP->accessDate;
-           xInfoP->updateDate = volDiskDataP->updateDate;
-           xInfoP->backupDate = volDiskDataP->backupDate;
-           now = FT_ApproxTime();
-           if (now - volDiskDataP->dayUseDate > OneDay)
-               xInfoP->dayUse = 0;
-           else
-               xInfoP->dayUse = volDiskDataP->dayUse;
-           xInfoP->filecount = volDiskDataP->filecount;
-           xInfoP->maxquota = volDiskDataP->maxquota;
-           xInfoP->size = volDiskDataP->diskused;
-
-           /*
-            * Copy out the stat fields in a single operation.
-            */
-           memcpy((char *)&(xInfoP->stat_reads[0]),
-                  (char *)&(volDiskDataP->stat_reads[0]), numStatBytes);
-
-           /*
-            * We're done copying.  Detach the volume and iterate.
-            */
-           VDetachVolume(&error, tv);
-           tv = (Volume *) 0;
-           if (error) {
-               xInfoP->status = 0;
-               strcpy(xInfoP->name, volname);
-               Log("1 Volser: XListVolumes: Could not detach volume %s\n",
-                   volname);
-               goto drop;
            }
-       } /*Full contents desired */
-       else
+       } else {
            /*
             * Just volume IDs are needed.
             */
            xInfoP->volid = volid;
-
-      drop:
-       /*
-        * Drop the transaction we have for this volume.
-        */
-       if (ttc) {
-           DeleteTrans(ttc, 1);
-           ttc = (struct volser_trans *)0;
        }
 
+      drop:
        /*
         * Bump the pointer in the data area we're building, along with
         * the count of the number of entries it contains.
@@ -2521,14 +2488,6 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
                /*
                 * Bummer, no memory. Bag it, tell our caller what went wrong.
                 */
-               if (tv) {
-                   VDetachVolume(&error, tv);
-                   tv = (Volume *) 0;
-               }
-               if (ttc) {
-                   DeleteTrans(ttc, 1);
-                   ttc = (struct volser_trans *)0;
-               }
                closedir(dirp);
                return (VOLSERNO_MEMORY);
            }
@@ -2543,20 +2502,8 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
                a_volumeXInfoP->volXEntries_val +
                a_volumeXInfoP->volXEntries_len;
        }
-       /*Need more space */
+
       drop2:
-       /*
-        * Detach our current volume and the transaction on it, then move on
-        * to the next volume in the partition directory.
-        */
-       if (tv) {
-           VDetachVolume(&error, tv);
-           tv = (Volume *) 0;
-       }
-       if (ttc) {
-           DeleteTrans(ttc, 1);
-           ttc = (struct volser_trans *)0;
-       }
        GetNextVol(dirp, volname, &volid);
     }                          /*Sweep through the partition directory */
 
@@ -2565,8 +2512,6 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
      * delete our transaction (if any), and go home happy.
      */
     closedir(dirp);
-    if (ttc)
-       DeleteTrans(ttc, 1);
     return (0);
 
 }                              /*SAFSVolXListVolumes */
@@ -2750,116 +2695,65 @@ VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
     return error;
 }
 
-#ifdef AFS_NAMEI_ENV
-/* 
- * Inode number format  (from namei_ops.c): 
- * low 26 bits - vnode number - all 1's if volume special file.
- * next 3 bits - tag
- * next 3 bits spare (0's)
- * high 32 bits - uniquifier (regular) or type if spare
- */
-#define NAMEI_VNODEMASK    0x003ffffff
-#define NAMEI_TAGMASK      0x7
-#define NAMEI_TAGSHIFT     26
-#define NAMEI_UNIQMASK     0xffffffff
-#define NAMEI_UNIQSHIFT    32
-#define NAMEI_INODESPECIAL ((Inode)NAMEI_VNODEMASK)
-#define NAMEI_VNODESPECIAL NAMEI_VNODEMASK
-#endif /* AFS_NAMEI_ENV */
-
 afs_int32
 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
                           afs_int32 volumeId)
 {
-#if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
+#ifdef AFS_NT40_ENV
+    return EXDEV;
+#else
+    char caller[MAXKTCNAMELEN];
     DIR *dirp;
-    char pname[16];
-    char volname[20];
-    afs_int32 error = 0;
+    register struct volser_trans *ttc;
+    char pname[16], volname[20];
+    struct DiskPartition *partP;
+    afs_int32 ret = ENODEV;
     afs_int32 volid;
-    int found = 0;
-    char caller[MAXKTCNAMELEN];
-    char headername[16];
-    char opath[256];
-    char npath[256];
-    struct VolumeDiskHeader h;
-    int fd;
-    IHandle_t *ih;
-    Inode ino;
-    struct DiskPartition *dp;
 
     if (!afsconf_SuperUser(tdir, acid, caller))
        return VOLSERBAD_ACCESS;        /*not a super user */
     if (GetPartName(partId, pname))
-       return VOLSERILLEGAL_PARTITION;
-    dirp = opendir(pname);
+        return VOLSERILLEGAL_PARTITION;
+    if (!(partP = VGetPartition(pname, 0)))
+        return VOLSERILLEGAL_PARTITION;
+    dirp = opendir(VPartitionPath(partP));
     if (dirp == NULL)
        return VOLSERILLEGAL_PARTITION;
     strcpy(volname, "");
+    ttc = (struct volser_trans *)0;
 
-    while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
-       GetNextVol(dirp, volname, &volid);
-       if (strcmp(volname, "")) {      /* its a volume */
-           if (volid == volumeId)
-               found = 1;
+    while (strcmp(volname, "EOD")) {
+       if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
+            GetNextVol(dirp, volname, &volid);
+            continue;           /*back to while loop */
+        }
+       
+       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;
+            }
+#ifdef AFS_NAMEI_ENV
+           ret = namei_ConvertROtoRWvolume(pname, volumeId);
+#else
+           ret = inode_ConvertROtoRWvolume(pname, volumeId);
+#endif
+           break;
        }
+       GetNextVol(dirp, volname, &volid);
     }
-    if (!found)
-       return ENOENT;
-    (void)afs_snprintf(headername, sizeof headername, VFORMAT, volumeId);
-    (void)afs_snprintf(opath, sizeof opath, "%s/%s", pname, headername);
-    fd = open(opath, O_RDONLY);
-    if (fd < 0) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't open header for RO-volume %lu.\n", volumeId);
-       return ENOENT;
-    }
-    if (read(fd, &h, sizeof(h)) != sizeof(h)) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n", volumeId);
-       close(fd);
-       return EIO;
-    }
-    close(fd);
-    FSYNC_askfs(volumeId, pname, FSYNC_RESTOREVOLUME, 0);
-
-    for (dp = DiskPartitionList; dp && strcmp(dp->name, pname);
-        dp = dp->next);
-    if (!dp) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
-       return EIO;
-    }
-    ino = namei_MakeSpecIno(h.parent, VI_LINKTABLE);
-    IH_INIT(ih, dp->device, h.parent, ino);
-
-    error = namei_ConvertROtoRWvolume(ih, volumeId);
-    if (error)
-       return error;
-    h.id = h.parent;
-    h.volumeInfo_hi = h.id;
-    h.smallVnodeIndex_hi = h.id;
-    h.largeVnodeIndex_hi = h.id;
-    h.linkTable_hi = h.id;
-    (void)afs_snprintf(headername, sizeof headername, VFORMAT, h.id);
-    (void)afs_snprintf(npath, sizeof npath, "%s/%s", pname, headername);
-    fd = open(npath, O_CREAT | O_EXCL | O_RDWR, 0644);
-    if (fd < 0) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't create header for RW-volume %lu.\n", h.id);
-       return EIO;
-    }
-    if (write(fd, &h, sizeof(h)) != sizeof(h)) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't write header for RW-volume %lu.\n", h.id);
-       close(fd);
-       return EIO;
-    }
-    close(fd);
-    if (unlink(opath) < 0) {
-       Log("1 SAFS_VolConvertROtoRWvolume: Couldn't unlink RO header, error = %d\n", error);
+    
+    if (ttc) {
+        DeleteTrans(ttc, 1);
+        ttc = (struct volser_trans *)0;
     }
-    FSYNC_askfs(volumeId, pname, FSYNC_DONE, 0);
-    FSYNC_askfs(h.id, pname, FSYNC_ON, 0);
-    return 0;
-#else /* AFS_NAMEI_ENV */
-    return EINVAL;
-#endif /* AFS_NAMEI_ENV */
+    
+    closedir(dirp);
+    return ret;
+#endif
 }
 
 afs_int32