afs_uint32 volid;
afs_uint32 server;
afs_int32 code, i, same;
- struct nvldbentry entry, storeEntry;
+ struct nvldbentry entry, checkEntry, storeEntry;
afs_int32 vcode;
afs_int32 rwindex = 0;
afs_uint32 rwserver = 0;
if (as->parms[3].items)
force = 1;
+ memset(&entry, 0, sizeof(entry));
vcode = VLDB_GetEntryByID(volid, -1, &entry);
if (vcode) {
fprintf(STDERR,
}
/* use RO volid even if user specified RW or BK volid */
-
if (volid != entry.volumeId[ROVOL])
volid = entry.volumeId[ROVOL];
if (!roserver) {
fprintf(STDERR, "Warning: RO volume didn't exist in vldb!\n");
}
- if (ropartition != partition) {
+ if (roserver && (ropartition != partition)) {
fprintf(STDERR,
"Warning: RO volume should be in partition %d instead of %d (vldb)\n",
ropartition, partition);
PrintError("", vcode);
return -1;
}
+
+ /* make sure the VLDB entry hasn't changed since we started */
+ memset(&checkEntry, 0, sizeof(checkEntry));
+ vcode = VLDB_GetEntryByID(volid, -1, &checkEntry);
+ if (vcode) {
+ fprintf(STDERR,
+ "Could not fetch the entry for volume %lu from VLDB\n",
+ (unsigned long)volid);
+ PrintError("convertROtoRW ", vcode);
+ code = vcode;
+ goto error_exit;
+ }
+
+ MapHostToNetwork(&checkEntry);
+ entry.flags &= ~VLOP_ALLOPERS; /* clear any stale lock operation flags */
+ entry.flags |= VLOP_MOVE; /* set to match SetLock operation above */
+ if (memcmp(&entry, &checkEntry, sizeof(entry)) != 0) {
+ fprintf(STDERR,
+ "VLDB entry for volume %lu has changed; please reissue the command.\n",
+ (unsigned long)volid);
+ code = -1;
+ goto error_exit;
+ }
+
aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
if (code) {
PrintError("convertROtoRW ", code);
goto error_exit;
}
- entry.serverFlags[roindex] = ITSRWVOL;
+ /* Update the VLDB to match what we did on disk as much as possible. */
+ /* If the converted RO was in the VLDB, make it look like the new RW. */
+ if (roserver) {
+ entry.serverFlags[roindex] = ITSRWVOL;
+ } else {
+ /* Add a new site entry for the newly created RW. It's possible
+ * (but unlikely) that we are already at MAXNSERVERS and that this
+ * new site will invalidate the whole VLDB entry; however,
+ * VLDB_ReplaceEntry will detect this and return VL_BADSERVER,
+ * so we need no extra guard logic here.
+ */
+ afs_int32 newrwindex = entry.nServers;
+ (entry.nServers)++;
+ entry.serverNumber[newrwindex] = server;
+ entry.serverPartition[newrwindex] = partition;
+ entry.serverFlags[newrwindex] = ITSRWVOL;
+ }
entry.flags |= RW_EXISTS;
entry.flags &= ~BACK_EXISTS;
+
+ /* if the old RW was in the VLDB, remove it by decrementing the number */
+ /* of servers, replacing the RW entry with the last entry, and zeroing */
+ /* out the last entry. */
if (rwserver) {
(entry.nServers)--;
if (rwindex != entry.nServers) {