#include <afs/voldefs.h>
#include <rx/xdr.h>
#include <rx/rx.h>
+#include <rx/rx_queue.h>
#include <afs/vlserver.h>
#include <afs/nfs.h>
#include <afs/cellconfig.h>
struct rx_connection *aconn;
afs_int32 code = 0;
- aconn = (struct rx_connection *)0;
aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
code = AFSVolPartitionInfo64(aconn, pname, partition);
if (code == RXGEN_OPCODE) {
- struct diskPartition *dpp =
- (struct diskPartition *)malloc(sizeof(struct diskPartition));
+ struct diskPartition *dpp = malloc(sizeof(struct diskPartition));
code = AFSVolPartitionInfo(aconn, pname, dpp);
if (!code) {
strncpy(partition->name, dpp->name, 32);
struct volintInfo tstatus;
tid = 0;
- aconn = (struct rx_connection *)0;
error = 0;
init_volintInfo(&tstatus);
/* rw,ro, bk id are related in the default case */
/* If caller specified RW id, but not RO/BK ids, have them be RW+1 and RW+2 */
lastid = *anewid;
+ if (aroid && *aroid != 0) {
+ lastid = max(lastid, *aroid);
+ }
+ if (abkid && *abkid != 0) {
+ lastid = max(lastid, *abkid);
+ }
if (aroid && *aroid == 0) {
*aroid = ++lastid;
}
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 */
+ totid = 0; /* initialize to uncreated */
/* ***
* clone the read/write volume locally.
/* Get a clone id */
VPRINT1("Allocating new volume id for clone of volume %u ...",
afromvol);
- newVol = tmpVol = 0;
+ tmpVol = 0;
vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &tmpVol);
newVol = tmpVol;
EGOTO1(mfail, vcode,
}
if (volid && toconn)
- code = DoVolDelete(toconn, volid, atopart,
- "destination", 0, NULL, "Recovery:");
+ DoVolDelete(toconn, volid, atopart,
+ "destination", 0, NULL, "Recovery:");
/* put source volume on-line */
if (fromconn) {
/* delete backup volume */
if (fromconn) {
- code = DoVolDelete(fromconn, backupId, afrompart,
- "backup", 0, NULL, "Recovery:");
+ DoVolDelete(fromconn, backupId, afrompart,
+ "backup", 0, NULL, "Recovery:");
- code = DoVolDelete(fromconn, afromvol, afrompart, "source",
- (atoserver != afromserver)?atoserver:0,
- NULL, NULL);
+ DoVolDelete(fromconn, afromvol, afrompart, "source",
+ (atoserver != afromserver)?atoserver:0,
+ NULL, NULL);
}
}
/* common cleanup - delete local clone */
- if (newVol) {
- code = DoVolDelete(fromconn, newVol, afrompart,
- "clone", 0, NULL, "Recovery:");
- }
+ if (newVol)
+ DoVolDelete(fromconn, newVol, afrompart,
+ "clone", 0, NULL, "Recovery:");
/* unlock VLDB entry */
if (islocked) {
ubik_VL_ReleaseLock(cstruct, 0, afromvol, -1,
(LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
VDONE;
- islocked = 0;
}
done: /* routine cleanup */
if (volName)
manyDests tr;
manyResults results;
int rwindex, roindex, roclone, roexists;
- afs_uint32 rwcrdate = 0;
+ afs_uint32 rwcrdate = 0, rwupdate = 0;
afs_uint32 clcrdate;
struct rtime {
int validtime;
char hoststr[16];
afs_int32 origflags[NMAXNSERVERS];
struct volser_status orig_status;
+ int notreleased = 0;
+ int tried_justnewsites = 0;
+ int justnewsites = 0; /* are we just trying to release to new RO sites? */
memset(remembertime, 0, sizeof(remembertime));
memset(&results, 0, sizeof(results));
if (entry.serverFlags[i] & ITSROVOL) {
m++;
if (entry.serverFlags[i] & NEW_REPSITE) s++;
+ if (entry.serverFlags[i] & RO_DONTUSE) notreleased++;
}
origflags[i] = entry.serverFlags[i];
}
if ((forceflag && !fullrelease) || (s == m) || (s == 0))
fullrelease = 1;
+ if (!forceflag && (s == m || s == 0)) {
+ if (notreleased && notreleased != m) {
+ /* we have some new unreleased sites. try to just release to those,
+ * if the RW has not changed */
+ justnewsites = 1;
+ }
+ }
+
/* Determine which volume id to use and see if it exists */
cloneVolId =
((fullrelease
}
}
+ if (fullrelease != 1) {
+ /* in case the RW has changed, and just to be safe */
+ justnewsites = 0;
+ }
+
if (verbose) {
switch (fullrelease) {
case 2:
case 1:
fprintf(STDOUT, "This is a complete release of volume %lu\n",
(unsigned long)afromvol);
+ if (justnewsites) {
+ tried_justnewsites = 1;
+ fprintf(STDOUT, "There are new RO sites; we will try to "
+ "only release to new sites\n");
+ }
break;
case 0:
fprintf(STDOUT, "This is a completion of a previous release\n");
}
if (fullrelease) {
+ afs_int32 oldest = 0;
/* If the RO clone exists, then if the clone is a temporary
* clone, delete it. Or if the RO clone is marked RO_DONTUSE
* (it was recently added), then also delete it. We do not
roexists = 0;
}
+ if (justnewsites) {
+ VPRINT("Querying old RO sites for update times...");
+ for (vldbindex = 0; vldbindex < entry.nServers; vldbindex++) {
+ volEntries volumeInfo;
+ struct rx_connection *conn;
+ afs_int32 crdate;
+
+ if (!(entry.serverFlags[vldbindex] & ITSROVOL)) {
+ continue;
+ }
+ if ((entry.serverFlags[vldbindex] & RO_DONTUSE)) {
+ continue;
+ }
+ conn = UV_Bind(entry.serverNumber[vldbindex], AFSCONF_VOLUMEPORT);
+ if (!conn) {
+ fprintf(STDERR, "Cannot establish connection to server %s\n",
+ hostutil_GetNameByINet(entry.serverNumber[vldbindex]));
+ justnewsites = 0;
+ break;
+ }
+ volumeInfo.volEntries_val = NULL;
+ volumeInfo.volEntries_len = 0;
+ code = AFSVolListOneVolume(conn, entry.serverPartition[vldbindex],
+ entry.volumeId[ROVOL],
+ &volumeInfo);
+ if (code) {
+ fprintf(STDERR, "Could not fetch information about RO vol %lu from server %s\n",
+ (unsigned long)entry.volumeId[ROVOL],
+ hostutil_GetNameByINet(entry.serverNumber[vldbindex]));
+ PrintError("", code);
+ justnewsites = 0;
+ rx_DestroyConnection(conn);
+ break;
+ }
+
+ crdate = CLOCKADJ(volumeInfo.volEntries_val[0].creationDate);
+
+ if (oldest == 0 || crdate < oldest) {
+ oldest = crdate;
+ }
+
+ rx_DestroyConnection(conn);
+ free(volumeInfo.volEntries_val);
+ volumeInfo.volEntries_val = NULL;
+ volumeInfo.volEntries_len = 0;
+ }
+ VDONE;
+ }
+ if (justnewsites) {
+ volEntries volumeInfo;
+ volumeInfo.volEntries_val = NULL;
+ volumeInfo.volEntries_len = 0;
+ code = AFSVolListOneVolume(fromconn, afrompart, afromvol,
+ &volumeInfo);
+ if (code) {
+ fprintf(STDERR, "Could not fetch information about RW vol %lu from server %s\n",
+ (unsigned long)afromvol,
+ hostutil_GetNameByINet(afromserver));
+ PrintError("", code);
+ justnewsites = 0;
+ } else {
+ rwupdate = volumeInfo.volEntries_val[0].updateDate;
+
+ free(volumeInfo.volEntries_val);
+ volumeInfo.volEntries_val = NULL;
+ volumeInfo.volEntries_len = 0;
+ }
+ }
+ if (justnewsites && oldest <= rwupdate) {
+ /* RW has changed */
+ justnewsites = 0;
+ }
+
/* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
* write this entry out to the vlserver until after the first
* RO volume is released (temp RO clones don't count).
+ *
+ * If 'justnewsites' is set, we're only updating sites that have
+ * RO_DONTUSE set, so set NEW_REPSITE for all of the others.
*/
for (i = 0; i < entry.nServers; i++) {
- entry.serverFlags[i] &= ~NEW_REPSITE;
- entry.serverFlags[i] |= RO_DONTUSE;
+ if (justnewsites) {
+ if ((entry.serverFlags[i] & RO_DONTUSE)) {
+ entry.serverFlags[i] &= ~NEW_REPSITE;
+ } else {
+ entry.serverFlags[i] |= NEW_REPSITE;
+ }
+ } else {
+ entry.serverFlags[i] &= ~NEW_REPSITE;
+ entry.serverFlags[i] |= RO_DONTUSE;
+ }
}
entry.serverFlags[rwindex] |= NEW_REPSITE;
entry.serverFlags[rwindex] &= ~RO_DONTUSE;
+ }
+
+ if (justnewsites && roexists) {
+ /* if 'justnewsites' and 'roexists' are set, we don't need to do
+ * anything with the RO clone, so skip the reclone */
+ /* noop */
+
+ } else if (fullrelease) {
if (roclone) {
strcpy(vname, entry.name);
goto rfail;
}
+ if (justnewsites && rwupdate != volstatus.updateDate) {
+ justnewsites = 0;
+ /* reset the serverFlags as if 'justnewsites' had never been set */
+ for (i = 0; i < entry.nServers; i++) {
+ entry.serverFlags[i] &= ~NEW_REPSITE;
+ entry.serverFlags[i] |= RO_DONTUSE;
+ }
+ entry.serverFlags[rwindex] |= NEW_REPSITE;
+ entry.serverFlags[rwindex] &= ~RO_DONTUSE;
+ }
+
rwcrdate = volstatus.creationDate;
/* Remember clone volume ID in case we fail or are interrupted */
* There is a fix in the 3.4 client that does not need this sleep
* anymore, but we don't know what clients we have.
*/
- if (entry.nServers > 2)
+ if (entry.nServers > 2 && !justnewsites)
sleep(5);
/* Mark the RO clone in the VLDB as a good site (already released) */
}
}
+ if (justnewsites) {
+ VPRINT("RW vol has not changed; only releasing to new RO sites\n");
+ /* act like this is a completion of a previous release */
+ fullrelease = 0;
+ } else if (tried_justnewsites) {
+ VPRINT("RW vol has changed; releasing to all sites\n");
+ }
+
/* Now we will release from the clone to the remaining RO replicas.
* The first 2 ROs (counting the non-temporary RO clone) are released
* individually: releasecount. This is to reduce the race condition
cookie.clone = 0;
/* how many to do at once, excluding clone */
- if (stayUp)
+ if (stayUp || justnewsites)
nservers = entry.nServers; /* can do all, none offline */
else
nservers = entry.nServers / 2;
for (volcount = 0;
((volcount < nservers) && (vldbindex < entry.nServers));
vldbindex++) {
- if (!stayUp) {
+ if (!stayUp && !justnewsites) {
/* The first two RO volumes will be released individually.
* The rest are then released in parallel. This is a hack
* for clients not recognizing right away when a RO volume
char tovolreal[VOLSER_OLDMAXVOLNAME];
afs_uint32 pvolid;
afs_int32 temptid, pparentid;
- int success;
struct nvldbentry entry, storeEntry;
afs_int32 error;
int islocked;
memset(&cookie, 0, sizeof(cookie));
islocked = 0;
- success = 0;
error = 0;
reuseID = 1;
tocall = (struct rx_call *)0;
- toconn = (struct rx_connection *)0;
tempconn = (struct rx_connection *)0;
totid = 0;
temptid = 0;
goto refail;
}
- success = 1;
fprintf(STDOUT, " done\n");
fflush(STDOUT);
- if (success && (!reuseID || (flags & RV_FULLRST))) {
+ if (!reuseID || (flags & RV_FULLRST)) {
/* Volume was restored on the file server, update the
* VLDB to reflect the change.
*/
afs_int32 code = 0;
afs_int32 success = 1;
- aconn = (struct rx_connection *)0;
aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
curPos = 0;
for (curPtr = volPtr; curPos < arraySize; curPtr++) {
afs_uint32 curCloneId = 0;
char cloneName[256]; /*max vol name */
- aconn = (struct rx_connection *)0;
aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
curPos = 0;
if ((volPtr->volFlags & REUSECLONEID) && (volPtr->volFlags & ENTRYVALID))
* We set the val field to a null pointer as a hint for the stub to
* allocate space.
*/
- code = 0;
*a_numEntsInResultP = 0;
*a_resultPP = (volintXInfo *) 0;
volumeXInfo.volXEntries_val = (volintXInfo *) 0;
afs_int32 code = 0;
volEntries volumeInfo;
- code = 0;
-
*resultPtr = (volintInfo *) 0;
volumeInfo.volEntries_val = (volintInfo *) 0; /*this hints the stub to allocate space */
volumeInfo.volEntries_len = 0;
* the info. Setting the val field to a null pointer tells the stub
* to allocate space for us.
*/
- code = 0;
*a_resultPP = (volintXInfo *) 0;
volumeXInfo.volXEntries_val = (volintXInfo *) 0;
volumeXInfo.volXEntries_len = 0;
if (code) {
if (code != VL_NOENT) {
fprintf(STDOUT,
- "Could not retreive the VLDB entry for volume %lu \n",
+ "Could not retrieve the VLDB entry for volume %lu \n",
(unsigned long)rwvolid);
ERROR_EXIT(code);
}