register struct cmd_syndesc *as;
{
- afs_int32 volid, fromserver, toserver, frompart, topart, code, err;
+ afs_int32 volid, fromserver, toserver, frompart, topart;
+ afs_int32 flags, code, err;
char fromPartName[10], toPartName[10];
struct diskPartition partition; /* for space check */
return ENOENT;
}
+ flags = 0;
+ if (as->parms[5].items) flags |= RV_NOCLONE;
+
/*
* check source partition for space to clone volume
*/
/* successful move still not guaranteed but shoot for it */
- code = UV_MoveVolume(volid, fromserver, frompart, toserver, topart);
+ code =
+ UV_MoveVolume2(volid, fromserver, frompart, toserver, topart, flags);
if (code) {
PrintDiagnostics("move", code);
return code;
CopyVolume(as)
register struct cmd_syndesc *as;
{
- afs_int32 volid, fromserver, toserver, frompart, topart, code, err;
+ afs_int32 volid, fromserver, toserver, frompart, topart, code, err, flags;
char fromPartName[10], toPartName[10], *tovolume;
struct nvldbentry entry;
struct diskPartition partition; /* for space check */
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);
+ as->parms[4].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);
+ as->parms[5].items->data);
return EINVAL;
}
if (!IsPartValid(topart, toserver, &code)) { /*check for validity of the partition */
else
fprintf(STDERR,
"vos : partition %s does not exist on the server\n",
- as->parms[4].items->data);
+ as->parms[5].items->data);
return ENOENT;
}
- /*
- * check source partition for space to clone volume
- */
+ flags = 0;
+ if (as->parms[6].items) flags |= RV_OFFLINE;
+ if (as->parms[7].items) flags |= RV_RDONLY;
+ if (as->parms[8].items) flags |= RV_NOCLONE;
MapPartIdIntoName(topart, toPartName);
MapPartIdIntoName(frompart, fromPartName);
/* successful copy still not guaranteed but shoot for it */
code =
- UV_CopyVolume(volid, fromserver, frompart, tovolume, toserver,
- topart);
+ UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
+ topart, 0, flags);
if (code) {
PrintDiagnostics("copy", code);
return code;
static
+ShadowVolume(as)
+ register struct cmd_syndesc *as;
+{
+ afs_int32 volid, fromserver, toserver, frompart, topart, tovolid;
+ afs_int32 code, err, flags;
+ char fromPartName[10], toPartName[10], toVolName[32], *tovolume;
+ struct nvldbentry entry;
+ struct diskPartition partition; /* for space check */
+ volintInfo *p, *q;
+
+ p = (volintInfo *) 0;
+ q = (volintInfo *) 0;
+
+ 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[3].items->data);
+ if (toserver == 0) {
+ fprintf(STDERR, "vos: server '%s' not found in host table\n",
+ as->parms[3].items->data);
+ return ENOENT;
+ }
+
+ 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[4].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;
+ }
+
+ if (as->parms[5].items) {
+ tovolume = as->parms[5].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;
+ }
+ } else {
+ /* use actual name of source volume */
+ code = UV_ListOneVolume(fromserver, frompart, volid, &p);
+ if (code) {
+ fprintf(STDERR, "vos:cannot access volume %lu\n",
+ (unsigned long)volid);
+ exit(1);
+ }
+ strcpy(toVolName, p->name);
+ tovolume = toVolName;
+ /* save p for size checks later */
+ }
+
+ if (as->parms[6].items) {
+ tovolid = vsu_GetVolumeID(as->parms[6].items->data, cstruct, &err);
+ if (tovolid == 0) {
+ if (err)
+ PrintError("", err);
+ else
+ fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+ as->parms[6].items->data);
+ if (p)
+ free(p);
+ return ENOENT;
+ }
+ } else {
+ tovolid = vsu_GetVolumeID(tovolume, cstruct, &err);
+ if (tovolid == 0) {
+ if (err)
+ PrintError("", err);
+ else
+ fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+ tovolume);
+ if (p)
+ free(p);
+ return ENOENT;
+ }
+ }
+
+ flags = RV_NOVLDB;
+ if (as->parms[7].items) flags |= RV_OFFLINE;
+ if (as->parms[8].items) flags |= RV_RDONLY;
+ if (as->parms[9].items) flags |= RV_NOCLONE;
+ if (as->parms[10].items) flags |= RV_CPINCR;
+
+ 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);
+
+ /* Don't do this again if we did it above */
+ if (!p) {
+ code = UV_ListOneVolume(fromserver, frompart, volid, &p);
+ if (code) {
+ fprintf(STDERR, "vos:cannot access volume %lu\n",
+ (unsigned long)volid);
+ exit(1);
+ }
+ }
+
+ /* OK if this fails */
+ code = UV_ListOneVolume(toserver, topart, tovolid, &q);
+
+ /* Treat existing volume size as "free" */
+ if (q)
+ p->size = (q->size < p->size) ? p->size - q->size : 0;
+
+ if (partition.free <= p->size) {
+ fprintf(STDERR,
+ "vos: no space on target partition %s to copy volume %lu\n",
+ toPartName, (unsigned long)volid);
+ free(p);
+ if (q) free(q);
+ exit(1);
+ }
+ free(p);
+ if (q) free(q);
+
+ /* successful copy still not guaranteed but shoot for it */
+
+ code =
+ UV_CopyVolume2(volid, fromserver, frompart, tovolume, toserver,
+ topart, tovolid, flags);
+ if (code) {
+ PrintDiagnostics("shadow", code);
+ return code;
+ }
+ MapPartIdIntoName(topart, toPartName);
+ MapPartIdIntoName(frompart, fromPartName);
+ fprintf(STDOUT, "Volume %lu shadowed from %s %s to %s %s \n",
+ (unsigned long)volid, as->parms[1].items->data, fromPartName,
+ as->parms[4].items->data, toPartName);
+
+ return 0;
+}
+
+
+static
+CloneVolume(as)
+ register struct cmd_syndesc *as;
+{
+ afs_int32 server, part, volid, cloneid, voltype;
+ char partName[10], *volname;
+ afs_int32 code, err, flags;
+ struct nvldbentry entry;
+
+ 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;
+ }
+
+ if (as->parms[1].items || as->parms[2].items) {
+ if (!as->parms[1].items || !as->parms[2].items) {
+ fprintf(STDERR,
+ "Must specify both -server and -partition options\n");
+ return -1;
+ }
+ server = GetServer(as->parms[1].items->data);
+ if (server == 0) {
+ fprintf(STDERR, "vos: server '%s' not found in host table\n",
+ as->parms[1].items->data);
+ return ENOENT;
+ }
+ part = volutil_GetPartitionID(as->parms[2].items->data);
+ if (part < 0) {
+ fprintf(STDERR, "vos: could not interpret partition name '%s'\n",
+ as->parms[2].items->data);
+ return EINVAL;
+ }
+ if (!IsPartValid(part, server, &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;
+ }
+ } else {
+ code = GetVolumeInfo(volid, &server, &part, &voltype, &entry);
+ if (code)
+ return code;
+ }
+
+ volname = 0;
+ if (as->parms[3].items) {
+ volname = as->parms[3].items->data;
+ if (strlen(volname) > VOLSER_OLDMAXVOLNAME - 1) {
+ fprintf(STDERR,
+ "vos: the name of the root volume %s exceeds the size limit of %d\n",
+ volname, VOLSER_OLDMAXVOLNAME - 1);
+ return E2BIG;
+ }
+ if (!VolNameOK(volname)) {
+ fprintf(STDERR,
+ "Illegal volume name %s, should not end in .readonly or .backup\n",
+ volname);
+ return EINVAL;
+ }
+ if (IsNumeric(volname)) {
+ fprintf(STDERR,
+ "Illegal volume name %s, should not be a number\n",
+ volname);
+ return EINVAL;
+ }
+ }
+
+ cloneid = 0;
+ if (as->parms[4].items) {
+ cloneid = vsu_GetVolumeID(as->parms[4].items->data, cstruct, &err);
+ if (cloneid == 0) {
+ if (err)
+ PrintError("", err);
+ else
+ fprintf(STDERR, "vos: can't find volume ID or name '%s'\n",
+ as->parms[4].items->data);
+ return ENOENT;
+ }
+ }
+
+ flags = 0;
+ if (as->parms[5].items) flags |= RV_OFFLINE;
+ if (as->parms[6].items) flags |= RV_RDONLY;
+
+
+ code =
+ UV_CloneVolume(server, part, volid, cloneid, volname, flags);
+
+ if (code) {
+ PrintDiagnostics("clone", code);
+ return code;
+ }
+ MapPartIdIntoName(part, partName);
+ fprintf(STDOUT, "Created clone for volume %lu\n",
+ as->parms[0].items->data);
+
+ return 0;
+}
+
+
+static
BackupVolume(as)
register struct cmd_syndesc *as;
{
"machine name on destination");
cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
"partition name on destination");
+ cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+ "copy live volume without cloning");
COMMONPARMS;
ts = cmd_CreateSyntax("copy", CopyVolume, 0, "copy a volume");
"machine name on destination");
cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
"partition name on destination");
+ cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+ "leave new volume offline");
+ cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+ "make new volume read-only");
+ cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+ "copy live volume without cloning");
+ COMMONPARMS;
+
+ ts = cmd_CreateSyntax("shadow", ShadowVolume, 0,
+ "make or update a shadow 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, "-toserver", CMD_SINGLE, 0,
+ "machine name on destination");
+ cmd_AddParm(ts, "-topartition", CMD_SINGLE, 0,
+ "partition name on destination");
+ cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
+ "volume name on destination");
+ cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
+ "volume ID on destination");
+ cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+ "leave shadow volume offline");
+ cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+ "make shadow volume read-only");
+ cmd_AddParm(ts, "-live", CMD_FLAG, CMD_OPTIONAL,
+ "copy live volume without cloning");
+ cmd_AddParm(ts, "-incremental", CMD_FLAG, CMD_OPTIONAL,
+ "do incremental update if target exists");
COMMONPARMS;
ts = cmd_CreateSyntax("backup", BackupVolume, 0,
cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
COMMONPARMS;
+ ts = cmd_CreateSyntax("clone", CloneVolume, 0,
+ "make clone of a volume");
+ cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
+ cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "server");
+ cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition");
+ cmd_AddParm(ts, "-toname", CMD_SINGLE, CMD_OPTIONAL,
+ "volume name on destination");
+ cmd_AddParm(ts, "-toid", CMD_SINGLE, CMD_OPTIONAL,
+ "volume ID on destination");
+ cmd_AddParm(ts, "-offline", CMD_FLAG, CMD_OPTIONAL,
+ "leave clone volume offline");
+ cmd_AddParm(ts, "-readonly", CMD_FLAG, CMD_OPTIONAL,
+ "make clone volume read-only, not readwrite");
+ COMMONPARMS;
+
ts = cmd_CreateSyntax("release", ReleaseVolume, 0, "release a volume");
cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
}
/* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
- * <atopart>. The operation is almost idempotent
+ * <atopart>. The operation is almost idempotent. The following
+ * flags are recognized:
+ *
+ * RV_NOCLONE - don't use a copy clone
*/
int
-UV_MoveVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
- afs_int32 atoserver, afs_int32 atopart)
+UV_MoveVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
+ afs_int32 atoserver, afs_int32 atopart, int flags)
{
struct rx_connection *toconn, *fromconn;
afs_int32 fromtid, totid, clonetid;
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, &newVol);
- EGOTO1(mfail, vcode,
- "Could not get an ID for the clone of volume %u from the VLDB\n",
- afromvol);
- VDONE;
+ if (!(flags & RV_NOCLONE)) {
+ /* 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, &newVol);
+ EGOTO1(mfail, vcode,
+ "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 */
- VPRINT1("Cloning source volume %u ...", afromvol);
- strcpy(vname, "move-clone-temp");
- code = AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &newVol);
- EGOTO1(mfail, code, "Failed to clone the source volume %u\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, "move-clone-temp");
+ code =
+ AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &newVol);
+ EGOTO1(mfail, code, "Failed to clone the source volume %u\n",
+ afromvol);
+ VDONE;
+ }
/* lookup the name of the volume we just cloned */
volid = afromvol;
code = AFSVolGetName(fromconn, fromtid, &volName);
- EGOTO1(mfail, code, "Failed to get the name of the volume %u\n", newVol);
+ EGOTO1(mfail, code, "Failed to get the name of the volume %u\n",
+ afromvol);
VPRINT1("Ending the transaction on the source volume %u ...", afromvol);
rcode = 0;
* Create the destination volume
* ***/
- VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
- code =
- AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
- EGOTO1(mfail, code,
- "Failed to start a transaction on the cloned volume%u\n", newVol);
- VDONE;
+ if (!(flags & RV_NOCLONE)) {
+ /* All of this is to get the fromDate */
+ VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
+ code =
+ AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline,
+ &clonetid);
+ EGOTO1(mfail, code,
+ "Failed to start a transaction on the cloned volume%u\n",
+ newVol);
+ VDONE;
- VPRINT1("Setting flags on cloned volume %u ...", newVol);
- code = AFSVolSetFlags(fromconn, clonetid, VTDeleteOnSalvage | VTOutOfService); /*redundant */
- EGOTO1(mfail, code, "Could not set falgs on the cloned volume %u\n",
- newVol);
- VDONE;
+ VPRINT1("Setting flags on cloned volume %u ...", newVol);
+ code =
+ AFSVolSetFlags(fromconn, clonetid,
+ VTDeleteOnSalvage | VTOutOfService); /*redundant */
+ EGOTO1(mfail, code, "Could not set flags on the cloned volume %u\n",
+ newVol);
+ VDONE;
- /* remember time from which we've dumped the volume */
- VPRINT1("Getting status of cloned volume %u ...", newVol);
- code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
- EGOTO1(mfail, code, "Failed to get the status of the cloned volume %u\n",
- newVol);
- VDONE;
+ /* remember time from which we've dumped the volume */
+ VPRINT1("Getting status of cloned volume %u ...", newVol);
+ code = AFSVolGetStatus(fromconn, clonetid, &tstatus);
+ EGOTO1(mfail, code,
+ "Failed to get the status of the cloned volume %u\n",
+ newVol);
+ VDONE;
+
+ fromDate = tstatus.creationDate - CLOCKSKEW;
+ } else {
+ /* With RV_NOCLONE, just do a full copy from the source */
+ fromDate = 0;
+ }
- fromDate = tstatus.creationDate - CLOCKSKEW;
#ifdef ENABLE_BUGFIX_1165
/*
destination.destPort = AFSCONF_VOLUMEPORT;
destination.destSSID = 1;
- /* Copy the clone to the new volume */
- VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
- newVol, afromvol);
strncpy(cookie.name, tmpName, VOLSER_OLDMAXVOLNAME);
cookie.type = RWVOL;
cookie.parent = entry.volumeId[RWVOL];
cookie.clone = 0;
- code = AFSVolForward(fromconn, clonetid, 0, &destination, totid, &cookie);
- EGOTO1(mfail, code, "Failed to move data for the volume %u\n", volid);
- 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;
+ if (!(flags & RV_NOCLONE)) {
+ /* Copy the clone to the new volume */
+ VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
+ newVol, afromvol);
+ code =
+ AFSVolForward(fromconn, clonetid, 0, &destination, totid,
+ &cookie);
+ EGOTO1(mfail, code, "Failed to move data for the volume %u\n", volid);
+ 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;
+ }
/* ***
* reattach to the main-line volume, and incrementally dump it.
VDONE;
/* now do the incremental */
- VPRINT1
- ("Doing the incremental dump from source to destination for volume %u ... ",
+ VPRINT2
+ ("Doing the%s dump from source to destination for volume %u ... ",
+ (flags & RV_NOCLONE) ? "" : " incremental",
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");
+ EGOTO1(mfail, code,
+ "Failed to do the%s dump from rw volume on old site to rw volume on newsite\n",
+ (flags & RV_NOCLONE) ? "" : " incremental");
VDONE;
/* now adjust the flags so that the new volume becomes official */
code = 0; /* no backup volume? that's okay */
fromtid = 0;
- VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
- code =
- AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
- EGOTO1(mfail, code,
- "Failed to start a transaction on the cloned volume%u\n", newVol);
- VDONE;
+ if (!(flags & RV_NOCLONE)) {
+ VPRINT1("Starting transaction on the cloned volume %u ...", newVol);
+ code =
+ AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline,
+ &clonetid);
+ 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;
+ /* 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;
+ 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;
+ }
/* fall through */
/* END OF MOVE */
if (code || rcode) {
VPRINT("\n");
fprintf(STDERR,
- "Could not end transaction on the source's clone volume %lu\n",
- (unsigned long)newVol);
+ "Could not end transaction on the source volume %lu\n",
+ (unsigned long)afromvol);
if (!error)
error = (code ? code : rcode);
}
}
-/* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
- * <atopart>. The operation is almost idempotent
- */
+int
+UV_MoveVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
+ afs_int32 atoserver, afs_int32 atopart)
+{
+ return UV_MoveVolume2(afromvol, afromserver, afrompart,
+ atoserver, atopart, 0);
+}
+
+/* Copy volume <afromvol> from <afromserver> <afrompart> to <atoserver>
+ * <atopart>. The new volume is named by <atovolname>. The new volume
+ * has ID <atovolid> if that is nonzero; otherwise a new ID is allocated
+ * from the VLDB. the following flags are supported:
+ *
+ * RV_RDONLY - target volume is RO
+ * RV_OFFLINE - leave target volume offline
+ * RV_CPINCR - do incremental dump if target exists
+ * RV_NOVLDB - don't create/update VLDB entry
+ * RV_NOCLONE - don't use a copy clone
+ */
int
-UV_CopyVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
- char *atovolname, afs_int32 atoserver, afs_int32 atopart)
+UV_CopyVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
+ char *atovolname, afs_int32 atoserver, afs_int32 atopart,
+ afs_int32 atovolid, int flags)
{
struct rx_connection *toconn, *fromconn;
afs_int32 fromtid, totid, clonetid;
char vname[64];
- char tmpName[VOLSER_MAXVOLNAME + 1];
afs_int32 rcode;
- afs_int32 fromDate;
+ afs_int32 fromDate, cloneFromDate;
struct restoreCookie cookie;
register afs_int32 vcode, code;
- afs_int32 cloneVol, newVol;
+ afs_int32 cloneVol, newVol, volflag;
struct volser_status tstatus;
struct destServer destination;
* 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;
+ cloneVol = 0;
+ if (!(flags & RV_NOCLONE)) {
+ 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,
+ /* Get a clone id */
+ VPRINT1("Allocating new volume id for clone of volume %u ...",
+ afromvol);
+ cloneVol = 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;
+ 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;
+ if (atovolid) {
+ newVol = atovolid;
+ } else {
+ /* 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;
+ if (!(flags & RV_NOCLONE)) {
+ /* 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;
+ 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,
+ if (!(flags & RV_NOCLONE)) {
+ 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;
+ 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;
+ VPRINT1("Setting flags on cloned volume %u ...", cloneVol);
+ code =
+ AFSVolSetFlags(fromconn, clonetid,
+ VTDeleteOnSalvage | VTOutOfService); /*redundant */
+ EGOTO1(mfail, code, "Could not set flags 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;
+ /* 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;
+ fromDate = tstatus.creationDate - CLOCKSKEW;
+ } else {
+ fromDate = 0;
+ }
/* create a volume on the target machine */
+ cloneFromDate = 0;
code = AFSVolTransCreate(toconn, newVol, atopart, ITOffline, &totid);
if (!code) {
+ if ((flags & RV_CPINCR)) {
+ VPRINT1("Getting status of pre-existing volume %u ...", newVol);
+ code = AFSVolGetStatus(toconn, totid, &tstatus);
+ EGOTO1(mfail, code,
+ "Failed to get the status of the pre-existing volume %u\n",
+ newVol);
+ VDONE;
+
+ /* Using the update date should be OK here, but add some fudge */
+ cloneFromDate = tstatus.updateDate - CLOCKSKEW;
+ if ((flags & RV_NOCLONE))
+ fromDate = cloneFromDate;
+
+ /* XXX We should check that the source volume's creationDate is
+ * XXX not newer than the existing target volume, and if not,
+ * XXX throw away the existing target and do a full dump. */
+
+ goto cpincr;
+ }
+
/* 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
VPRINT1("Creating the destination volume %u ...", newVol);
code =
- AFSVolCreateVolume(toconn, atopart, atovolname, volser_RW, newVol,
- &newVol, &totid);
+ AFSVolCreateVolume(toconn, atopart, atovolname,
+ (flags & RV_RDONLY) ? volser_RO : 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));
"Failed to set the flags on the destination volume %u\n", newVol);
VDONE;
- /***
- * Now dump the clone to the new volume
- ***/
+cpincr:
destination.destHost = ntohl(atoserver);
destination.destPort = AFSCONF_VOLUMEPORT;
destination.destSSID = 1;
+ strncpy(cookie.name, atovolname, VOLSER_OLDMAXVOLNAME);
+ cookie.type = (flags & RV_RDONLY) ? ROVOL : RWVOL;
+ cookie.parent = 0;
+ cookie.clone = 0;
-/* 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 */
+ /***
+ * Now dump the clone to the new volume
+ ***/
- /* Copy the clone to the new volume */
- VPRINT2("Dumping from clone %u on source to volume %u on destination ...",
+ if (!(flags & RV_NOCLONE)) {
+ /* XXX probably should have some code here that checks to see if
+ * XXX we are copying to same server and partition - if so, just
+ * XXX 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;
+ code =
+ AFSVolForward(fromconn, clonetid, cloneFromDate, &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;
+ 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.
VDONE;
/* now do the incremental */
- VPRINT1
- ("Doing the incremental dump from source to destination for volume %u ... ",
+ VPRINT2
+ ("Doing the%s dump from source to destination for volume %u ... ",
+ (flags & RV_NOCLONE) ? "" : " incremental",
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");
+ EGOTO1(mfail, code,
+ "Failed to do the%s dump from old site to new site\n",
+ afromvol);
VDONE;
VPRINT1("Setting volume flags on destination volume %u ...", newVol);
- code = AFSVolSetFlags(toconn, totid, 0);
+ volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0); /* off or on-line */
+ code = AFSVolSetFlags(toconn, totid, volflag);
EGOTO(mfail, code,
"Failed to set the flags to make destination volume online\n");
VDONE;
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;
+ if (!(flags & RV_NOCLONE)) {
+ 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("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;
+ /* 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;
- /* 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 %lu\n",
- atovolname, (unsigned long)newVol);
- /*destroy the created volume */
- VPRINT1("Deleting the newly created volume %u\n", newVol);
- AFSVolDeleteVolume(toconn, totid);
- error = vcode;
- goto mfail;
+ 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;
+ }
+
+ if (!(flags & RV_NOVLDB)) {
+ /* 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 = (flags & RV_RDONLY) ? RO_EXISTS : RW_EXISTS;
+ newentry.serverFlags[0] = (flags & RV_RDONLY) ? ITSROVOL : ITSRWVOL;
+ newentry.volumeId[RWVOL] = newVol;
+ newentry.volumeId[ROVOL] = (flags & RV_RDONLY) ? newVol : 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 %lu\n",
+ atovolname, (unsigned long)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);
}
- VPRINT2("Created the VLDB entry for the volume %s %u\n", atovolname,
- newVol);
/* normal cleanup code */
}
+int
+UV_CopyVolume(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
+ char *atovolname, afs_int32 atoserver, afs_int32 atopart)
+{
+ return UV_CopyVolume2(afromvol, afromserver, afrompart,
+ atovolname, atoserver, atopart, 0, 0);
+}
return error;
}
+/* Make a new clone of volume <avolid> on <aserver> and <apart>
+ * using volume ID <acloneid>, or a new ID allocated from the VLDB.
+ * The new volume is named by <aname>, or by appending ".clone" to
+ * the existing name if <aname> is NULL. The following flags are
+ * supported:
+ *
+ * RV_RDONLY - target volume is RO
+ * RV_OFFLINE - leave target volume offline
+ */
+
+int
+UV_CloneVolume(afs_int32 aserver, afs_int32 apart, afs_int32 avolid,
+ afs_int32 acloneid, char *aname, int flags)
+{
+ struct rx_connection *aconn = (struct rx_connection *)0;
+ afs_int32 ttid = 0, btid = 0;
+ afs_int32 code = 0, rcode = 0;
+ char vname[VOLSER_MAXVOLNAME + 1];
+ afs_int32 error = 0;
+ int backexists = 1;
+ volEntries volumeInfo;
+
+ aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
+
+ if (!aname) {
+ volumeInfo.volEntries_val = (volintInfo *) 0;
+ volumeInfo.volEntries_len = 0;
+ code = AFSVolListOneVolume(aconn, apart, avolid, &volumeInfo);
+ if (code) {
+ fprintf(stderr, "Could not get info for volume %lu\n",
+ (unsigned long)avolid);
+ error = code;
+ goto bfail;
+ }
+ strncpy(vname, volumeInfo.volEntries_val[0].name,
+ VOLSER_OLDMAXVOLNAME - 7);
+ vname[VOLSER_OLDMAXVOLNAME - 7] = 0;
+ strcat(vname, ".clone");
+ aname = vname;
+ if (volumeInfo.volEntries_val)
+ free(volumeInfo.volEntries_val);
+ }
+
+ if (!acloneid) {
+ /* Get a clone id */
+ VPRINT1("Allocating new volume id for clone of volume %u ...",
+ avolid);
+ code = ubik_Call(VL_GetNewVolumeId, cstruct, 0, 1, &acloneid);
+ EGOTO1(bfail, code,
+ "Could not get an ID for the clone of volume %u from the VLDB\n",
+ 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(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;
+ }
+ }
+
+ /* Now go ahead and try to clone the RW volume.
+ * First start a transaction on the RW volume
+ */
+ code = AFSVolTransCreate(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 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(aconn, acloneid, apart, ITOffline, &btid);
+ if (code) {
+ fprintf(STDERR,
+ "Failed to start a transaction on the clone volume %lu\n",
+ (unsigned long)acloneid);
+ error = code;
+ goto bfail;
+ }
+
+ code = AFSVolSetFlags(aconn, btid, 0);
+ if (code) {
+ fprintf(STDERR, "Could not mark the clone volume %lu on line \n",
+ (unsigned long)acloneid);
+ error = code;
+ goto bfail;
+ }
+
+ code = AFSVolEndTrans(aconn, btid, &rcode);
+ btid = 0;
+ if (code || rcode) {
+ fprintf(STDERR,
+ "Failed to end the transaction on the clone volume %lu\n",
+ (unsigned long)acloneid);
+ error = (code ? code : rcode);
+ goto bfail;
+ }
+ }
+
+ VDONE;
+
+ bfail:
+ 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 clone volume %lu\n",
+ (unsigned long)acloneid);
+ if (!error)
+ error = (code ? code : rcode);
+ }
+ }
+
+ if (aconn)
+ rx_DestroyConnection(aconn);
+
+ PrintError("", error);
+ return error;
+}
+
static int
DelVol(struct rx_connection *conn, afs_int32 vid, afs_int32 part,
afs_int32 flags)