vos: Do not try to remove backup volume id 0
[openafs.git] / src / volser / vsprocs.c
index 7376ae0..801489c 100644 (file)
 #include <afsconfig.h>
 #include <afs/param.h>
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
+#include <afs/procmgmt.h>      /* signal(), kill(), wait(), etc. */
+#include <roken.h>
+
 #ifdef AFS_AIX_ENV
 #include <sys/statfs.h>
 #endif
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#include <winsock2.h>
-#else
-#include <sys/file.h>
-#include <netinet/in.h>
-#endif
 
 #include <lock.h>
 #include <afs/voldefs.h>
 #endif
 #include <afs/vnode.h>
 #include <afs/volume.h>
-#include <errno.h>
 #define ERRCODE_RANGE 8                /* from error_table.h */
 #define        CLOCKSKEW   2           /* not really skew, but resolution */
 #define CLOCKADJ(x) (((x) < CLOCKSKEW) ? 0 : (x) - CLOCKSKEW)
 
 /* for UV_MoveVolume() recovery */
 
-#include <afs/procmgmt.h>      /* signal(), kill(), wait(), etc. */
 #include <setjmp.h>
 
 #include "volser_internal.h"
@@ -63,7 +53,7 @@
 #include "vsutils_prototypes.h"
 #include "lockprocs_prototypes.h"
 
-struct ubik_client *cstruct;
+extern struct ubik_client *cstruct;
 int verbose = 0, noresolve = 0;
 
 struct release {
@@ -161,7 +151,10 @@ do { \
 
 
 /* getting rid of this */
-#define ERROR_EXIT(code) {error=(code); goto error_exit;}
+#define ERROR_EXIT(code) do { \
+    error = (code); \
+    goto error_exit; \
+} while (0)
 
 
 /* Protos for static routines */
@@ -170,19 +163,35 @@ static afs_int32 CheckAndDeleteVolume(struct rx_connection *aconn,
                                      afs_int32 apart, afs_uint32 okvol,
                                      afs_uint32 delvol);
 #endif
-static int DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
-                 afs_int32 flags);
 static int GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
                    struct rx_connection **connPtr, afs_int32 * transPtr,
                    afs_uint32 * crtimePtr, afs_uint32 * uptimePtr,
-                   afs_int32 *origflags);
+                   afs_int32 *origflags, afs_uint32 tmpVolId);
 static int SimulateForwardMultiple(struct rx_connection *fromconn,
                                   afs_int32 fromtid, afs_int32 fromdate,
                                   manyDests * tr, afs_int32 flags,
                                   void *cookie, manyResults * results);
+static int DoVolOnline(struct nvldbentry *vldbEntryPtr, afs_uint32 avolid,
+                      int index, char *vname, struct rx_connection *connPtr);
+static int DoVolClone(struct rx_connection *aconn, afs_uint32 avolid,
+                     afs_int32 apart, int type, afs_uint32 cloneid,
+                     char *typestring, char *pname, char *vname, char *suffix,
+                     struct volser_status *volstatus, afs_int32 *transPtr);
+static int DoVolDelete(struct rx_connection *aconn, afs_uint32 avolid,
+                      afs_int32 apart, char *typestring, afs_uint32 atoserver,
+                      struct volser_status *volstatus, char *pprefix);
 static afs_int32 CheckVolume(volintInfo * volumeinfo, afs_uint32 aserver,
                             afs_int32 apart, afs_int32 * modentry,
                             afs_uint32 * maxvolid, struct nvldbentry *aentry);
+static afs_int32 VolumeExists(afs_uint32 server, afs_int32 partition,
+                              afs_uint32 volumeid);
+static afs_int32 CheckVldbRWBK(struct nvldbentry * entry,
+                               afs_int32 * modified);
+static afs_int32 CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified);
+static afs_int32 CheckVldb(struct nvldbentry *entry, afs_int32 * modified,
+                           afs_int32 *deleted);
+static void dump_sig_handler(int x);
+static int sortVolumes(const void *a, const void *b);
 
 
 /*map the partition <partId> into partition name <partName>*/
@@ -205,21 +214,6 @@ MapPartIdIntoName(afs_int32 partId, char *partName)
 }
 
 int
