volser: document 'vos restore -readonly' restriction
[openafs.git] / src / volser / vsprocs.c
index 6fb3ca1..a2c00ca 100644 (file)
@@ -159,11 +159,6 @@ do { \
 
 
 /* Protos for static routines */
-#if 0
-static afs_int32 CheckAndDeleteVolume(struct rx_connection *aconn,
-                                     afs_int32 apart, afs_uint32 okvol,
-                                     afs_uint32 delvol);
-#endif
 static int GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
                    struct rx_connection **connPtr, afs_int32 * transPtr,
                    afs_uint32 * crtimePtr, afs_uint32 * uptimePtr,
@@ -485,57 +480,6 @@ AFSVolTransCreate_retry(struct rx_connection *z_conn,
     return code;
 }
 
-#if 0
-/* if <okvol> is allright(indicated by beibg able to
- * start a transaction, delete the <delvol> */
-static afs_int32
-CheckAndDeleteVolume(struct rx_connection *aconn, afs_int32 apart,
-                    afs_uint32 okvol, afs_uint32 delvol)
-{
-    afs_int32 error, code, tid, rcode;
-    error = 0;
-    code = 0;
-
-    if (okvol == 0) {
-       code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
-       if (!error && code)
-           error = code;
-       code = AFSVolDeleteVolume(aconn, tid);
-       if (!error && code)
-           error = code;
-       code = AFSVolEndTrans(aconn, tid, &rcode);
-       if (!code)
-           code = rcode;
-       if (!error && code)
-           error = code;
-       return error;
-    } else {
-       code = AFSVolTransCreate_retry(aconn, okvol, apart, ITOffline, &tid);
-       if (!code) {
-           code = AFSVolEndTrans(aconn, tid, &rcode);
-           if (!code)
-               code = rcode;
-           if (!error && code)
-               error = code;
-           code = AFSVolTransCreate_retry(aconn, delvol, apart, ITOffline, &tid);
-           if (!error && code)
-               error = code;
-           code = AFSVolDeleteVolume(aconn, tid);
-           if (!error && code)
-               error = code;
-           code = AFSVolEndTrans(aconn, tid, &rcode);
-           if (!code)
-               code = rcode;
-           if (!error && code)
-               error = code;
-       } else
-           error = code;
-       return error;
-    }
-}
-
-#endif
-
 /* called by EmuerateEntry, show vldb entry in a reasonable format */
 void
 SubEnumerateEntry(struct nvldbentry *entry)
@@ -545,25 +489,6 @@ SubEnumerateEntry(struct nvldbentry *entry)
     int isMixed = 0;
     char hoststr[16];
 
-#ifdef notdef
-    fprintf(STDOUT, "  readWriteID %-10u ", entry->volumeId[RWVOL]);
-    if (entry->flags & VLF_RWEXISTS)
-       fprintf(STDOUT, " valid \n");
-    else
-       fprintf(STDOUT, " invalid \n");
-    fprintf(STDOUT, "  readOnlyID  %-10u ", entry->volumeId[ROVOL]);
-    if (entry->flags & VLF_ROEXISTS)
-       fprintf(STDOUT, " valid \n");
-    else
-       fprintf(STDOUT, " invalid \n");
-    fprintf(STDOUT, "  backUpID    %-10u ", entry->volumeId[BACKVOL]);
-    if (entry->flags & VLF_BACKEXISTS)
-       fprintf(STDOUT, " valid \n");
-    else
-       fprintf(STDOUT, " invalid \n");
-    if ((entry->cloneId != 0) && (entry->flags & VLF_ROEXISTS))
-       fprintf(STDOUT, "    releaseClone %-10u \n", entry->cloneId);
-#else
     if (entry->flags & VLF_RWEXISTS)
        fprintf(STDOUT, "    RWrite: %-10u", entry->volumeId[RWVOL]);
     if (entry->flags & VLF_ROEXISTS)
@@ -573,7 +498,6 @@ SubEnumerateEntry(struct nvldbentry *entry)
     if ((entry->cloneId != 0) && (entry->flags & VLF_ROEXISTS))
        fprintf(STDOUT, "    RClone: %-10lu", (unsigned long)entry->cloneId);
     fprintf(STDOUT, "\n");
-#endif
     fprintf(STDOUT, "    number of sites -> %lu\n",
            (unsigned long)entry->nServers);
     for (i = 0; i < entry->nServers; i++) {
@@ -868,13 +792,8 @@ UV_AddVLDBEntry(afs_uint32 aserver, afs_int32 apart, char *aname,
     entry.flags = VLF_RWEXISTS;        /* this records that rw volume exists */
     entry.serverFlags[0] = VLSF_RWVOL; /*this rep site has rw  vol */
     entry.volumeId[RWVOL] = aid;
-#ifdef notdef
-    entry.volumeId[ROVOL] = anewid + 1;        /* rw,ro, bk id are related in the default case */
-    entry.volumeId[BACKVOL] = *anewid + 2;
-#else
     entry.volumeId[ROVOL] = 0;
     entry.volumeId[BACKVOL] = 0;
-#endif
     entry.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 */
@@ -1570,8 +1489,9 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
        fflush(STDOUT);
        if (fscanf(stdin, "%c", &in) < 1)
            in = 0;
-       if (fscanf(stdin, "%c", &lf) < 0)       /* toss away */
-           ; /* don't care */
+       if (fscanf(stdin, "%c", &lf) < 0) {
+           /* toss away; don't care */
+       }
        if (in == 'y') {
            fprintf(STDOUT, "type control-c\n");
            while (1) {
@@ -1928,8 +1848,9 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
        fflush(STDOUT);
        if (fscanf(stdin, "%c", &in) < 1)
            in = 0;
-       if (fscanf(stdin, "%c", &lf) < 0)       /* toss away */
-           ; /* don't care */
+       if (fscanf(stdin, "%c", &lf) < 0) {
+           /* toss away, don't care */
+       }
        if (in == 'y') {
            fprintf(STDOUT, "type control-c\n");
            while (1) {
@@ -1963,8 +1884,9 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
        fflush(STDOUT);
        if (fscanf(stdin, "%c", &in) < 1)
            in = 0;
-       if (fscanf(stdin, "%c", &lf) < 0)       /* toss away */
-           ; /* don't care */
+       if (fscanf(stdin, "%c", &lf) < 0) {
+           /* toss away; don't care */
+       }
        if (in == 'y') {
            fprintf(STDOUT, "type control-c\n");
            while (1) {
@@ -1975,21 +1897,6 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
        }
        /* or drop through */
     }
-#ifdef notdef
-    /* This is tricky.  File server is very stupid, and if you mark the volume
-     * as VTOutOfService, it may mark the *good* instance (if you're moving
-     * between partitions on the same machine) as out of service.  Since
-     * we're cleaning this code up in DEcorum, we're just going to kludge around
-     * it for now by removing this call. */
-    /* already out of service, just zap it now */
-    code =
-       AFSVolSetFlags(fromconn, fromtid, VTDeleteOnSalvage | VTOutOfService);
-    if (code) {
-       fprintf(STDERR,
-               "Failed to set the flags to make the old source volume offline\n");
-       goto mfail;
-    }
-#endif
     if (atoserver != afromserver) {
        /* set forwarding pointer for moved volumes */
        VPRINT1("Setting forwarding pointer for volume %u ...", afromvol);
@@ -2030,13 +1937,12 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
     if (!(flags & RV_NOCLONE)) {
        code = DoVolDelete(fromconn, newVol, afrompart,
                           "cloned", 0, NULL, NULL);
-       if (code) {
-           if (code == VNOVOL) {
-               EPRINT1(code, "Failed to start transaction on %u\n", newVol);
-           }
+       if (code && code != VNOVOL) {
            error = code;
            goto mfail;
        }
+
+       code = 0;       /* clone missing? that's okay */
     }
 
     /* fall through */
@@ -2048,8 +1954,9 @@ UV_MoveVolume2(afs_uint32 afromvol, afs_uint32 afromserver, afs_int32 afrompart,
        fflush(STDOUT);
        if (fscanf(stdin, "%c", &in) < 1)
            in = 0;
-       if (fscanf(stdin, "%c", &lf) < 0)       /* toss away */
-           ; /* don't care */
+       if (fscanf(stdin, "%c", &lf) < 0) {     /* toss away */
+           /* don't care */
+       }
        if (in == 'y') {
            fprintf(STDOUT, "type control-c\n");
            while (1) {
@@ -2641,13 +2548,12 @@ cpincr:
     if (!(flags & RV_NOCLONE)) {
        code = DoVolDelete(fromconn, cloneVol, afrompart,
                           "cloned", 0, NULL, NULL);
-       if (code) {
-           if (code == VNOVOL) {
-               EPRINT1(code, "Failed to start transaction on %u\n", cloneVol);
-           }
+       if (code && code != VNOVOL) {
            error = code;
            goto mfail;
        }
+
+       code = 0;               /* clone missing? that's ok */
     }
 
     if (!(flags & RV_NOVLDB)) {
@@ -2771,11 +2677,8 @@ cpincr:
 
     /* common cleanup - delete local clone */
     if (cloneVol) {
-       code = DoVolDelete(fromconn, cloneVol, afrompart,
-                          "clone", 0, NULL, "Recovery:");
-       if (code == VNOVOL) {
-           EPRINT1(code, "Recovery: Failed to start transaction on %u\n", cloneVol);
-       }
+       DoVolDelete(fromconn, cloneVol, afrompart, "clone", 0, NULL,
+                   "Recovery:");
     }
 
   done:                        /* routine cleanup */
@@ -2925,8 +2828,6 @@ UV_BackupVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid)
        goto bfail;
     }
 
-    VDONE;
-
     /* Will update the vldb below */
 
   bfail:
@@ -3086,8 +2987,6 @@ UV_CloneVolume(afs_uint32 aserver, afs_int32 apart, afs_uint32 avolid,
        }
     }
 
-    VDONE;
-
   bfail:
     if (ttid) {
        code = AFSVolEndTrans(aconn, ttid, &rcode);
@@ -3431,11 +3330,11 @@ PutTrans(afs_int32 *vldbindex, struct replica *replicas,
 /**
  * Release a volume to read-only sites
  *
- * 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.
+ * Release volume <afromvol> on <afromserver> <afrompart> to all its RO
+ * sites (complete release), unless the previous release was incomplete
+ * or new sites were added without changes to the read-write volume, in
+ * which case we bring the remaining volumes up to date with the volumes
+ * that were previously 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,
@@ -3495,7 +3394,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     int new_sites = 0; /* number of ro sites markes as new */
 
     typedef enum {
-        CR_RECOVER    = 0x0000, /**< not complete: a recovery from a previous failed release */
+        CR_PARTIAL    = 0x0000, /**< just new sites added or recover from a previous failed release */
         CR_FORCED     = 0x0001, /**< complete: forced by caller */
         CR_LAST_OK    = 0x0002, /**< complete: no sites have been marked as new release */
         CR_ALL_NEW    = 0x0004, /**< complete: all sites have been marked as new release */
@@ -3503,7 +3402,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
         CR_RO_MISSING = 0x0010, /**< complete: ro clone is missing */
     } complete_release_t;
 
-    complete_release_t complete_release = CR_RECOVER;
+    complete_release_t complete_release = CR_PARTIAL;
 
     memset(remembertime, 0, sizeof(remembertime));
     memset(&results, 0, sizeof(results));
@@ -3552,7 +3451,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     if (entry.volumeId[ROVOL] == INVALID_BID) {
        /* need to get a new RO volume id */
        vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 1, &roVolId);
-       ONERROR(vcode, entry.name, "Cant allocate ID for RO volume of %s\n");
+       ONERROR(vcode, entry.name, "Can't allocate ID for RO volume of %s\n");
 
        entry.volumeId[ROVOL] = roVolId;
        MapNetworkToHost(&entry, &storeEntry);
@@ -3671,8 +3570,13 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                    "This is a recovery of previously failed release\n");
        } else {
            fprintf(STDOUT, "This is a complete release of volume %u", afromvol);
-           /* Give the reasons for a complete release, except if only CR_LAST_OK. */
-           if (complete_release != CR_LAST_OK) {
+           if (complete_release == CR_LAST_OK) {
+               if (justnewsites) {
+                   tried_justnewsites = 1;
+                   fprintf(STDOUT, "\nThere are new RO sites; we will try to "
+                           "only release to new sites");
+               }
+           } else {
                char *sep = " (";
                if (complete_release & CR_FORCED) {
                    fprintf(STDOUT, "%sforced", sep);
@@ -3696,11 +3600,6 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                fprintf(STDOUT, ")");
            }
            fprintf(STDOUT, "\n");
-           if (justnewsites) {
-               tried_justnewsites = 1;
-               fprintf(STDOUT, "There are new RO sites; we will try to "
-                       "only release to new sites\n");
-           }
        }
     }
 
@@ -3913,7 +3812,7 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
     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 */
-       complete_release = CR_RECOVER;
+       complete_release = CR_PARTIAL;
     } else if (tried_justnewsites) {
        VPRINT("RW vol has changed; releasing to all sites\n");
     }
@@ -4011,11 +3910,16 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
                /* Do a full dump when forced by the caller. */
                VPRINT("This will be a full dump: forced\n");
                thisdate = 0;
-           } else if (!complete_release) {
-               /* If this release is a recovery of a failed release, we can't be
-                * sure the creation date is good, so do a full dump.
-                */
-               VPRINT("This will be a full dump: previous release failed\n");
+           } else if (complete_release == CR_PARTIAL) {
+               if (justnewsites) {
+                   VPRINT("This will be a full dump: read-only volume needs be created for new site\n");
+               } else {
+                   /*
+                    * We cannot be sure the creation date is good since the previous
+                    * release failed, so do a full dump.
+                    */
+                   VPRINT("This will be a full dump: previous release failed\n");
+               }
                thisdate = 0;
            } else if (times[volcount].crtime == 0) {
                /* A full dump is needed for a new read-only volume. */
@@ -4214,7 +4118,8 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
        }
        code = DoVolDelete(fromconn, cloneVolId, afrompart, NULL, 0, NULL,
                           NULL);
-       ONERROR(code, cloneVolId, "Failed to delete volume %u.\n");
+       if (code && code != VNOVOL)
+           ONERROR(code, cloneVolId, "Failed to delete volume %u.\n");
        VDONE;
     }
 
@@ -4631,7 +4536,13 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
                goto refail;
            }
            reuseID = 0;
+       } else if (vcode) {
+           fprintf(STDERR, "Could not fetch the VLDB entry for the volume %s\n",
+                   tovolname);
+           error = vcode;
+           goto refail;
        } else if (flags & RV_RDONLY) {
+           /* -readonly restore is prohibited if an RW already exists */
            if (entry.flags & VLF_RWEXISTS) {
                fprintf(STDERR,
                        "Entry for ReadWrite volume %s already exists!\n",
@@ -4676,41 +4587,40 @@ UV_RestoreVolume2(afs_uint32 toserver, afs_int32 topart, afs_uint32 tovolid,
             noresolve ? afs_inet_ntoa_r(toserver, hoststr) :
            hostutil_GetNameByINet(toserver), partName);
     fflush(STDOUT);
-    code =
-       AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid, &pvolid,
-                          &totid);
-    if (code) {
-       if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
-           code = DoVolDelete(toconn, pvolid, topart, "the previous", 0,
-                              &tstatus, NULL);
-           if (code && code != VNOVOL) {
-               error = code;
-               goto refail;
-           }
 
-           code =
-               AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid,
-                                  &pvolid, &totid);
+    /*
+     * Obtain a transaction and get the status of the target volume. Create a new
+     * volume if the target volume does not already exist.
+     */
+    memset(&tstatus, 0, sizeof(tstatus));
+    if ((flags & RV_FULLRST) != 0) {
+       /* Full restore: Delete existing volume then create anew. */
+       code = DoVolDelete(toconn, pvolid, topart, "the previous", 0, &tstatus, NULL);
+       if (code && code != VNOVOL) {
+           error = code;
+           goto refail;
+       }
+       code = AFSVolCreateVolume(toconn, topart, tovolreal, volsertype, pparentid,
+                                 &pvolid, &totid);
+       EGOTO1(refail, code, "Could not create new volume %u\n", pvolid);
+    } else {
+       /* Incremental restore: Obtain a transaction on the existing volume. */
+       code = AFSVolTransCreate_retry(toconn, pvolid, topart, ITOffline, &totid);
+       if (code == 0) {
+           code = AFSVolGetStatus(toconn, totid, &tstatus);
+           EGOTO1(refail, code, "Could not get timestamp from volume %u\n", pvolid);
+       } else if (code == VNOVOL) {
+           code = AFSVolCreateVolume(toconn, topart, tovolreal, volsertype,
+                                     pparentid, &pvolid, &totid);
            EGOTO1(refail, code, "Could not create new volume %u\n", pvolid);
        } else {
-           code =
-               AFSVolTransCreate_retry(toconn, pvolid, topart, ITOffline, &totid);
-           EGOTO1(refail, code, "Failed to start transaction on %u\n",
-                  pvolid);
-
-           code = AFSVolGetStatus(toconn, totid, &tstatus);
-           EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
-                  pvolid);
-
+           EGOTO1(refail, code, "Failed to start transaction on %u\n", pvolid);
        }
-       oldCreateDate = tstatus.creationDate;
-       oldUpdateDate = tstatus.updateDate;
-       oldCloneId = tstatus.cloneID;
-       oldBackupId = tstatus.backupID;
-    } else {
-       oldCreateDate = 0;
-       oldUpdateDate = 0;
     }
+    oldCreateDate = tstatus.creationDate;
+    oldUpdateDate = tstatus.updateDate;
+    oldCloneId = tstatus.cloneID;
+    oldBackupId = tstatus.backupID;
 
     cookie.parent = pparentid;
     cookie.type = voltype;
@@ -5247,7 +5157,8 @@ UV_RemoveSite(afs_uint32 server, afs_int32 part, afs_uint32 volid)
                      LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
            return (vcode);
        }
-       VDONE;
+       fprintf(STDOUT, " done\n");
+       fflush(STDOUT);
     }
     return 0;
 }
@@ -5452,7 +5363,7 @@ UV_GenerateVolumeClones(afs_uint32 aserver, afs_int32 apart,
                VPRINT2("Clone for volume %s %u failed \n", curPtr->volName,
                        curPtr->volId);
            if (code) {
-               curPtr->volFlags &= ~CLONEVALID;        /*cant clone */
+               curPtr->volFlags &= ~CLONEVALID;        /* can't clone */
                curPos++;
                continue;
            }
@@ -5507,7 +5418,6 @@ UV_ListVolumes(afs_uint32 aserver, afs_int32 apart, int all,
     afs_int32 code = 0;
     volEntries volumeInfo;
 
-    code = 0;
     *size = 0;
     *resultPtr = (volintInfo *) 0;
     volumeInfo.volEntries_val = (volintInfo *) 0;      /*this hints the stub to allocate space */
@@ -7069,7 +6979,39 @@ UV_RenameVolume(struct nvldbentry *entry, char oldname[], char newname[])
        goto rvfail;
     }
     islocked = 1;
+
+    /*
+     * Match the flags we just set via SetLock,
+     * so we don't invalidate our compare below.
+     */
+    entry->flags &= ~VLOP_ALLOPERS;
+    entry->flags |= VLOP_ADDSITE;
+
+    /*
+     * Now get the entry again (under lock) and
+     * verify the volume hasn't otherwise changed.
+     */
+    vcode = VLDB_GetEntryByID(entry->volumeId[RWVOL], RWVOL, &storeEntry);
+    if (vcode) {
+       fprintf(STDERR,
+               "Could not obtain the VLDB entry for the volume %u\n",
+               entry->volumeId[RWVOL]);
+       error = vcode;
+       goto rvfail;
+    }
+    /* Convert to net order to match entry, which was passed in net order. */
+    MapHostToNetwork(&storeEntry);
+    if (memcmp(entry, &storeEntry, sizeof(*entry)) != 0) {
+       fprintf(STDERR,
+               "VLDB entry for volume %u has changed; "
+               "please reissue the command.\n",
+               entry->volumeId[RWVOL]);
+       error = VL_BADENTRY;    /* an arbitrary choice, but closest to the truth */
+       goto rvfail;
+    }
+
     strncpy(entry->name, newname, VOLSER_OLDMAXVOLNAME);
+    /* Note that we are reusing storeEntry. */
     MapNetworkToHost(entry, &storeEntry);
     vcode = VLDB_ReplaceEntry(entry->volumeId[RWVOL], RWVOL, &storeEntry, 0);
     if (vcode) {