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;
{
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;
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;
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");
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
*/
#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) {
}
}
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);
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