-yesprompt(char *str)
-{
-    int response, c;
-    int code;
-
-    fprintf(STDERR, "Do you want to %s? [yn](n): ", str);
-    response = c = getchar();
-    while (!(c == EOF || c == '\n'))
-       c = getchar();          /*skip to end of line */
-    code = (response == 'y' || response == 'Y');
-    return code;
-}
-
-
-int
 PrintError(char *msg, afs_int32 errcode)
 {
     fprintf(STDERR, "%s", msg);
@@ -399,11 +393,9 @@ PrintError(char *msg, afs_int32 errcode)
        break;
     default:
        {
-           initialize_KA_error_table();
            initialize_RXK_error_table();
            initialize_KTC_error_table();
            initialize_ACFG_error_table();
-           initialize_CMD_error_table();
            initialize_VL_error_table();
 
            fprintf(STDERR, "%s: %s\n", afs_error_table_name(errcode),
@@ -937,26 +929,15 @@ UV_DeleteVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
 
     /* Whether volume is in the VLDB or not. Delete the volume on disk */
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
-    code = AFSVolTransCreate_retry(aconn, avolid, apart, ITOffline, &ttid);
+
+    code = DoVolDelete(aconn, avolid, apart, "the", 0, NULL, NULL);
     if (code) {
-       if (code == VNOVOL) {
+       if (code == VNOVOL)
            notondisk = 1;
-       } else {
-           EGOTO1(error_exit, code, "Transaction on volume %u failed\n",
-                  avolid);
+       else {
+           error = code;
+           goto error_exit;
        }
-    } else {
-       VPRINT1("Trying to delete the volume %u ...", avolid);
-
-       code = AFSVolDeleteVolume(aconn, ttid);
-       EGOTO1(error_exit, code, "Could not delete the volume %u \n", avolid);
-
-       code = AFSVolEndTrans(aconn, ttid, &rcode);
-       code = (code ? code : rcode);
-       ttid = 0;
-       EGOTO1(error_exit, code,
-              "Could not end the transaction for the volume %u \n", avolid);
-       VDONE;
     }
 
     /* Now update the VLDB entry.
@@ -1014,29 +995,14 @@ UV_DeleteVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
            ERROR_EXIT(0);
        }
 
-       /* Delete backup if it exists */
-       code =
-           AFSVolTransCreate_retry(aconn, entry.volumeId[BACKVOL], apart,
-                                   ITOffline, &ttid);
-
-       if (!code) {
-           if (verbose) {
-               fprintf(STDOUT, "Trying to delete the backup volume %u ...",
-                       entry.volumeId[BACKVOL]);
-               fflush(STDOUT);
+       if (entry.volumeId[BACKVOL]) {
+           /* Delete backup if it exists */
+           code = DoVolDelete(aconn, entry.volumeId[BACKVOL], apart,
+                              "the backup", 0, NULL, NULL);
+           if (code && code != VNOVOL) {
+               error = code;
+               goto error_exit;
            }
-           code = AFSVolDeleteVolume(aconn, ttid);
-           EGOTO1(error_exit, code, "Could not delete the volume %u \n",
-                  entry.volumeId[BACKVOL]);
-
-           code = AFSVolEndTrans(aconn, ttid, &rcode);
-           ttid = 0;
-           code = (code ? code : rcode);
-           EGOTO1(error_exit, code,
-                  "Could not end the transaction for the volume %u \n",
-                  entry.volumeId[BACKVOL]);
-           if (verbose)
-               fprintf(STDOUT, " done\n");
        }
 
        if (verbose)
@@ -1175,6 +1141,193 @@ sigint_handler(int x)
     (void)signal(SIGINT, sigint_handler);
 }
 
+static int
+DoVolDelete(struct rx_connection *aconn, afs_uint32 avolid,
+           afs_int32 apart, char *ptypestring, afs_uint32 atoserver,
+           struct volser_status *volstatus, char *pprefix)
+{
+    afs_int32 ttid = 0, code, rcode, error = 0;
+    char *prefix, *typestring;
+    int beverbose = 0;
+
+    if (pprefix)
+       prefix = pprefix;
+    else
+       prefix = "";
+
+    if (ptypestring) {
+       typestring = ptypestring;
+       beverbose = 1;
+    } else
+       typestring = "the";
+
+    if (beverbose)
+       VPRINT3("%sDeleting %s volume %u ...", prefix, typestring, avolid);
+
+    code =
+       AFSVolTransCreate_retry(aconn, avolid, apart, ITOffline, &ttid);
+
+    EGOTO2(dfail, code, "%sFailed to start transaction on %u\n",
+          prefix, avolid);
+
+    if (volstatus) {
+       code = AFSVolGetStatus(aconn, ttid, volstatus);
+       EGOTO2(dfail, code, "%sCould not get timestamp from volume %u\n",
+              prefix, avolid);
+    }
+
+    code =
+       AFSVolSetFlags(aconn, ttid,
+                      VTDeleteOnSalvage | VTOutOfService);
+
+    EGOTO2(dfail, code, "%sCould not set flags on volume %u \n",
+          prefix, avolid);
+
+    if (atoserver) {
+       VPRINT1("%sSetting volume forwarding pointer ...", prefix);
+       AFSVolSetForwarding(aconn, ttid, atoserver);
+       VDONE;
+    }
+
+    code = AFSVolDeleteVolume(aconn, ttid);
+    EGOTO2(dfail, code, "%sCould not delete volume %u\n", prefix, avolid);
+
+dfail:
+    if (ttid) {
+        code = AFSVolEndTrans(aconn, ttid, &rcode);
+       ttid = 0;
+        if (!code)
+            code = rcode;
+        if (code) {
+            fprintf(STDERR, "%sCould not end transaction on %s volume %lu \n",
+                    prefix, typestring, (unsigned long)avolid);
+            if (!error)
+                error = code;
+        }
+    }
+
+    if (beverbose && !error)
+       VDONE;
+    return error;
+}
+
+static int
+DoVolClone(struct rx_connection *aconn, afs_uint32 avolid,
+          afs_int32 apart, int type, afs_uint32 cloneid,
+          char *typestring, char *pname, char *vname, char *suffix,
+          struct volser_status *volstatus, afs_int32 *transPtr)
+{
+    char cname[64];
+    afs_int32 ttid = 0, btid = 0;
+    afs_int32 code = 0, rcode = 0;
+    afs_int32 error = 0;
+    int cloneexists = 1;
+
+    /* Test to see if the clone volume exists by trying to create
+     * a transaction on the clone volume. We've assumed the clone exists.
+     */
+    code = AFSVolTransCreate_retry(aconn, cloneid, apart, ITOffline, &btid);
+    if (code) {
+        if (code != VNOVOL) {
+           EPRINT2(code, "Could not reach the %s volume %lu\n",
+                    typestring, (unsigned long)cloneid);
+            error = code;
+            goto cfail;
+        }
+        cloneexists = 0;         /* clone volume does not exist */
+    }
+    if (btid) {
+        code = AFSVolEndTrans(aconn, btid, &rcode);
+        btid = 0;
+        if (code || rcode) {
+            fprintf(STDERR,
+                    "Could not end transaction on the previous %s volume %lu\n",
+                    typestring, (unsigned long)cloneid);
+            error = (code ? code : rcode);
+            goto cfail;
+        }
+    }
+
+    /* Now go ahead and try to clone the RW volume.
+     * First start a transaction on the RW volume
+     */
+    code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
+    if (code) {
+        fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
+                (unsigned long)avolid);
+        error = code;
+        goto cfail;
+    }
+
+    /* Clone or reclone the volume, depending on whether the clone
+     * volume exists or not
+     */
+    if (cloneexists) {
+        VPRINT2("Re-cloning %s volume %u ...", typestring, cloneid);
+
+        code = AFSVolReClone(aconn, ttid, cloneid);
+        if (code) {
+            EPRINT2(code, "Could not re-clone %s volume %lu\n",
+                    typestring, (unsigned long)cloneid);
+            error = code;
+            goto cfail;
+        }
+    } else {
+        VPRINT2("Creating a new %s clone %u ...", typestring, cloneid);
+
+       if (!vname) {
+           strcpy(cname, pname);
+           strcat(cname, suffix);
+       }
+
+        code = AFSVolClone(aconn, ttid, 0, type, vname?vname:cname,
+                          &cloneid);
+        if (code) {
+            fprintf(STDERR, "Failed to clone the volume %lu\n",
+                    (unsigned long)avolid);
+            error = code;
+            goto cfail;
+        }
+    }
+
+    VDONE;
+
+    if (volstatus) {
+       VPRINT1("Getting status of parent volume %u...", avolid);
+       code = AFSVolGetStatus(aconn, ttid, volstatus);
+       if (code) {
+           fprintf(STDERR, "Failed to get the status of the parent volume %lu\n",
+                   (unsigned long)avolid);
+           error = code;
+            goto cfail;
+       }
+       VDONE;
+    }
+
+cfail:
+    if (ttid) {
+        code = AFSVolEndTrans(aconn, ttid, &rcode);
+        if (code || rcode) {
+            fprintf(STDERR, "Could not end transaction on the volume %lu\n",
+                    (unsigned long)avolid);
+            if (!error)
+                error = (code ? code : rcode);
+        }
+    }
+
+    if (btid) {
+        code = AFSVolEndTrans(aconn, btid, &rcode);
+        if (code || rcode) {
+            fprintf(STDERR,
+                    "Could not end transaction on the %s volume %lu\n",
+                    typestring, (unsigned long)cloneid);
+            if (!error)
+                error = (code ? code : rcode);
+        }
+    }
+    return error;
+}
+
 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
  * <atopart>.  The operation is almost idempotent.  The following
  * flags are recognized:
@@ -1315,79 +1468,20 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
         * may still be existing physically on from fileserver
         */
        fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
-       fromtid = 0;
        pntg = 1;
 
-       tmp = fromtid;
-       code =
-           AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITOffline,
-                                   &tmp);
-       fromtid = tmp;
-
-       if (!code) {            /* volume exists - delete it */
-           VPRINT1("Setting flags on leftover source volume %u ...",
-                   afromvol);
-           code =
-               AFSVolSetFlags(fromconn, fromtid,
-                              VTDeleteOnSalvage | VTOutOfService);
-           EGOTO1(mfail, code,
-                  "Failed to set flags on the leftover source volume %u\n",
-                  afromvol);
-           VDONE;
-
-           VPRINT1("Deleting leftover source volume %u ...", afromvol);
-           code = AFSVolDeleteVolume(fromconn, fromtid);
-           EGOTO1(mfail, code,
-                  "Failed to delete the leftover source volume %u\n",
-                  afromvol);
-           VDONE;
-
-           VPRINT1("Ending transaction on leftover source volume %u ...",
-                   afromvol);
-           code = AFSVolEndTrans(fromconn, fromtid, &rcode);
-           fromtid = 0;
-           if (!code)
-               code = rcode;
-           EGOTO1(mfail, code,
-                  "Could not end the transaction for the leftover source volume %u \n",
-                  afromvol);
-           VDONE;
+       code = DoVolDelete(fromconn, afromvol, afrompart,
+                          "leftover", 0, NULL, NULL);
+       if (code && code != VNOVOL) {
+           error = code;
+           goto mfail;
        }
 
-       /*delete the backup volume now */
-       fromtid = 0;
-       code =
-           AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline,
-                                   &tmp);
-       fromtid = tmp;
-
-       if (!code) {            /* backup volume exists - delete it */
-           VPRINT1("Setting flags on leftover backup volume %u ...",
-                   backupId);
-           code =
-               AFSVolSetFlags(fromconn, fromtid,
-                              VTDeleteOnSalvage | VTOutOfService);
-           EGOTO1(mfail, code,
-                  "Failed to set flags on the backup volume %u\n", backupId);
-           VDONE;
-
-           VPRINT1("Deleting leftover backup volume %u ...", backupId);
-           code = AFSVolDeleteVolume(fromconn, fromtid);
-           EGOTO1(mfail, code,
-                  "Could not delete the leftover backup volume %u\n",
-                  backupId);
-           VDONE;
-
-           VPRINT1("Ending transaction on leftover backup volume %u ...",
-                   backupId);
-           code = AFSVolEndTrans(fromconn, fromtid, &rcode);
-           fromtid = 0;
-           if (!code)
-               code = rcode;
-           EGOTO1(mfail, code,
-                  "Could not end the transaction for the leftover backup volume %u\n",
-                  backupId);
-           VDONE;
+       code = DoVolDelete(fromconn, backupId, afrompart,
+                          "leftover backup", 0, NULL, NULL);
+       if (code && code != VNOVOL) {
+           error = code;
+           goto mfail;
        }
 
        fromtid = 0;
@@ -1529,33 +1623,11 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
 
     /* create a volume on the target machine */
     volid = afromvol;
-    tmp = totid;
-    code = AFSVolTransCreate_retry(toconn, volid, atopart, ITOffline, &tmp);
-    totid = tmp;
-    if (!code) {
-       /* Delete the existing volume.
-        * While we are deleting the volume in these steps, the transaction
-        * we started against the cloned volume (clonetid above) will be
-        * sitting idle. It will get cleaned up after 600 seconds
-        */
-       VPRINT1("Deleting pre-existing volume %u on destination ...", volid);
-       code = AFSVolDeleteVolume(toconn, totid);
-       EGOTO1(mfail, code,
-              "Could not delete the pre-existing volume %u on destination\n",
-              volid);
-       VDONE;
-
-       VPRINT1
-           ("Ending transaction on pre-existing volume %u on destination ...",
-            volid);
-       code = AFSVolEndTrans(toconn, totid, &rcode);
-       totid = 0;
-       if (!code)
-           code = rcode;
-       EGOTO1(mfail, code,
-              "Could not end the transaction on pre-existing volume %u on destination\n",
-              volid);
-       VDONE;
+    code = DoVolDelete(toconn, volid, atopart,
+                      "pre-existing destination", 0, NULL, NULL);
+    if (code && code != VNOVOL) {
+       error = code;
+       goto mfail;
     }
 
     VPRINT1("Creating the destination volume %u ...", volid);
@@ -1770,73 +1842,23 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
           afromvol);
     VDONE;
 
-    /* Delete the backup volume on the original site */
-    VPRINT1("Creating transaction for backup volume %u on source ...",
-           backupId);
-    tmp = fromtid;
-    code =
-       AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline, &tmp);
-    fromtid = tmp;
-    VDONE;
-    if (!code) {
-       VPRINT1("Setting flags on backup volume %u on source ...", backupId);
-       code =
-           AFSVolSetFlags(fromconn, fromtid,
-                          VTDeleteOnSalvage | VTOutOfService);
-       EGOTO1(mfail, code,
-              "Failed to set the flags on the backup volume %u on the source\n",
-              backupId);
-       VDONE;
-
-       VPRINT1("Deleting the backup volume %u on the source ...", backupId);
-       code = AFSVolDeleteVolume(fromconn, fromtid);
-       EGOTO1(mfail, code,
-              "Failed to delete the backup volume %u on the source\n",
-              backupId);
-       VDONE;
+    code = DoVolDelete(fromconn, backupId, afrompart,
+                      "source backup", 0, NULL, NULL);
+    if (code && code != VNOVOL) {
+       error = code;
+       goto mfail;
+    }
 
-       VPRINT1("Ending transaction on backup volume %u on source ...",
-               backupId);
-       code = AFSVolEndTrans(fromconn, fromtid, &rcode);
-       fromtid = 0;
-       if (!code)
-           code = rcode;
-       EGOTO1(mfail, code,
-              "Failed to end the transaction on the backup volume %u on the source\n",
-              backupId);
-       VDONE;
-    } else
-       code = 0;               /* no backup volume? that's okay */
+    code = 0;          /* no backup volume? that's okay */
 
     fromtid = 0;
     if (!(flags & RV_NOCLONE)) {
-       VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
-       tmp = clonetid;
-       code =
-           AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
-                             &tmp);
-       clonetid = tmp;
-       EGOTO1(mfail, code,
-              "Failed to start a transaction on the cloned volume%u\n",
-              newVol);
-       VDONE;
-
-       /* now delete the clone */
-       VPRINT1("Deleting the cloned volume %u ...", newVol);
-       code = AFSVolDeleteVolume(fromconn, clonetid);
-       EGOTO1(mfail, code, "Failed to delete the cloned volume %u\n",
-              newVol);
-       VDONE;
-
-       VPRINT1("Ending transaction on cloned volume %u ...", newVol);
-       code = AFSVolEndTrans(fromconn, clonetid, &rcode);
-       if (!code)
-           code = rcode;
-       clonetid = 0;
-       EGOTO1(mfail, code,
-              "Failed to end the transaction on the cloned volume %u\n",
-              newVol);
-       VDONE;
+       code = DoVolDelete(fromconn, newVol, afrompart,
+                          "cloned", 0, NULL, NULL);
+       if (code) {
+           error = code;
+           goto mfail;
+       }
     }
 
     /* fall through */
@@ -1996,41 +2018,9 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
            fflush(STDOUT);
        }
 
-       if (volid && toconn) {
-           VPRINT1
-               ("Recovery: Creating transaction for destination volume %u ...",
-                volid);
-           tmp = totid;
-           code =
-               AFSVolTransCreate_retry(toconn, volid, atopart, ITOffline, &tmp);
-           totid = tmp;
-
-           if (!code) {
-               VDONE;
-
-               VPRINT1
-                   ("Recovery: Setting flags on destination volume %u ...",
-                    volid);
-               AFSVolSetFlags(toconn, totid,
-                              VTDeleteOnSalvage | VTOutOfService);
-               VDONE;
-
-               VPRINT1("Recovery: Deleting destination volume %u ...",
-                       volid);
-               AFSVolDeleteVolume(toconn, totid);
-               VDONE;
-
-               VPRINT1
-                   ("Recovery: Ending transaction on destination volume %u ...",
-                    volid);
-               AFSVolEndTrans(toconn, totid, &rcode);
-               VDONE;
-           } else {
-               VPRINT1
-                   ("\nRecovery: Unable to start transaction on destination volume %u.\n",
-                    afromvol);
-           }
-       }
+       if (volid && toconn)
+           code = DoVolDelete(toconn, volid, atopart,
+                              "destination", 0, NULL, "Recovery:");
 
        /* put source volume on-line */
        if (fromconn) {
@@ -2069,102 +2059,19 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
 
        /* delete backup volume */
        if (fromconn) {
-           VPRINT1("Recovery: Creating transaction on backup volume %u ...",
-                   backupId);
-           tmp = fromtid;
-           code =
-               AFSVolTransCreate_retry(fromconn, backupId, afrompart, ITOffline,
-                                 &tmp);
-           fromtid = tmp;
-           if (!code) {
-               VDONE;
-
-               VPRINT1("Recovery: Setting flags on backup volume %u ...",
-                       backupId);
-               AFSVolSetFlags(fromconn, fromtid,
-                              VTDeleteOnSalvage | VTOutOfService);
-               VDONE;
-
-               VPRINT1("Recovery: Deleting backup volume %u ...", backupId);
-               AFSVolDeleteVolume(fromconn, fromtid);
-               VDONE;
-
-               VPRINT1
-                   ("Recovery: Ending transaction on backup volume %u ...",
-                    backupId);
-               AFSVolEndTrans(fromconn, fromtid, &rcode);
-               VDONE;
-           } else {
-               VPRINT1
-                   ("\nRecovery: Unable to start transaction on backup volume %u.\n",
-                    backupId);
-           }
+           code = DoVolDelete(fromconn, backupId, afrompart,
+                              "backup", 0, NULL, "Recovery:");
 
-           /* delete source volume */
-           VPRINT1("Recovery: Creating transaction on source volume %u ...",
-                   afromvol);
-           tmp = fromtid;
-           code =
-               AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
-                                 &tmp);
-           fromtid = tmp;
-           if (!code) {
-               VDONE;
-
-               VPRINT1("Recovery: Setting flags on backup volume %u ...",
-                       afromvol);
-               AFSVolSetFlags(fromconn, fromtid,
-                              VTDeleteOnSalvage | VTOutOfService);
-               VDONE;
-
-               if (atoserver != afromserver) {
-                   VPRINT("Recovery: Setting volume forwarding pointer ...");
-                   AFSVolSetForwarding(fromconn, fromtid, atoserver);
-                   VDONE;
-               }
-
-               VPRINT1("Recovery: Deleting source volume %u ...", afromvol);
-               AFSVolDeleteVolume(fromconn, fromtid);
-               VDONE;
-
-               VPRINT1
-                   ("Recovery: Ending transaction on source volume %u ...",
-                    afromvol);
-               AFSVolEndTrans(fromconn, fromtid, &rcode);
-               VDONE;
-           } else {
-               VPRINT1
-                   ("\nRecovery: Unable to start transaction on source volume %u.\n",
-                    afromvol);
-           }
+           code = DoVolDelete(fromconn, afromvol, afrompart, "source",
+                              (atoserver != afromserver)?atoserver:0,
+                              NULL, NULL);
        }
     }
 
     /* common cleanup - delete local clone */
     if (newVol) {
-       VPRINT1("Recovery: Creating transaction on clone volume %u ...",
-               newVol);
-       tmp = clonetid;
-       code =
-           AFSVolTransCreate_retry(fromconn, newVol, afrompart, ITOffline,
-                             &tmp);
-       clonetid = tmp;
-       if (!code) {
-           VDONE;
-
-           VPRINT1("Recovery: Deleting clone volume %u ...", newVol);
-           AFSVolDeleteVolume(fromconn, clonetid);
-           VDONE;
-
-           VPRINT1("Recovery: Ending transaction on clone volume %u ...",
-                   newVol);
-           AFSVolEndTrans(fromconn, clonetid, &rcode);
-           VDONE;
-       } else {
-           VPRINT1
-               ("\nRecovery: Unable to start transaction on source volume %u.\n",
-                afromvol);
-       }
+       code = DoVolDelete(fromconn, newVol, afrompart,
+                          "clone", 0, NULL, "Recovery:");
     }
 
     /* unlock VLDB entry */
