vos-dump-clone-and-vos-copy-support-20021026
authorNathan Neulinger <nneul@umr.edu>
Sat, 26 Oct 2002 16:41:14 +0000 (16:41 +0000)
committerDerrick Brashear <shadow@dementia.org>
Sat, 26 Oct 2002 16:41:14 +0000 (16:41 +0000)
support for cloning before a dump, and for vos copy

src/volser/vos.c
src/volser/vsprocs.c

index 00b62ab..5eb30eb 100644 (file)
@@ -1818,6 +1818,135 @@ register struct cmd_syndesc *as;
 
     return 0;
 }
+
+static CopyVolume(as)
+register struct cmd_syndesc *as;
+{
+    
+    afs_int32 volid, fromserver, toserver, tovolume, frompart, topart,code, err;
+    char fromPartName[10], toPartName[10];
+    struct nvldbentry entry;
+       struct diskPartition partition;         /* for space check */
+       volintInfo *p;
+
+       volid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
+       if (volid == 0) {
+       if (err) PrintError("", err);
+       else  fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+                   as->parms[0].items->data);
+           return ENOENT;
+       }
+       fromserver = GetServer(as->parms[1].items->data);
+       if (fromserver == 0) {
+           fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[1].items->data);
+           return ENOENT;
+       }
+
+       toserver = GetServer(as->parms[4].items->data);
+       if (toserver == 0) {
+           fprintf(STDERR,"vos: server '%s' not found in host table\n", as->parms[3].items->data);
+           return ENOENT;
+       }
+
+       tovolume = as->parms[3].items->data;
+    if(!ISNAMEVALID(tovolume)) {
+       fprintf(STDERR,"vos: the name of the root volume %s exceeds the size limit of %d\n",
+               tovolume,VOLSER_OLDMAXVOLNAME - 10);
+       return E2BIG;
+    }
+    if(!VolNameOK(tovolume)){
+       fprintf(STDERR,"Illegal volume name %s, should not end in .readonly or .backup\n",tovolume);
+       return EINVAL;
+    }
+    if(IsNumeric(tovolume)){
+       fprintf(STDERR,"Illegal volume name %s, should not be a number\n",tovolume);
+       return EINVAL;
+    }
+    code = VLDB_GetEntryByName(tovolume, &entry);
+    if(!code) {
+       fprintf(STDERR,"Volume %s already exists\n",tovolume);
+       PrintDiagnostics("copy", code);
+       return EEXIST;
+    }
+
+       frompart = volutil_GetPartitionID(as->parms[2].items->data);
+       if (frompart < 0) {
+           fprintf(STDERR,"vos: could not interpret partition name '%s'\n", as->parms[2].items->data);
+           return EINVAL;
+       }
+       if (!IsPartValid(frompart,fromserver,&code)){/*check for validity of the partition */
+           if(code) PrintError("",code);
+           else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[2].items->data);
+           return ENOENT;
+       }
+
+       topart = volutil_GetPartitionID(as->parms[5].items->data);
+       if (topart < 0) {
+           fprintf(STDERR,"vos: could not interpret partition name '%s'\n",as->parms[4].items->data);
+           return EINVAL;
+       }
+       if (!IsPartValid(topart,toserver,&code)){/*check for validity of the partition */
+           if(code) PrintError("",code);
+           else fprintf(STDERR,"vos : partition %s does not exist on the server\n",as->parms[4].items->data);
+           return ENOENT;
+       }
+
+       /*
+               check source partition for space to clone volume
+       */
+
+       MapPartIdIntoName(topart,toPartName);
+       MapPartIdIntoName(frompart, fromPartName);
+
+       /*
+               check target partition for space to move volume
+       */
+
+       code=UV_PartitionInfo(toserver,toPartName,&partition);
+       if(code)
+       {
+               fprintf(STDERR,"vos: cannot access partition %s\n",toPartName);
+               exit(1);
+       }
+       if(TESTM)
+               fprintf(STDOUT,"target partition %s free space %d\n",
+                       toPartName,partition.free);
+
+       p=(volintInfo *)0;
+       code=UV_ListOneVolume(fromserver,frompart,volid,&p);
+       if(code)
+       {
+               fprintf(STDERR,"vos:cannot access volume %u\n",volid);
+               free(p);
+               exit(1);
+       }
+
+       if(partition.free<=p->size)
+       {
+               fprintf(STDERR,"vos: no space on target partition %s to copy volume %u\n",
+                       toPartName,volid);
+               free(p);
+               exit(1);
+       }
+       free(p);
+
+       /* successful copy still not guaranteed but shoot for it */
+
+       code = UV_CopyVolume(volid, fromserver, frompart, tovolume, toserver, topart);
+       if (code) {
+           PrintDiagnostics("copy", code);
+           return code;
+       }
+       MapPartIdIntoName(topart,toPartName);
+       MapPartIdIntoName(frompart, fromPartName);
+       fprintf(STDOUT,"Volume %u copied from %s %s to %s on %s %s \n",volid,
+               as->parms[1].items->data,fromPartName,
+               tovolume, as->parms[4].items->data,toPartName);
+
+    return 0;
+}
+
+
 static BackupVolume(as)
 register struct cmd_syndesc *as;
 {
@@ -1976,7 +2105,12 @@ register struct cmd_syndesc *as;
        else{
            strcpy(filename,"");
        }
-       code = UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction, filename);
+
+    if (as->parms[5].items) {
+               code = UV_DumpClonedVolume(avolid, aserver, apart, fromdate, DumpFunction, filename);
+       } else {
+               code = UV_DumpVolume(avolid, aserver, apart, fromdate, DumpFunction, filename);
+       }               
        if (code) {
            PrintDiagnostics("dump", code);
            return code;
@@ -4134,6 +4268,15 @@ char **argv; {
     cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0, "partition name on destination");
     COMMONPARMS;
 
+    ts = cmd_CreateSyntax("copy", CopyVolume, 0, "copy a volume");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID on source");
+    cmd_AddParm(ts, "-fromserver", CMD_SINGLE, 0, "machine name on source");
+    cmd_AddParm(ts, "-frompartition", CMD_SINGLE, 0, "partition name on source");
+       cmd_AddParm(ts, "-toname", CMD_SINGLE, 0, "volume name on destination");
+    cmd_AddParm(ts, "-toserver", CMD_SINGLE, 0, "machine name on destination");
+    cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0, "partition name on destination");
+    COMMONPARMS;
+
     ts = cmd_CreateSyntax("backup", BackupVolume, 0, "make backup of a volume");
     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
     COMMONPARMS;
