vos: vos release -force-reclone option
[openafs.git] / src / volser / vsprocs.c
index 9366dcb..18d47f3 100644 (file)
@@ -1338,6 +1338,159 @@ cfail:
     return error;
 }
 
+/* Convert volume from RO to RW; adjust the VLDB entry to match.
+ * The nvldbentry passed to us has already been MapHostToNetwork'd
+ * by the caller.
+ */
+
+int
+UV_ConvertRO(afs_uint32 server, afs_uint32 partition, afs_uint32 volid,
+               struct nvldbentry *entry)
+{
+    afs_int32 code, i, same;
+    struct nvldbentry checkEntry, storeEntry;
+    afs_int32 vcode;
+    afs_int32 rwindex = 0;
+    afs_uint32 rwserver = 0;
+    afs_int32 roindex = 0;
+    afs_uint32 roserver = 0;
+    struct rx_connection *aconn;
+
+    vcode =
+       ubik_VL_SetLock(cstruct, 0, entry->volumeId[RWVOL], RWVOL,
+                 VLOP_MOVE);
+    if (vcode) {
+       fprintf(STDERR,
+               "Unable to lock volume %lu, code %d\n",
+               (unsigned long)entry->volumeId[RWVOL],vcode);
+       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;
+    }
+
+    /* extract information from the original entry */
+    for (i = 0; i < entry->nServers; i++) {
+       if (entry->serverFlags[i] & ITSRWVOL) {
+           rwindex = i;
+           rwserver = entry->serverNumber[i];
+       /*  rwpartition = entry->serverPartition[i]; */
+           if (roserver)
+               break;
+       } else if ((entry->serverFlags[i] & ITSROVOL) && !roserver) {
+           same = VLDB_IsSameAddrs(server, entry->serverNumber[i], &code);
+           if (code) {
+               fprintf(STDERR,
+                       "Failed to get info about server's %d address(es) from vlserver (err=%d); aborting call!\n",
+                       server, code);
+               code = ENOENT;
+               goto error_exit;
+           }
+           if (same) {
+               roindex = i;
+               roserver = entry->serverNumber[i];
+       /*      ropartition = entry->serverPartition[i]; */
+               if (rwserver)
+                    break;
+           }
+       }
+    }
+
+    aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
+    code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
+    if (code) {
+       fprintf(STDERR,
+               "Converting RO volume %lu to RW volume failed with code %d\n",
+               (unsigned long)volid, code);
+       PrintError("convertROtoRW ", code);
+       goto error_exit;
+    }
+    /* 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) {
+           entry->serverNumber[rwindex] = entry->serverNumber[entry->nServers];
+           entry->serverPartition[rwindex] =
+               entry->serverPartition[entry->nServers];
+           entry->serverFlags[rwindex] = entry->serverFlags[entry->nServers];
+           entry->serverNumber[entry->nServers] = 0;
+           entry->serverPartition[entry->nServers] = 0;
+           entry->serverFlags[entry->nServers] = 0;
+       }
+    }
+    entry->flags &= ~RO_EXISTS;
+    for (i = 0; i < entry->nServers; i++) {
+       if (entry->serverFlags[i] & ITSROVOL) {
+           if (!(entry->serverFlags[i] & (RO_DONTUSE | NEW_REPSITE)))
+               entry->flags |= RO_EXISTS;
+       }
+    }
+    MapNetworkToHost(entry, &storeEntry);
+    code =
+       VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry,
+                         (LOCKREL_OPCODE | LOCKREL_AFSID |
+                          LOCKREL_TIMESTAMP));
+    if (code) {
+       fprintf(STDERR,
+               "Warning: volume converted, but vldb update failed with code %d!\n",
+               code);
+    }
+
+  error_exit:
+    vcode = UV_LockRelease(entry->volumeId[RWVOL]);
+    if (vcode) {
+       fprintf(STDERR,
+               "Unable to unlock volume %lu, code %d\n",
+               (unsigned long)entry->volumeId[RWVOL],vcode);
+       PrintError("", vcode);
+    }
+    return code;
+}
+
+
 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
  * <atopart>.  The operation is almost idempotent.  The following
  * flags are recognized:
@@ -3063,11 +3216,6 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
            goto fail;
        }
 
-       if (tmpVolId)
-           strcat(volname, ".roclone");
-       else
-           strcat(volname, ".readonly");
-
        if (verbose) {
            fprintf(STDOUT,
                    "Creating new volume %lu on replication site %s: ",
@@ -3301,23 +3449,31 @@ DoVolOnline(struct nvldbentry *vldbEntryPtr, afs_uint32 avolid, int index,
     return code;
 }
 
-/* UV_ReleaseVolume()
- *    Release volume <afromvol> on <afromserver> <afrompart> to all
- *    its RO sites (full release). Unless the previous release was
- *    incomplete: in which case we bring the remaining incomplete
- *    volumes up to date with the volumes that were released
- *    successfully.
- *    forceflag: Performs a full release.
+/**
+ * Release a volume to read-only sites
  *
- *    Will create a clone from the RW, then dump the clone out to
- *    the remaining replicas. If there is more than 1 RO sites,
- *    ensure that the VLDB says at least one RO is available all
- *    the time: Influences when we write back the VLDB entry.
+ * Release volume <afromvol> on <afromserver> <afrompart> to all
+ * its RO sites (full release). Unless the previous release was
+ * incomplete: in which case we bring the remaining incomplete
+ * volumes up to date with the volumes that were released
+ * successfully.
+ *
+ * Will create a clone from the RW, then dump the clone out to
+ * the remaining replicas. If there is more than 1 RO sites,
+ * ensure that the VLDB says at least one RO is available all
+ * the time: Influences when we write back the VLDB entry.
+ *
+ * @param[in] afromvol      volume to be released
+ * @param[in] afromserver   server containing afromvol
+ * @param[in] afrompart     partition containing afromvol
+ * @param[in] flags         bitmap of options
+ *                            REL_COMPLETE  - force a complete release
+ *                            REL_FULLDUMPS - force full dumps
+ *                            REL_STAYUP    - dump to clones to avoid offline time
  */
-
 int
 UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
-                afs_int32 afrompart, int forceflag, int stayUp)
+                afs_int32 afrompart, int flags)
 {
     char vname[64];
     afs_int32 code = 0;
@@ -3359,6 +3515,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     int justnewsites = 0; /* are we just trying to release to new RO sites? */
     int sites = 0; /* number of ro sites */
     int new_sites = 0; /* number of ro sites markes as new */
+    int stayUp = (flags & REL_STAYUP);
 
     typedef enum {
         CR_RECOVER    = 0x0000, /**< not complete: a recovery from a previous failed release */
@@ -3434,7 +3591,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
      * vldb flags.
      *
      * The caller can override the vldb flags check using the -force
-     * flag, to force this to be a complete release.
+     * or -force-reclone flag, to force this to be a complete release.
      */
     for (i = 0; i < entry.nServers; i++) {
        if (entry.serverFlags[i] & ITSROVOL) {
@@ -3447,7 +3604,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        origflags[i] = entry.serverFlags[i];
     }
 
-    if (forceflag) {
+    if (flags & REL_COMPLETE) {
        complete_release |= CR_FORCED;
     }
 
@@ -3461,7 +3618,8 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        && !(complete_release & CR_FORCED)) {
        if (notreleased && notreleased != sites) {
            /* we have some new unreleased sites. try to just release to those,
-            * if the RW has not changed. The caller can override with -force. */
+            * if the RW has not changed. The caller can override with -force
+            * or with -force-reclone. */
            justnewsites = 1;
        }
     }
@@ -3919,7 +4077,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                continue;
 
            /* Thisdate is the date from which we want to pick up all changes */
-           if (forceflag) {
+           if (flags & REL_FULLDUMPS) {
                /* Do a full dump when forced by the caller. */
                VPRINT("This will be a full dump: forced\n");
                thisdate = 0;
@@ -4394,7 +4552,7 @@ UV_DumpVolume(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
     struct rx_connection * volatile fromconn = NULL;
     afs_int32 volatile fromtid = 0;
 
-    afs_int32 rxError = 0, rcode = 0;
+    afs_int32 rcode = 0;
     afs_int32 code, error = 0;
     afs_int32 tmp;
     time_t tmv = fromdate;
@@ -4444,7 +4602,7 @@ UV_DumpVolume(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
 
   error_exit:
     if (fromcall) {
-       code = rx_EndCall(fromcall, rxError);
+       code = rx_EndCall(fromcall, 0);
        if (code && code != RXGEN_OPCODE)
            fprintf(STDERR, "Error in rx_EndCall\n");
        if (code && !error)
@@ -4489,7 +4647,7 @@ UV_DumpClonedVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     afs_uint32 volatile clonevol = 0;
 
     afs_int32 tmp;
-    afs_int32 fromtid = 0, rxError = 0, rcode = 0;
+    afs_int32 fromtid = 0, rcode = 0;
     afs_int32 code = 0, error = 0;
     afs_uint32 tmpVol;
     char vname[64];
@@ -4597,7 +4755,7 @@ UV_DumpClonedVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     }
 
     if (fromcall) {
-       code = rx_EndCall(fromcall, rxError);
+       code = rx_EndCall(fromcall, 0);
        if (code) {
            fprintf(STDERR, "Error in rx_EndCall\n");
            if (!error)
@@ -4639,7 +4797,6 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
     struct rx_connection *toconn, *tempconn;
     struct rx_call *tocall;
     afs_int32 totid, code, rcode, vcode, terror = 0;
-    afs_int32 rxError = 0;
     struct volser_status tstatus;
     struct volintInfo vinfo;
     char partName[10];
@@ -4785,7 +4942,7 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
        error = code;
        goto refail;
     }
-    terror = rx_EndCall(tocall, rxError);
+    terror = rx_EndCall(tocall, 0);
     tocall = (struct rx_call *)0;
     if (terror) {
        fprintf(STDERR, "rx_EndCall Failed \n");
@@ -5009,7 +5166,7 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
     }
   refail:
     if (tocall) {
-       code = rx_EndCall(tocall, rxError);
+       code = rx_EndCall(tocall, 0);
        if (!error)
            error = code;
     }