@@ -2540,33 +2447,12 @@ cpincr:
     fromtid = 0;
 
     if (!(flags & RV_NOCLONE)) {
-       VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
-       tmp = clonetid;
-       code =
-           AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
-                             &tmp);
-       clonetid = tmp;
-       EGOTO1(mfail, code,
-              "Failed to start a transaction on the cloned volume%u\n",
-              cloneVol);
-       VDONE;
-
-       /* now delete the clone */
-       VPRINT1("Deleting the cloned volume %u ...", cloneVol);
-       code = AFSVolDeleteVolume(fromconn, clonetid);
-       EGOTO1(mfail, code, "Failed to delete the cloned volume %u\n",
-              cloneVol);
-       VDONE;
-
-       VPRINT1("Ending transaction on cloned volume %u ...", cloneVol);
-       code = AFSVolEndTrans(fromconn, clonetid, &rcode);
-       if (!code)
-           code = rcode;
-       clonetid = 0;
-       EGOTO1(mfail, code,
-              "Failed to end the transaction on the cloned volume %u\n",
-              cloneVol);
-       VDONE;
+       code = DoVolDelete(fromconn, cloneVol, afrompart,
+                          "cloned", 0, NULL, NULL);
+       if (code) {
+           error = code;
+           goto mfail;
+       }
     }
 
     if (!(flags & RV_NOVLDB)) {
@@ -2689,31 +2575,9 @@ cpincr:
     MapHostToNetwork(&entry);
 
     /* common cleanup - delete local clone */
-    if (cloneVol) {
-       VPRINT1("Recovery: Creating transaction on clone volume %u ...",
-               cloneVol);
-       tmp = clonetid;
-       code =
-           AFSVolTransCreate_retry(fromconn, cloneVol, afrompart, ITOffline,
-                             &tmp);
-       clonetid = tmp;
-       if (!code) {
-           VDONE;
-
-           VPRINT1("Recovery: Deleting clone volume %u ...", cloneVol);
-           AFSVolDeleteVolume(fromconn, clonetid);
-           VDONE;
-
-           VPRINT1("Recovery: Ending transaction on clone volume %u ...",
-                   cloneVol);
-           AFSVolEndTrans(fromconn, clonetid, &rcode);
-           VDONE;
-       } else {
-           VPRINT1
-               ("\nRecovery: Unable to start transaction on clone volume %u.\n",
-                cloneVol);
-       }
-    }
+    if (cloneVol)
+       code = DoVolDelete(fromconn, cloneVol, afrompart,
+                          "clone", 0, NULL, "Recovery:");
 
   done:                        /* routine cleanup */
     if (fromconn)
@@ -2750,10 +2614,9 @@ UV_BackupVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
     afs_int32 ttid = 0, btid = 0;
     afs_uint32 backupID;
     afs_int32 code = 0, rcode = 0;
-    char vname[VOLSER_MAXVOLNAME + 1];
     struct nvldbentry entry, storeEntry;
     afs_int32 error = 0;
-    int vldblocked = 0, vldbmod = 0, backexists = 1;
+    int vldblocked = 0, vldbmod = 0;
 
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
 
@@ -2822,82 +2685,14 @@ UV_BackupVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
        vldbmod = 1;
     }
 