@@ -4149,6 +4292,7 @@ char **argv; {
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
+    cmd_AddParm(ts, "-clone", CMD_FLAG, CMD_OPTIONAL, "dump a clone of the volume");
     COMMONPARMS;
 
     ts = cmd_CreateSyntax("restore", RestoreVolume, 0, "restore a volume");
index 918b535..1ccbc17 100644 (file)
@@ -1663,6 +1663,387 @@ done:   /* routine cleanup */
     exit(1);
 }
 
+
+/* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
+ * <atopart>. The operation is almost idempotent 
+ */
+
+int UV_CopyVolume(afs_int32 afromvol, afs_int32 afromserver, 
+       afs_int32 afrompart, char *atovolname, afs_int32 atoserver, afs_int32 atopart)
+{
+    struct rx_connection *toconn, *fromconn ;
+    afs_int32                fromtid, totid, clonetid;
+    char                 vname[64];
+    char                 tmpName[VOLSER_MAXVOLNAME +1];
+    afs_int32                rcode;
+    afs_int32                fromDate;
+    struct restoreCookie cookie;
+    register afs_int32       vcode, code;
+    afs_int32                cloneVol, newVol;
+    struct volser_status tstatus;
+    struct destServer    destination;
+
+    struct nvldbentry    entry, newentry, storeEntry;
+    int                  i, islocked, pntg;
+    afs_int32                error;
+    char                 in,lf;                                /* for test code */
+    int                  same;
+       int justclone = 0;
+
+    islocked = 0;
+    fromconn = (struct rx_connection *)0;
+    toconn   = (struct rx_connection *)0;
+    fromtid  = 0;
+    totid    = 0;
+    clonetid = 0;
+    error    = 0;
+    pntg     = 0;
+    newVol   = 0;
+
+    /* support control-c processing */
+    if (setjmp(env)) goto mfail;
+    (void) signal(SIGINT,sigint_handler);
+    vcode = VLDB_GetEntryByID(afromvol, -1, &entry);
+    EGOTO1(mfail, vcode, "Could not fetch the entry for the volume  %u from the VLDB \n", afromvol);
+    MapHostToNetwork(&entry);
+
+    pntg = 1;
+    toconn   = UV_Bind(atoserver,   AFSCONF_VOLUMEPORT); /* get connections to the servers */
+    fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
+    fromtid = totid = 0;       /* initialize to uncreated */
+
+
+       /* check if we can shortcut and use a local clone instead of a full copy */
+       if ( afromserver == atoserver && afrompart == atopart )
+       {
+               justclone = 1;
+       }
+
+    /* ***
+     * clone the read/write volume locally.
+     * ***/
+
+    VPRINT1("Starting transaction on source volume %u ...", afromvol);
+    code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
+    EGOTO1(mfail, code, "Failed to create transaction on the volume %u\n", afromvol);
+    VDONE;
+
+    /* Get a clone id */
+    VPRINT1("Allocating new volume id for clone of volume %u ...", afromvol);
+    newVol = 0;
+    vcode = ubik_Call (VL_GetNewVolumeId, cstruct, 0, 1, &cloneVol);
+    EGOTO1(mfail, vcode, "Could not get an ID for the clone of volume %u from the VLDB\n", afromvol);
+    VDONE;
+
+    /* Get a new volume id */
+    VPRINT1("Allocating new volume id for copy of volume %u ...", afromvol);
+    newVol = 0;
+    vcode = ubik_Call (VL_GetNewVolumeId, cstruct, 0, 1, &newVol);
+    EGOTO1(mfail, vcode, "Could not get an ID for the copy of volume %u from the VLDB\n", afromvol);
+    VDONE;
+
+    /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
+    VPRINT1("Cloning source volume %u ...", afromvol);
+    strcpy(vname, "copy-clone-temp");
+    code = AFSVolClone(fromconn, fromtid, 0,readonlyVolume, vname, &cloneVol);
+    EGOTO1(mfail, code, "Failed to clone the source volume %u\n", afromvol);
+    VDONE;
+
+    VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
+    rcode = 0;
+    code = AFSVolEndTrans(fromconn, fromtid, &rcode);
+    fromtid = 0;
+    if (!code) code = rcode;
+    EGOTO1(mfail, code, "Failed to end the transaction on the source volume %u\n", afromvol);
+    VDONE;
+
+    /* ***
+     * Create the destination volume
+     * ***/
+
+    VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
+    code = AFSVolTransCreate (fromconn, cloneVol, afrompart, ITOffline, &clonetid);
+    EGOTO1(mfail, code, "Failed to start a transaction on the cloned volume%u\n", cloneVol);
+    VDONE;
+
+    VPRINT1("Setting flags on cloned volume %u ...", cloneVol);
+    code = AFSVolSetFlags (fromconn, clonetid, VTDeleteOnSalvage|VTOutOfService); /*redundant */
+    EGOTO1(mfail, code, "Could not set falgs on the cloned volume %u\n", cloneVol);
+    VDONE;
+
+    /* remember time from which we've dumped the volume */
+    VPRINT1("Getting status of cloned volume %u ...", cloneVol);
+    code = AFSVolGetStatus (fromconn, clonetid, &tstatus);
+    EGOTO1(mfail, code, "Failed to get the status of the cloned volume %u\n", cloneVol);
+    VDONE;
+
+    fromDate = tstatus.creationDate-CLOCKSKEW;
+
+    /* create a volume on the target machine */
+    code = AFSVolTransCreate (toconn, newVol, atopart, ITOffline, &totid);
+    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 ...", newVol);
+               code = AFSVolDeleteVolume(toconn, totid);
+               EGOTO1(mfail, code, "Could not delete the pre-existing volume %u on destination\n", newVol);
+               VDONE;
+
+               VPRINT1("Ending transaction on pre-existing volume %u on destination ...", newVol);
+               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",
+                          newVol);
+               VDONE;
+    }
+
+    VPRINT1("Creating the destination volume %u ...", newVol);
+    code = AFSVolCreateVolume (toconn, atopart, atovolname, volser_RW, newVol, &newVol, &totid);
+    EGOTO1(mfail, code, "Failed to create the destination volume %u\n", newVol);
+    VDONE;
+
+    strncpy(tmpName, atovolname, VOLSER_OLDMAXVOLNAME);
+
+    VPRINT1("Setting volume flags on destination volume %u ...", newVol);
+    code = AFSVolSetFlags (toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
+    EGOTO1(mfail, code, "Failed to set the flags on the destination volume %u\n", newVol);
+    VDONE;
+
+    /***
+     * Now dump the clone to the new volume
+     ***/
+
+    destination.destHost = ntohl(atoserver);
+    destination.destPort = AFSCONF_VOLUMEPORT;
+    destination.destSSID = 1;
+
+
+/* probably should have some code here that checks to see if we are copying to same server
+and partition - if so, just use a clone to save disk space */
+
+    /* Copy the clone to the new volume */
+    VPRINT2("Dumping from clone %u on source to volume %u on destination ...", cloneVol, newVol);
+    strncpy(cookie.name,tmpName,VOLSER_OLDMAXVOLNAME);
+    cookie.type   = RWVOL;
+    cookie.parent = 0;
+    cookie.clone  = 0;
+    code = AFSVolForward(fromconn, clonetid, 0, &destination, totid, &cookie);
+    EGOTO1(mfail, code, "Failed to move data for the volume %u\n", newVol);
+    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;
+
+    /* ***
+     * reattach to the main-line volume, and incrementally dump it.
+     * ***/
+
+    VPRINT1("Starting transaction on source volume %u ...", afromvol);
+    code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
+    EGOTO1(mfail, code, "Failed to create a transaction on the source volume %u\n", afromvol);
+    VDONE;
+
+    /* now do the incremental */
+    VPRINT1("Doing the incremental dump from source to destination for volume %u ... ", afromvol);
+    code = AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,&cookie);
+    EGOTO(mfail, code, "Failed to do the incremental dump from rw volume on old site to rw volume on newsite\n");
+    VDONE;
+
+    VPRINT1("Setting volume flags on destination volume %u ...", newVol);
+    code = AFSVolSetFlags(toconn, totid, 0);
+    EGOTO(mfail, code, "Failed to set the flags to make destination volume online\n");
+    VDONE;
+
+    /* put new volume online */
+    VPRINT1("Ending transaction on destination volume %u ...", newVol);
+    code = AFSVolEndTrans(toconn, totid, &rcode);
+    totid = 0;
+    if (!code) code = rcode;
+    EGOTO1(mfail, code, "Failed to end the transaction on the destination volume %u\n", newVol);
+    VDONE;
+
+    VPRINT1("Ending transaction on source volume %u ...", afromvol);
+    code = AFSVolEndTrans(fromconn, fromtid, &rcode);
+    fromtid = 0;
+    if (!code) code = rcode;
+    EGOTO1(mfail, code, "Failed to end the transaction on the source volume %u\n", afromvol);
+    VDONE;
+
+    fromtid = 0;
+    VPRINT1("Starting transaction on the cloned volume %u ...", cloneVol);
+    code = AFSVolTransCreate(fromconn, cloneVol, afrompart, ITOffline, &clonetid);
+    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;
+
+       /* create the vldb entry for the copied volume */
+    strncpy(newentry.name, atovolname, VOLSER_OLDMAXVOLNAME);
+    newentry.nServers = 1;
+    newentry.serverNumber[0] = atoserver;
+    newentry.serverPartition[0] = atopart;
+    newentry.flags = RW_EXISTS;/* this records that rw volume exists */
+    newentry.serverFlags[0] = ITSRWVOL;        /*this rep site has rw vol */
+    newentry.volumeId[RWVOL] = newVol;
+    newentry.volumeId[ROVOL] = 0;
+    newentry.volumeId[BACKVOL] = 0;
+    newentry.cloneId = 0;
+    /*map into right byte order, before passing to xdr, the stuff has to be in host
+      byte order. Xdr converts it into network order */
+    MapNetworkToHost(&newentry,&storeEntry);
+    /* create the vldb entry */
+    vcode = VLDB_CreateEntry(&storeEntry);
+    if(vcode) {
+               fprintf(STDERR,"Could not create a VLDB entry for the volume %s %u\n", atovolname,newVol);
+               /*destroy the created volume*/
+               VPRINT1("Deleting the newly created volume %u\n",newVol);
+               AFSVolDeleteVolume(toconn,totid);
+               error = vcode;
+               goto mfail;
+    }
+    VPRINT2("Created the VLDB entry for the volume %s %u\n",atovolname,newVol);
+
+    /* normal cleanup code */
+    
+    if (fromtid) 
+    {
+       VPRINT1("Cleanup: Ending transaction on source volume %u ...", afromvol);
+       code = AFSVolEndTrans(fromconn, fromtid, &rcode);
+       if (code || rcode)
+       {
+           VPRINT("\n");
+           fprintf(STDERR,"Could not end transaction on the source volume %u\n", afromvol);
+           if (!error) error = (code ? code : rcode);
+       }
+       VDONE;
+    }
+
+    if (clonetid) 
+    {
+       VPRINT1("Cleanup: Ending transaction on clone volume %u ...", cloneVol);
+       code = AFSVolEndTrans(fromconn, clonetid, &rcode);
+       if (code || rcode) 
+       {
+           VPRINT("\n");
+           fprintf(STDERR,"Could not end transaction on the source's clone volume %u\n",cloneVol);
+           if (!error) error = (code ? code : rcode);
+       }
+       VDONE;
+    }
+
+    if (totid) 
+    {
+       VPRINT1("Cleanup: Ending transaction on destination volume %u ...", newVol);
+       code = AFSVolEndTrans(toconn, totid, &rcode);
+       if (code) 
+       {
+           VPRINT("\n");
+           fprintf(STDERR,"Could not end transaction on destination volume %u\n", newVol);
+           if (!error) error = (code ? code : rcode);
+       }
+       VDONE;
+    }
+    if (fromconn) rx_DestroyConnection(fromconn);
+    if (toconn)   rx_DestroyConnection(toconn);
+    PrintError("",error);
+    return error;
+
+    /* come here only when the sky falls */
+mfail:
+
+    if (pntg) 
+    {
+       fprintf(STDOUT,"vos copy: operation interrupted, cleanup in progress...\n");
+       fprintf(STDOUT,"clear transaction contexts\n");
+       fflush(STDOUT);
+    }
+
+    if (clonetid)
+    {
+       VPRINT("Recovery: Ending transaction on clone volume ...");
+       AFSVolEndTrans(fromconn, clonetid, &rcode);
+       VDONE;
+    }
+    if (totid)
+    {
+       VPRINT("Recovery: Ending transaction on destination volume ...");
+       AFSVolEndTrans(toconn, totid, &rcode);
+       VDONE;
+    }
+    if (fromtid)
+    {  /* put it on-line */
+               VPRINT("Recovery: Ending transaction on source volume ...");
+               AFSVolEndTrans(fromconn, fromtid, &rcode);
+               VDONE;
+    }
+
+    VPRINT("Recovery: Accessing VLDB.\n");
+    vcode= VLDB_GetEntryByID (afromvol, -1, &entry);
+    if (vcode)
+    {
+        fprintf(STDOUT,"FATAL: VLDB access error: abort cleanup\n");
+       fflush(STDOUT);
+       goto done;
+    }
+    MapHostToNetwork(&entry);
+
+    /* common cleanup - delete local clone */
+    if (cloneVol) {
+       VPRINT1("Recovery: Creating transaction on clone volume %u ...", cloneVol);
+        code = AFSVolTransCreate (fromconn, newVol, afrompart, ITOffline, &clonetid);
+       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);
+       }
+    }
+
+done:  /* routine cleanup */
+    if (fromconn) rx_DestroyConnection(fromconn);
+    if (toconn)   rx_DestroyConnection(toconn);
+
+    if (pntg) {
+       fprintf(STDOUT,"cleanup complete - user verify desired result\n");
+       fflush(STDOUT);
+    }
+    exit(1);
+}
+
+
+
+
+
 /* Make a new backup of volume <avolid> on <aserver> and <apart> 
  * if one already exists, update it 
  */