-    /* Test to see if the backup volume exists by trying to create
-     * a transaction on the backup volume. We've assumed the backup exists.
-     */
-    code = AFSVolTransCreate_retry(aconn, backupID, apart, ITOffline, &btid);
+    code = DoVolClone(aconn, avolid, apart, backupVolume, backupID, "backup",
+                     entry.name, NULL, ".backup", NULL, NULL);
     if (code) {
-       if (code != VNOVOL) {
-           fprintf(STDERR, "Could not reach the backup volume %lu\n",
-                   (unsigned long)backupID);
-           error = code;
-           goto bfail;
-       }
-       backexists = 0;         /* backup volume does not exist */
-    }
-    if (btid) {
-       code = AFSVolEndTrans(aconn, btid, &rcode);
-       btid = 0;
-       if (code || rcode) {
-           fprintf(STDERR,
-                   "Could not end transaction on the previous backup volume %lu\n",
-                   (unsigned long)backupID);
-           error = (code ? code : rcode);
-           goto bfail;
-       }
-    }
-
-    /* Now go ahead and try to clone the RW volume.
-     * First start a transaction on the RW volume
-     */
-    code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
-    if (code) {
-       fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
-               (unsigned long)avolid);
        error = code;
        goto bfail;
     }
 
-    /* Clone or reclone the volume, depending on whether the backup
-     * volume exists or not
-     */
-    if (backexists) {
-       VPRINT1("Re-cloning backup volume %u ...", backupID);
-
-       code = AFSVolReClone(aconn, ttid, backupID);
-       if (code) {
-           fprintf(STDERR, "Could not re-clone backup volume %lu\n",
-                   (unsigned long)backupID);
-           error = code;
-           goto bfail;
-       }
-    } else {
-       VPRINT1("Creating a new backup clone %u ...", backupID);
-
-       strcpy(vname, entry.name);
-       strcat(vname, ".backup");
-
-       code = AFSVolClone(aconn, ttid, 0, backupVolume, vname, &backupID);
-       if (code) {
-           fprintf(STDERR, "Failed to clone the volume %lu\n",
-                   (unsigned long)avolid);
-           error = code;
-           goto bfail;
-       }
-    }
-
-    /* End the transaction on the RW volume */
-    code = AFSVolEndTrans(aconn, ttid, &rcode);
-    ttid = 0;
-    if (code || rcode) {
-       fprintf(STDERR,
-               "Failed to end the transaction on the rw volume %lu\n",
-               (unsigned long)avolid);
-       error = (code ? code : rcode);
-       goto bfail;
-    }
-
-    /* Mork vldb as backup exists */
+    /* Mark vldb as backup exists */
     if (!(entry.flags & BACK_EXISTS)) {
        entry.flags |= BACK_EXISTS;
        vldbmod = 1;
@@ -3013,8 +2808,8 @@ UV_CloneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid,
     afs_int32 code = 0, rcode = 0;
     char vname[VOLSER_MAXVOLNAME + 1];
     afs_int32 error = 0;
-    int backexists = 1;
     volEntries volumeInfo;
+    int type = 0;
 
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
 
@@ -3048,81 +2843,20 @@ UV_CloneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid,
        VDONE;
     }
 
-    /* Test to see if the clone volume exists by trying to create
-     * a transaction on the clone volume. We've assumed the clone exists.
-     */
-    /* XXX I wonder what happens if the clone has some other parent... */
-    code = AFSVolTransCreate_retry(aconn, acloneid, apart, ITOffline, &btid);
-    if (code) {
-       if (code != VNOVOL) {
-           fprintf(STDERR, "Could not reach the clone volume %lu\n",
-                   (unsigned long)acloneid);
-           error = code;
-           goto bfail;
-       }
-       backexists = 0;         /* backup volume does not exist */
-    }
-    if (btid) {
-       code = AFSVolEndTrans(aconn, btid, &rcode);
-       btid = 0;
-       if (code || rcode) {
-           fprintf(STDERR,
-                   "Could not end transaction on the previous clone volume %lu\n",
-                   (unsigned long)acloneid);
-           error = (code ? code : rcode);
-           goto bfail;
-       }
-    }
+    if (flags & RV_RWONLY)
+       type = readwriteVolume;
+    else if (flags & RV_RDONLY)
+       type = readonlyVolume;
+    else
+       type = backupVolume;
 
-    /* Now go ahead and try to clone the RW volume.
-     * First start a transaction on the RW volume
-     */
-    code = AFSVolTransCreate_retry(aconn, avolid, apart, ITBusy, &ttid);
+    code = DoVolClone(aconn, avolid, apart, type, acloneid, "clone",
+                     NULL, ".clone", NULL, NULL, NULL);
     if (code) {
-       fprintf(STDERR, "Could not start a transaction on the volume %lu\n",
-               (unsigned long)avolid);
        error = code;
        goto bfail;
     }
 
-    /* Clone or reclone the volume, depending on whether the backup
-     * volume exists or not
-     */
-    if (backexists) {
-       VPRINT1("Re-cloning clone volume %u ...", acloneid);
-
-       code = AFSVolReClone(aconn, ttid, acloneid);
-       if (code) {
-           fprintf(STDERR, "Could not re-clone backup volume %lu\n",
-                   (unsigned long)acloneid);
-           error = code;
-           goto bfail;
-       }
-    } else {
-       VPRINT1("Creating a new clone %u ...", acloneid);
-
-       code = AFSVolClone(aconn, ttid, 0,
-                          (flags & RV_RDONLY) ? readonlyVolume : backupVolume,
-                          aname, &acloneid);
-       if (code) {
-           fprintf(STDERR, "Failed to clone the volume %lu\n",
-                   (unsigned long)avolid);
-           error = code;
-           goto bfail;
-       }
-    }
-
-    /* End the transaction on the RW volume */
-    code = AFSVolEndTrans(aconn, ttid, &rcode);
-    ttid = 0;
-    if (code || rcode) {
-       fprintf(STDERR,
-               "Failed to end the transaction on the rw volume %lu\n",
-               (unsigned long)avolid);
-       error = (code ? code : rcode);
-       goto bfail;
-    }
-
     /* Now go back to the backup volume and bring it on line */
     if (!(flags & RV_OFFLINE)) {
        code = AFSVolTransCreate_retry(aconn, acloneid, apart, ITOffline, &btid);
@@ -3184,37 +2918,24 @@ UV_CloneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid,
     return error;
 }
 
-static int
-DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
-       afs_int32 flags)
-{
-    afs_int32 acode, ccode, rcode, tid;
-    ccode = rcode = tid = 0;
-
-    acode = AFSVolTransCreate_retry(conn, vid, part, flags, &tid);
-    if (!acode) {              /* It really was there */
-       acode = AFSVolDeleteVolume(conn, tid);
-       if (acode) {
-           fprintf(STDERR, "Failed to delete volume %lu.\n",
-                   (unsigned long)vid);
-           PrintError("", acode);
-       }
-       ccode = AFSVolEndTrans(conn, tid, &rcode);
-       if (!ccode)
-           ccode = rcode;
-       if (ccode) {
-           fprintf(STDERR, "Failed to end transaction on volume %lu.\n",
-                   (unsigned long)vid);
-           PrintError("", ccode);
-       }
-    }
-
-    return acode;
-}
-
-#define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
-#define ONERROR0(ec, es) if (ec) { fprintf(STDERR, (es)); error = (ec); goto rfail; }
-#define ERROREXIT(ec) { error = (ec); goto rfail; }
+#define ONERROR(ec, ep, es) do { \
+    if (ec) { \
+        fprintf(STDERR, (es), (ep)); \
+        error = (ec); \
+        goto rfail; \
+    } \
+} while (0)
+#define ONERROR0(ec, es) do { \
+    if (ec) { \
+        fprintf(STDERR, (es)); \
+        error = (ec); \
+        goto rfail; \
+    } \
+} while (0)
+#define ERROREXIT(ec) do { \
+    error = (ec); \
+    goto rfail; \
+} while (0)
 
 /* Get a "transaction" on this replica.  Create the volume
  * if necessary.  Return the time from which a dump should
@@ -3224,7 +2945,7 @@ static int
 GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
         struct rx_connection **connPtr, afs_int32 * transPtr,
         afs_uint32 * crtimePtr, afs_uint32 * uptimePtr,
-        afs_int32 *origflags)
+        afs_int32 *origflags, afs_uint32 tmpVolId)
 {
     afs_uint32 volid;
     struct volser_status tstatus;
@@ -3243,6 +2964,7 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
        goto fail;              /* server is down */
 
     volid = vldbEntryPtr->volumeId[ROVOL];
+
     if (volid) {
        code =
            AFSVolTransCreate_retry(*connPtr, volid,
@@ -3300,12 +3022,15 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
        }
 
        strcpy(volname, vldbEntryPtr->name);
-       strcat(volname, ".readonly");
+       if (tmpVolId)
+           strcat(volname, ".roclone");
+       else
+           strcat(volname, ".readonly");
 
        if (verbose) {
            fprintf(STDOUT,
                    "Creating new volume %lu on replication site %s: ",
-                   (unsigned long)volid,
+                   tmpVolId?(unsigned long)tmpVolId:(unsigned long)volid,
                     noresolve ? afs_inet_ntoa_r(vldbEntryPtr->
                                                 serverNumber[index], hoststr) :
                     hostutil_GetNameByINet(vldbEntryPtr->
@@ -3314,10 +3039,11 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
        }
 
        code =
-           AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
-                              volname, volser_RO,
-                              vldbEntryPtr->volumeId[RWVOL], &volid,
-                              transPtr);
+         AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
+                            volname, volser_RO,
+                            vldbEntryPtr->volumeId[RWVOL],
+                            tmpVolId?&tmpVolId:&volid,
+                            transPtr);
        if (code) {
            PrintError("Failed to create the ro volume: ", code);
            goto fail;
@@ -3351,6 +3077,20 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
                       code);
            goto fail;
        }
+       if (tmpVolId) {
+           code = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
+           *transPtr = 0;
+           if (!code)
+               code = rcode;
+           if (!code)
+               code = DoVolClone(*connPtr, volid,
+                                 vldbEntryPtr->serverPartition[index],
+                                 readonlyVolume, tmpVolId, "temporary",
+                                 vldbEntryPtr->name, NULL, ".roclone", NULL,
+                                 transPtr);
+           if (code)
+               goto fail;
+       }
        *crtimePtr = CLOCKADJ(tstatus.creationDate);
        *uptimePtr = CLOCKADJ(tstatus.updateDate);
     }
@@ -3363,7 +3103,7 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
        *transPtr = 0;
        if (!tcode)
            tcode = rcode;
-       if (tcode)
+       if (tcode && tcode != ENOENT)
            PrintError("Could not end transaction on a ro volume: ", tcode);
     }
 
@@ -3386,6 +3126,139 @@ SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
     return 0;
 }
 