@@ -2599,27 +2980,34 @@ int UV_DumpVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart
 #endif
    (void) signal(SIGINT,  dump_sig_handler);
 
+   if (!fromdate)
+   {
+      VPRINT("Full Dump ...\n");
+   }
+   else 
+   {
+      VPRINT1("Incremental Dump (as of %.24s)...\n", ctime((time_t *)&fromdate));
+   }
+
    /* get connections to the servers */
    fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
+
+   VPRINT1("Starting transaction on volume %u...", afromvol);
    code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
    EGOTO1(error_exit, code, "Could not start transaction on the volume %u to be dumped\n", afromvol);
-
-  if (!fromdate)
-{      VPRINT("Full Dump ..."); }
-  else 
-{
-       VPRINT1("Incremental Dump (as of %.24s) ...",
-               ctime((time_t *)&fromdate));
-}
+   VDONE;
 
    fromcall = rx_NewCall(fromconn);
+
+   VPRINT1("Starting volume dump on volume %u...", afromvol);
    code = StartAFSVolDump(fromcall, fromtid, fromdate);
    EGOTO(error_exit, code, "Could not start the dump process \n");
+   VDONE;
 
+   VPRINT1("Dumping volume %u...", afromvol);
    code = DumpFunction(fromcall, rock);
    EGOTO(error_exit, code, "Error while dumping volume \n");