+/**
+ * Check if a trans has timed out, and recreate it if necessary.
+ *
+ * @param[in] aconn  RX connection to the relevant server
+ * @param[inout] atid  Transaction ID to check; if we recreated the trans,
+ *                     contains the new trans ID on success
+ * @param[in] apart  Partition for the transaction
+ * @param[in] astat  The status of the original transaction
+ *
+ * @return operation status
+ *  @retval 0 existing transaction is still valid, or we managed to recreate
+ *            the trans successfully
+ *  @retval nonzero Fatal error; bail out
+ */
+static int
+CheckTrans(struct rx_connection *aconn, afs_int32 *atid, afs_int32 apart,
+           struct volser_status *astat)
+{
+    struct volser_status new_status;
+    afs_int32 code;
+
+    memset(&new_status, 0, sizeof(new_status));
+    code = AFSVolGetStatus(aconn, *atid, &new_status);
+    if (code) {
+       if (code == ENOENT) {
+           *atid = 0;
+           VPRINT1("Old transaction on cloned volume %lu timed out, "
+                   "restarting transaction\n", (long unsigned) astat->volID);
+           code = AFSVolTransCreate_retry(aconn, astat->volID, apart,
+                                          ITBusy, atid);
+           if (code) {
+               PrintError("Failed to recreate cloned RO volume transaction\n",
+                          code);
+               return 1;
+           }
+
+           memset(&new_status, 0, sizeof(new_status));
+           code = AFSVolGetStatus(aconn, *atid, &new_status);
+           if (code) {
+               PrintError("Failed to get status on recreated transaction\n",
+                          code);
+               return 1;
+           }
+
+           if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
+               PrintError("Recreated transaction on cloned RO volume, but "
+                          "the volume has changed!\n", 0);
+               return 1;
+           }
+       } else {
+           PrintError("Unable to get status of current cloned RO transaction\n",
+                      code);
+           return 1;
+       }
+    } else {
+       if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
+           /* sanity check */
+           PrintError("Internal error: current GetStatus does not match "
+                      "original GetStatus?\n", 0);
+           return 1;
+       }
+    }
+
+    return 0;
+}
+
+static void
+PutTrans(afs_int32 *vldbindex, struct replica *replicas,
+        struct rx_connection **toconns, struct release *times,
+        afs_int32 volcount)
+{
+    afs_int32 s, code = 0, rcode = 0;
+    /* End the transactions and destroy the connections */
+    for (s = 0; s < volcount; s++) {
+       if (replicas[s].trans) {
+           code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
+
+           replicas[s].trans = 0;
+           if (!code)
+               code = rcode;
+           if (code) {
+               if ((s == 0) || (code != ENOENT)) {
+                   PrintError("Could not end transaction on a ro volume: ",
+                              code);
+               } else {
+                   PrintError
+                       ("Transaction timed out on a ro volume. Will retry.\n",
+                        0);
+                   if (times[s].vldbEntryIndex < *vldbindex)
+                       *vldbindex = times[s].vldbEntryIndex;
+               }
+           }
+       }
+       if (toconns[s])
+           rx_DestroyConnection(toconns[s]);
+       toconns[s] = 0;
+    }
+}
+
+static int
+DoVolOnline(struct nvldbentry *vldbEntryPtr, afs_uint32 avolid, int index,
+           char *vname, struct rx_connection *connPtr)
+{
+    afs_int32 code = 0, rcode = 0, onlinetid = 0;
+
+    code =
+       AFSVolTransCreate_retry(connPtr, avolid,
+                               vldbEntryPtr->serverPartition[index],
+                               ITOffline,
+                               &onlinetid);
+    if (code)
+      EPRINT(code, "Could not create transaction on readonly...\n");
+
+    else {
+       code = AFSVolSetFlags(connPtr, onlinetid, 0);
+       if (code)
+           EPRINT(code, "Could not set flags on readonly...\n");
+    }
+
+    if (!code) {
+       code =
+           AFSVolSetIdsTypes(connPtr, onlinetid, vname,
+                             ROVOL, vldbEntryPtr->volumeId[RWVOL],
+                             0, 0);
+       if (code)
+           EPRINT(code, "Could not set ids on readonly...\n");
+    }
+    if (!code)
+       code = AFSVolEndTrans(connPtr, onlinetid, &rcode);
+    if (!code)
+       code = rcode;
+    return code;
+}
 
 /* UV_ReleaseVolume()
  *    Release volume <afromvol> on <afromserver> <afrompart> to all
@@ -3403,15 +3276,15 @@ SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
 
 int
 UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
-                afs_int32 afrompart, int forceflag)
+                afs_int32 afrompart, int forceflag, int stayUp)
 {
     char vname[64];
     afs_int32 code = 0;
     afs_int32 vcode, rcode, tcode;
-    afs_uint32 cloneVolId, roVolId;
+    afs_uint32 cloneVolId = 0, roVolId;
     struct replica *replicas = 0;
     struct nvldbentry entry, storeEntry;
-    int i, volcount, m, fullrelease, vldbindex;
+    int i, volcount = 0, m, fullrelease, vldbindex;
     int failure;
     struct restoreCookie cookie;
     struct rx_connection **toconns = 0;
@@ -3439,6 +3312,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     struct volser_status volstatus;
     char hoststr[16];
     afs_int32 origflags[NMAXNSERVERS];
+    struct volser_status orig_status;
 
     memset(remembertime, 0, sizeof(remembertime));
     memset(&results, 0, sizeof(results));
@@ -3513,6 +3387,29 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     code = VolumeExists(afromserver, afrompart, cloneVolId);
     roexists = ((code == ENODEV) ? 0 : 1);
 
+    /* For stayUp case, if roclone is the only site, bypass special handling */
+    if (stayUp && roclone) {
+       int e;
+       error = 0;
+
+       for (e = 0; (e < entry.nServers) && !error; e++) {
+           if ((entry.serverFlags[e] & ITSROVOL)) {
+               if (!(VLDB_IsSameAddrs(entry.serverNumber[e], afromserver,
+                                      &error)))
+                   break;
+           }
+       }
+       if (e >= entry.nServers)
+           stayUp = 0;
+    }
+
+    /* If we had a previous release to complete, do so, else: */
+    if (stayUp && (cloneVolId == entry.volumeId[ROVOL])) {
+       code = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &cloneVolId);
+       ONERROR(code, afromvol,
+               "Cannot get temporary clone id for volume %u\n");
+    }
+
     fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
     if (!fromconn)
        ONERROR(-1, afromserver,
@@ -3587,9 +3484,22 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
         * (it was recently added), then also delete it. We do not
         * want to "reclone" a temporary RO clone.
         */
+       if (stayUp) {
+           code = VolumeExists(afromserver, afrompart, cloneVolId);
+           if (!code) {
+               code = DoVolDelete(fromconn, cloneVolId, afrompart, "previous clone", 0,
+                                  NULL, NULL);
+               if (code && (code != VNOVOL))
+                   ERROREXIT(code);
+               VDONE;
+           }
+       }
+       /* clean up any previous tmp clone before starting if staying up */
        if (roexists
            && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
-           code = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
+           code = DoVolDelete(fromconn,
+                              stayUp ? entry.volumeId[ROVOL] : cloneVolId,
+                              afrompart, "the", 0, NULL, NULL);
            if (code && (code != VNOVOL))
                ERROREXIT(code);
            roexists = 0;
@@ -3606,54 +3516,30 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        entry.serverFlags[rwindex] |= NEW_REPSITE;
        entry.serverFlags[rwindex] &= ~RO_DONTUSE;
 
-       /* Begin transaction on RW and mark it busy while we clone it */
-       code =
-           AFSVolTransCreate_retry(fromconn, afromvol, afrompart, ITBusy,
-                             &clonetid);
-       ONERROR(code, afromvol, "Failed to start transaction on volume %u\n");
-
-       /* Clone or reclone the volume */
-       if (roexists) {
-           VPRINT1("Recloning RW volume %u...", cloneVolId);
-           code = AFSVolReClone(fromconn, clonetid, cloneVolId);
-           ONERROR(code, afromvol, "Failed to reclone the RW volume %u\n");
-           VDONE;
-       } else {
-           if (roclone) {
-               strcpy(vname, entry.name);
+       if (roclone) {
+           strcpy(vname, entry.name);
+           if (stayUp)
+               strcat(vname, ".roclone");
+           else
                strcat(vname, ".readonly");
-               VPRINT1("Cloning RW volume %u to permanent RO...", afromvol);
-           } else {
-               strcpy(vname, "readonly-clone-temp");
-               VPRINT1("Cloning RW volume %u to temporary RO...", afromvol);
-           }
-           code =
-               AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
-                           &cloneVolId);
-           ONERROR(code, afromvol, "Failed to clone the RW volume %u\n");
-           VDONE;
+       } else {
+           strcpy(vname, "readonly-clone-temp");
        }
 
-       /* Get the time the RW was created for future information */
-       VPRINT1("Getting status of RW volume %u...", afromvol);
-       code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
-       ONERROR(code, afromvol,
-               "Failed to get the status of the RW volume %u\n");
-       VDONE;
-       rwcrdate = volstatus.creationDate;
+       code = DoVolClone(fromconn, afromvol, afrompart, readonlyVolume,
+                         cloneVolId, (roclone && !stayUp)?"permanent RO":
+                         "temporary RO", NULL, vname, NULL, &volstatus, NULL);
+       if (code) {
+           error = code;
+           goto rfail;
+       }
 
-       /* End the transaction on the RW volume */
-       VPRINT1("Ending cloning transaction on RW volume %u...", afromvol);
-       code = AFSVolEndTrans(fromconn, clonetid, &rcode);
-       clonetid = 0;
-       ONERROR((code ? code : rcode), afromvol,
-               "Failed to end cloning transaction on RW %u\n");
-       VDONE;
+       rwcrdate = volstatus.creationDate;
 
        /* Remember clone volume ID in case we fail or are interrupted */
        entry.cloneId = cloneVolId;
 
-       if (roclone) {
+       if (roclone && !stayUp) {
            /* Bring the RO clone online - though not if it's a temporary clone */
            VPRINT1("Starting transaction on RO clone volume %u...",
                    cloneVolId);
@@ -3715,14 +3601,21 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
      */
 
     strcpy(vname, entry.name);
-    strcat(vname, ".readonly");
+    if (stayUp)
+       strcat(vname, ".roclone");
+    else
+       strcat(vname, ".readonly");
     memset(&cookie, 0, sizeof(cookie));
     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
     cookie.type = ROVOL;
     cookie.parent = entry.volumeId[RWVOL];
     cookie.clone = 0;
 
-    nservers = entry.nServers / 2;     /* how many to do at once, excluding clone */
+    /* how many to do at once, excluding clone */
+    if (stayUp)
+       nservers = entry.nServers; /* can do all, none offline */
+    else
+       nservers = entry.nServers / 2;
     replicas =
        (struct replica *)malloc(sizeof(struct replica) * nservers + 1);
     times = (struct release *)malloc(sizeof(struct release) * nservers + 1);
@@ -3731,7 +3624,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                                        nservers + 1);
     results.manyResults_val =
        (afs_int32 *) malloc(sizeof(afs_int32) * nservers + 1);
-    if (!replicas || !times || !!!results.manyResults_val || !toconns)
+    if (!replicas || !times || !results.manyResults_val || !toconns)
        ONERROR0(ENOMEM,
                "Failed to create transaction on the release clone\n");
 
@@ -3744,26 +3637,40 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     VPRINT1("Starting transaction on cloned volume %u...", cloneVolId);
     code =
        AFSVolTransCreate_retry(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
+    if (!code) {
+       memset(&orig_status, 0, sizeof(orig_status));
+       code = AFSVolGetStatus(fromconn, fromtid, &orig_status);
+    }
     if (!fullrelease && code)
        ONERROR(VOLSERNOVOL, afromvol,
                "Old clone is inaccessible. Try vos release -f %u.\n");
     ONERROR0(code, "Failed to create transaction on the release clone\n");
     VDONE;
 
+    /* if we have a clone, treat this as done, for now */
+    if (stayUp && !fullrelease) {
+       entry.serverFlags[roindex] |= NEW_REPSITE;
+       entry.serverFlags[roindex] &= ~RO_DONTUSE;
+       entry.flags |= RO_EXISTS;
+
+       releasecount++;
+    }
+
     /* For each index in the VLDB */
     for (vldbindex = 0; vldbindex < entry.nServers;) {
-
-       /* Get a transaction on the replicas. Pick replacas which have an old release. */
+       /* Get a transaction on the replicas. Pick replicas which have an old release. */
        for (volcount = 0;
             ((volcount < nservers) && (vldbindex < entry.nServers));
             vldbindex++) {
-           /* The first two RO volumes will be released individually.
-            * The rest are then released in parallel. This is a hack
-            * for clients not recognizing right away when a RO volume
-            * comes back on-line.
-            */
-           if ((volcount == 1) && (releasecount < 2))
-               break;
+           if (!stayUp) {
+               /* The first two RO volumes will be released individually.
+                * The rest are then released in parallel. This is a hack
+                * for clients not recognizing right away when a RO volume
+                * comes back on-line.
+                */
+               if ((volcount == 1) && (releasecount < 2))
+                   break;
+           }
 
            if (vldbindex == roindex)
                continue;       /* the clone    */
@@ -3790,7 +3697,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                         &(replicas[volcount].trans),
                         &(times[volcount].crtime),
                         &(times[volcount].uptime),
-                        origflags);
+                        origflags, stayUp?cloneVolId:0);
            if (code)
                continue;
 
@@ -3840,9 +3747,16 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        if (!volcount)
            continue;
 
+       code = CheckTrans(fromconn, &fromtid, afrompart, &orig_status);
+       if (code) {
+           code = ENOENT;
+           goto rfail;
+       }
+
        if (verbose) {
            fprintf(STDOUT, "Starting ForwardMulti from %lu to %u on %s",
-                   (unsigned long)cloneVolId, entry.volumeId[ROVOL],
+                   (unsigned long)cloneVolId, stayUp?
+                   cloneVolId:entry.volumeId[ROVOL],
                     noresolve ? afs_inet_ntoa_r(entry.serverNumber[times[0].
                                                 vldbEntryIndex], hoststr) :
                     hostutil_GetNameByINet(entry.
@@ -3929,36 +3843,166 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
            }
        }
 
-       /* End the transactions and destroy the connections */
+       if (!stayUp) {
+           PutTrans(&vldbindex, replicas, toconns, times, volcount);
+           MapNetworkToHost(&entry, &storeEntry);
+           vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
+           ONERROR(vcode, afromvol,
+                   " Could not update VLDB entry for volume %u\n");
+       }
+    }                          /* for each index in the vldb */
+
+    /* for the stayup case, put back at the end */
+    if (stayUp) {
+       afs_uint32 tmpVol = entry.volumeId[ROVOL];
+       strcpy(vname, entry.name);
+       strcat(vname, ".readonly");
+
+       if (roclone) {
+           /* have to clear flags to ensure new vol goes online
+            */
+           code = AFSVolSetFlags(fromconn, fromtid, 0);
+           if (code && (code != ENOENT)) {
+               PrintError("Failed to set flags on ro volume: ",
+                          code);
+           }
+
+           VPRINT3("%sloning to permanent RO %u on %s...", roexists?"Re-c":"C", tmpVol,
+                   noresolve ?
+                   afs_inet_ntoa_r(entry.serverNumber[roindex],
+                                   hoststr) :
+                   hostutil_GetNameByINet(entry.serverNumber[roindex]));
+
+           code = AFSVolClone(fromconn, fromtid, roexists?tmpVol:0,
+                              readonlyVolume, vname, &tmpVol);
+
+           if (!code) {
+               VDONE;
+               VPRINT("Bringing readonly online...");
+               code = DoVolOnline(&entry, tmpVol, roindex, vname,
+                                  fromconn);
+           }
+           if (code) {
+               EPRINT(code, "Failed: ");
+               entry.serverFlags[roindex] &= ~NEW_REPSITE;
+               entry.serverFlags[roindex] |= RO_DONTUSE;
+           } else {
+               entry.serverFlags[roindex] |= NEW_REPSITE;
+               entry.serverFlags[roindex] &= ~RO_DONTUSE;
+               entry.flags |= RO_EXISTS;
+               VDONE;
+           }
+
+       }
        for (s = 0; s < volcount; s++) {
-           if (replicas[s].trans)
+           if (replicas[s].trans) {
+               vldbindex = times[s].vldbEntryIndex;
+
+               /* ok, so now we have to end the previous transaction */
                code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
-           replicas[s].trans = 0;
-           if (!code)
-               code = rcode;
-           if (code) {
-               if ((s == 0) || (code != ENOENT)) {
-                   PrintError("Could not end transaction on a ro volume: ",
-                              code);
+               if (!code)
+                   code = rcode;
+
+               if (!code) {
+                   code = AFSVolTransCreate_retry(toconns[s],
+                                                  cloneVolId,
+                                                  entry.serverPartition[vldbindex],
+                                                  ITBusy,
+                                                  &(replicas[s].trans));
+                   if (code) {
+                       PrintError("Unable to begin transaction on temporary clone: ", code);
+                   }
                } else {
-                   PrintError
-                       ("Transaction timed out on a ro volume. Will retry.\n",
-                        0);
-                   if (times[s].vldbEntryIndex < vldbindex)
-                       vldbindex = times[s].vldbEntryIndex;
+                   PrintError("Unable to end transaction on temporary clone: ", code);
+               }
+
+               VPRINT3("%sloning to permanent RO %u on %s...", times[s].crtime?"Re-c":"C",
+                       tmpVol, noresolve ?
+                       afs_inet_ntoa_r(htonl(replicas[s].server.destHost),
+                                       hoststr) :
+                       hostutil_GetNameByINet(htonl(replicas[s].server.destHost)));
+               if (times[s].crtime)
+                   code = AFSVolClone(toconns[s], replicas[s].trans, tmpVol,
+                                      readonlyVolume, vname, &tmpVol);
+               else
+                   code = AFSVolClone(toconns[s], replicas[s].trans, 0,
+                                      readonlyVolume, vname, &tmpVol);
+
+               if (code) {
+                   if (!times[s].crtime) {
+                       entry.serverFlags[vldbindex] |= RO_DONTUSE;
+                   }
+                   entry.serverFlags[vldbindex] &= ~NEW_REPSITE;
+                   PrintError("Failed: ",
+                              code);
+               } else
+                   VDONE;
+
+               if (entry.serverFlags[vldbindex] != RO_DONTUSE) {
+                   /* bring it online (mark it InService) */
+                   VPRINT1("Bringing readonly online on %s...",
+                           noresolve ?
+                           afs_inet_ntoa_r(
+                               htonl(replicas[s].server.destHost),
+                               hoststr) :
+                           hostutil_GetNameByINet(
+                               htonl(replicas[s].server.destHost)));
+
+                   code = DoVolOnline(&entry, tmpVol, vldbindex, vname,
+                                      toconns[s]);
+                   /* needed to come online for cloning */
+                   if (code) {
+                       /* technically it's still new, just not online */
+                       entry.serverFlags[s] &= ~NEW_REPSITE;
+                       entry.serverFlags[s] |= RO_DONTUSE;
+                       if (code != ENOENT) {
+                           PrintError("Failed to set correct names and ids: ",
+                                      code);
+                       }
+                   } else
+                       VDONE;
                }
-           }
 
-           if (toconns[s])
-               rx_DestroyConnection(toconns[s]);
-           toconns[s] = 0;
+               VPRINT("Marking temporary clone for deletion...\n");
+               code = AFSVolSetFlags(toconns[s],
+                                     replicas[s].trans,
+                                     VTDeleteOnSalvage |
+                                     VTOutOfService);
+               if (code)
+                 EPRINT(code, "Failed: ");
+               else
+                 VDONE;
+
+               VPRINT("Ending transaction on temporary clone...\n");
+               code = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
+               if (!code)
+                   rcode = code;
+               if (code)
+                   PrintError("Failed: ", code);
+               else {
+                   VDONE;
+                   /* ended successfully */
+                   replicas[s].trans = 0;
+
+                   VPRINT2("Deleting temporary clone %u on %s...", cloneVolId,
+                           noresolve ?
+                           afs_inet_ntoa_r(htonl(replicas[s].server.destHost),
+                                           hoststr) :
+                           hostutil_GetNameByINet(htonl(replicas[s].server.destHost)));
+                   code = DoVolDelete(toconns[s], cloneVolId,
+                                      entry.serverPartition[vldbindex],
+                                      NULL, 0, NULL, NULL);
+                   if (code) {
+                       EPRINT(code, "Failed: ");
+                   } else
+                       VDONE;
+               }
+           }
        }
 
-       MapNetworkToHost(&entry, &storeEntry);
-       vcode = VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry, 0);
-       ONERROR(vcode, afromvol,
-               " Could not update VLDB entry for volume %u\n");
-    }                          /* for each index in the vldb */
+       /* done. put the vldb entry in the success tail case*/
+       PutTrans(&vldbindex, replicas, toconns, times, volcount);
+    }
 
     /* End the transaction on the cloned volume */
     code = AFSVolEndTrans(fromconn, fromtid, &rcode);
@@ -3986,7 +4030,6 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                         hostutil_GetNameByINet(entry.serverNumber[i]), pname);
            }
        }
-
        MapNetworkToHost(&entry, &storeEntry);
        vcode =
            VLDB_ReplaceEntry(afromvol, RWVOL, &storeEntry,
@@ -3997,18 +4040,19 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        ERROREXIT(VOLSERBADRELEASE);
     }
 
+    entry.cloneId = 0;
     /* All the ROs were release successfully. Remove the temporary clone */
-    if (!roclone) {
+    if (!roclone || stayUp) {
        if (verbose) {
            fprintf(STDOUT, "Deleting the releaseClone %lu ...",
                    (unsigned long)cloneVolId);
            fflush(STDOUT);
        }
-       code = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
+       code = DoVolDelete(fromconn, cloneVolId, afrompart, NULL, 0, NULL,
+                          NULL);
        ONERROR(code, cloneVolId, "Failed to delete volume %u.\n");
        VDONE;
     }
-    entry.cloneId = 0;
 
     for (i = 0; i < entry.nServers; i++)
        entry.serverFlags[i] &= ~NEW_REPSITE;
@@ -4096,7 +4140,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
 }
 
 
-void
+static void
 dump_sig_handler(int x)
 {
     fprintf(STDERR, "\nSignal handler: vos dump operation\n");
@@ -4467,36 +4511,12 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
                           &totid);
     if (code) {
        if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
-           VPRINT1("Deleting the previous volume %u ...", pvolid);
-
-           code =
-               AFSVolTransCreate_retry(toconn, pvolid, topart, ITOffline, &totid);
-           EGOTO1(refail, code, "Failed to start transaction on %u\n",
-                  pvolid);
-
-           code = AFSVolGetStatus(toconn, totid, &tstatus);
-           EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
-                  pvolid);
-
-           oldCreateDate = tstatus.creationDate;
-           oldUpdateDate = tstatus.updateDate;
-
-           code =
-               AFSVolSetFlags(toconn, totid,
-                              VTDeleteOnSalvage | VTOutOfService);
-           EGOTO1(refail, code, "Could not set flags on volume %u \n",
-                  pvolid);
-
-           code = AFSVolDeleteVolume(toconn, totid);
-           EGOTO1(refail, code, "Could not delete volume %u\n", pvolid);
-
-           code = AFSVolEndTrans(toconn, totid, &rcode);
-           totid = 0;
-           if (!code)
-               code = rcode;
-           EGOTO1(refail, code, "Could not end transaction on %u\n", pvolid);
-
-           VDONE;
+           code = DoVolDelete(toconn, pvolid, topart, "the previous", 0,
+                              &tstatus, NULL);
+           if (code && code != VNOVOL) {
+               error = code;
+               goto refail;
+           }
 
            code =
                AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid,