-
-   VPRINT("completed\n");
+   VDONE;
 
  error_exit: 
    if (fromcall) {
@@ -2630,11 +3018,13 @@ int UV_DumpVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart
       }        
    }
    if (fromtid) {
+      VPRINT1("Ending transaction on volume %u...", afromvol);
       code = AFSVolEndTrans(fromconn, fromtid, &rcode);
       if (code || rcode) {
         fprintf(STDERR,"Could not end transaction on the volume %u\n", afromvol);
         if (!error) error = (code?code:rcode);
       }
+      VDONE;
    }
    if (fromconn)
       rx_DestroyConnection(fromconn);
@@ -2643,6 +3033,128 @@ int UV_DumpVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart
    return(error);
 }
 
+/* Clone the volume <afromvol> on <afromserver> and
+ * <afrompart>, and then dump the clone volume to 
+ * <afilename> starting from <fromdate>.
+ * DumpFunction does the real work behind the scenes after
+ * extracting parameters from the rock 
+ */
+int UV_DumpClonedVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart, 
+       afs_int32 fromdate, afs_int32 (*DumpFunction)(), char *rock)
+{
+       struct rx_connection *fromconn = (struct rx_connection *)0;
+       struct rx_call       *fromcall = (struct rx_call *)0;
+       afs_int32 fromtid=0, rxError=0, rcode=0;
+       afs_int32 clonetid=0;
+       afs_int32 code=0, vcode=0, error = 0;
+       afs_int32 clonevol=0;
+    char vname[64];
+
+       if (setjmp(env)) ERROR_EXIT(EPIPE);
+#ifndef AFS_NT40_ENV
+       (void) signal(SIGPIPE, dump_sig_handler);
+#endif
+       (void) signal(SIGINT,  dump_sig_handler);
+
+       if (!fromdate)
+       {
+         VPRINT("Full Dump ...\n");
+       }
+       else 
+       {
+         VPRINT1("Incremental Dump (as of %.24s)...\n", ctime((time_t *)&fromdate));
+       }
+
+       /* get connections to the servers */
+       fromconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
+
+       VPRINT1("Starting transaction on volume %u...", afromvol);
+       code = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
+       EGOTO1(error_exit, code, "Could not start transaction on the volume %u to be dumped\n", afromvol);
+       VDONE;
+
+    /* Get a clone id */
+    VPRINT1("Allocating new volume id for clone of volume %u ...", afromvol);
+    code = ubik_Call (VL_GetNewVolumeId, cstruct, 0, 1, &clonevol);
+    EGOTO1(error_exit, code, "Could not get an ID for the clone of volume %u from the VLDB\n", afromvol);
+    VDONE;
+
+    /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
+    VPRINT2("Cloning source volume %u to clone volume %u...", afromvol, clonevol);
+    strcpy(vname, "dump-clone-temp");
+    code = AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &clonevol);
+    EGOTO1(error_exit, code, "Failed to clone the source volume %u\n", afromvol);
+    VDONE;
+
+    VPRINT1("Ending the transaction on the volume %u ...", afromvol);
+    rcode = 0;
+    code = AFSVolEndTrans(fromconn, fromtid, &rcode);
+    fromtid = 0;
+    if (!code) code = rcode;
+    EGOTO1(error_exit, code, "Failed to end the transaction on the volume %u\n", afromvol);
+    VDONE;
+
+
+    VPRINT1("Starting transaction on the cloned volume %u ...", clonevol);
+    code = AFSVolTransCreate (fromconn, clonevol, afrompart, ITOffline, &clonetid);
+    EGOTO1(error_exit, code, "Failed to start a transaction on the cloned volume%u\n", clonevol);
+    VDONE;
+
+    VPRINT1("Setting flags on cloned volume %u ...", clonevol);
+    code = AFSVolSetFlags (fromconn, clonetid, VTDeleteOnSalvage|VTOutOfService); /*redundant */
+    EGOTO1(error_exit, code, "Could not set falgs on the cloned volume %u\n", clonevol);
+    VDONE;
+
+
+       fromcall = rx_NewCall(fromconn);
+
+       VPRINT1("Starting volume dump from cloned volume %u...", clonevol);
+       code = StartAFSVolDump(fromcall, clonetid, fromdate);
+       EGOTO(error_exit, code, "Could not start the dump process \n");
+       VDONE;
+
+       VPRINT1("Dumping volume %u...", afromvol);
+       code = DumpFunction(fromcall, rock);
+       EGOTO(error_exit, code, "Error while dumping volume \n");
+       VDONE;
+
+ error_exit: 
+    /* now delete the clone */
+    VPRINT1("Deleting the cloned volume %u ...", clonevol);
+    code = AFSVolDeleteVolume(fromconn, clonetid);
+       if ( code )
+       {       
+           fprintf(STDERR,"Failed to delete the cloned volume %u\n", clonevol);
+       }
+       else
+       {
+           VDONE;
+       }
+
+       if (fromcall) {
+               code = rx_EndCall(fromcall, rxError);
+               if (code) {
+                       fprintf(STDERR,"Error in rx_EndCall\n");
+                       if (!error) error = code;
+               }       
+       }
+       if (fromtid) {
+               VPRINT1("Ending transaction on cloned volume %u...", clonevol);
+               code = AFSVolEndTrans(fromconn, clonetid, &rcode);
+               if (code || rcode) {
+                       fprintf(STDERR,"Could not end transaction on the cloned volume %u\n", clonevol);
+                       if (!error) error = (code?code:rcode);
+               }
+               VDONE;
+       }
+       if (fromconn)
+               rx_DestroyConnection(fromconn);
+
+       PrintError("", error);
+       return(error);
+}
+
+
 
 /*
  * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from