@@ -4512,9 +4532,9 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
            EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
                   pvolid);
 
-           oldCreateDate = tstatus.creationDate;
-           oldUpdateDate = tstatus.updateDate;
        }
+       oldCreateDate = tstatus.creationDate;
+       oldUpdateDate = tstatus.updateDate;
     } else {
        oldCreateDate = 0;
        oldUpdateDate = 0;
@@ -4726,45 +4746,15 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
                              noresolve ? afs_inet_ntoa_r(entry.serverNumber[index], hoststr) :
                             hostutil_GetNameByINet(entry.serverNumber[index]),
                             apartName);
-                       code =
-                           AFSVolTransCreate_retry(tempconn, pvolid,
-                                             entry.serverPartition[index],
-                                             ITOffline, &temptid);
-                       if (!code) {
-                           code =
-                               AFSVolSetFlags(tempconn, temptid,
-                                              VTDeleteOnSalvage |
-                                              VTOutOfService);
-                           if (code) {
-                               fprintf(STDERR,
-                                       "Could not set flags on volume %lu on the older site\n",
-                                       (unsigned long)pvolid);
-                               error = code;
-                               goto refail;
-                           }
-                           code = AFSVolDeleteVolume(tempconn, temptid);
-                           if (code) {
-                               fprintf(STDERR,
-                                       "Could not delete volume %lu on the older site\n",
-                                       (unsigned long)pvolid);
-                               error = code;
-                               goto refail;
-                           }
-                           code = AFSVolEndTrans(tempconn, temptid, &rcode);
-                           temptid = 0;
-                           if (!code)
-                               code = rcode;
-                           if (code) {
-                               fprintf(STDERR,
-                                       "Could not end transaction on volume %lu on the older site\n",
-                                       (unsigned long)pvolid);
-                               error = code;
-                               goto refail;
-                           }
-                           VDONE;
-                           MapPartIdIntoName(entry.serverPartition[index],
-                                             partName);
+                       code = DoVolDelete(tempconn, pvolid,
+                                          entry.serverPartition[index],
+                                          "the", 0, NULL, NULL);
+                       if (code && code != VNOVOL) {
+                           error = code;
+                           goto refail;
                        }
+                       MapPartIdIntoName(entry.serverPartition[index],
+                                         partName);
                    }
                }
                entry.serverNumber[index] = toserver;
@@ -5218,9 +5208,7 @@ UV_ZapVolumeClones(afs_uint32 aserver, afs_int32 apart,
     struct volDescription *curPtr;
     int curPos;
     afs_int32 code = 0;
-    afs_int32 rcode = 0;
     afs_int32 success = 1;
-    afs_int32 tid;
 
     aconn = (struct rx_connection *)0;
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
@@ -5229,19 +5217,12 @@ UV_ZapVolumeClones(afs_uint32 aserver, afs_int32 apart,
        if (curPtr->volFlags & CLONEVALID) {
            curPtr->volFlags &= ~CLONEZAPPED;
            success = 1;
-           code =
-               AFSVolTransCreate_retry(aconn, curPtr->volCloneId, apart, ITOffline,
-                                 &tid);
+
+           code = DoVolDelete(aconn, curPtr->volCloneId, apart,
+                              "clone", 0, NULL, NULL);
            if (code)
                success = 0;
-           else {
-               code = AFSVolDeleteVolume(aconn, tid);
-               if (code)
-                   success = 0;
-               code = AFSVolEndTrans(aconn, tid, &rcode);
-               if (code || rcode)
-                   success = 0;
-           }
+
            if (success)
                curPtr->volFlags |= CLONEZAPPED;
            if (!success)
@@ -5251,7 +5232,6 @@ UV_ZapVolumeClones(afs_uint32 aserver, afs_int32 apart,
                VPRINT2("Clone of %s %u deleted\n", curPtr->volName,
                        curPtr->volCloneId);
            curPos++;
-           tid = 0;
        }
     }
     if (aconn)
@@ -6033,7 +6013,7 @@ CheckVolume(volintInfo * volumeinfo, afs_uint32 aserver, afs_int32 apart,
     return (error);
 }
 
-int
+static int
 sortVolumes(const void *a, const void *b)
 {
     volintInfo *v1 = (volintInfo *) a;
@@ -6448,7 +6428,7 @@ UV_SyncVldb(afs_uint32 aserver, afs_int32 apart, int flags, int force)
  *      Some error codes mean the volume is unavailable but
  *      still exists - so we catch these error codes.
  */
-afs_int32
+static afs_int32
 VolumeExists(afs_uint32 server, afs_int32 partition, afs_uint32 volumeid)
 {
     struct rx_connection *conn = (struct rx_connection *)0;
@@ -6472,7 +6452,7 @@ VolumeExists(afs_uint32 server, afs_int32 partition, afs_uint32 volumeid)
 /* CheckVldbRWBK()
  *
  */
-afs_int32
+static afs_int32
 CheckVldbRWBK(struct nvldbentry * entry, afs_int32 * modified)
 {
     int modentry = 0;
@@ -6579,7 +6559,7 @@ CheckVldbRWBK(struct nvldbentry * entry, afs_int32 * modified)
     return (error);
 }
 
-int
+static afs_int32
 CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified)
 {
     int idx;
@@ -6643,7 +6623,7 @@ CheckVldbRO(struct nvldbentry *entry, afs_int32 * modified)
 /* CheckVldb()
  *      Ensure that <entry> matches with the info on file servers
  */
-afs_int32
+static afs_int32
 CheckVldb(struct nvldbentry * entry, afs_int32 * modified, afs_int32 * deleted)
 {
     afs_int32 code, error = 0;
@@ -7165,46 +7145,13 @@ UV_VolserStatus(afs_uint32 server, transDebugInfo ** rpntr, afs_int32 * rcount)
 int
 UV_VolumeZap(afs_uint32 server, afs_int32 part, afs_uint32 volid)
 {
-    afs_int32 rcode, ttid, error, code;
+    afs_int32 error;
     struct rx_connection *aconn;
 
-    code = 0;
-    error = 0;
-    ttid = 0;
-
     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
-    code = AFSVolTransCreate_retry(aconn, volid, part, ITOffline, &ttid);
-    if (code) {
-       fprintf(STDERR, "Could not start transaction on volume %lu\n",
-               (unsigned long)volid);
-       error = code;
-       goto zfail;
-    }
-    code = AFSVolDeleteVolume(aconn, ttid);
-    if (code) {
-       fprintf(STDERR, "Could not delete volume %lu\n",
-               (unsigned long)volid);
-       error = code;
-       goto zfail;
-    }
-    code = AFSVolEndTrans(aconn, ttid, &rcode);
-    ttid = 0;
-    if (!code)
-       code = rcode;
-    if (code) {
-       fprintf(STDERR, "Could not end transaction on volume %lu\n",
-               (unsigned long)volid);
-       error = code;
-       goto zfail;
-    }
-  zfail:
-    if (ttid) {
-       code = AFSVolEndTrans(aconn, ttid, &rcode);
-       if (!code)
-           code = rcode;
-       if (!error)
-           error = code;
-    }
+    error = DoVolDelete(aconn, volid, part,
+                       "the", 0, NULL, NULL);
+
     PrintError("", error);
     if (aconn)
        rx_DestroyConnection(aconn);