Allow specifying vos create/addsite volume IDs
authorAndrew Deason <adeason@sinenomine.net>
Mon, 6 Jul 2009 15:29:20 +0000 (10:29 -0500)
committerDerrick Brashear <shadow@dementia.org>
Fri, 24 Jul 2009 19:29:30 +0000 (12:29 -0700)
This adds the -id option to 'vos create', and the -roid option to 'vos
create' and 'vos addsite'. This allows the user to manually specify the
volume IDs that a new RW or RO volume will get (or explicitly specify
that an RO volume ID should be unset), instead of always relying on the
volume IDs retrieved from the vlserver.

Reviewed-on: http://gerrit.openafs.org/157
Tested-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

doc/man-pages/pod1/vos_addsite.pod
doc/man-pages/pod1/vos_create.pod
src/volser/volser_prototypes.h
src/volser/vos.c
src/volser/vsprocs.c

index bc16145..ac6a9cf 100644 (file)
@@ -9,14 +9,17 @@ vos_addsite - Adds a read-only site definition to a volume's VLDB entry
 
 B<vos addsite> S<<< B<-server> <I<machine name for new site>> >>>
     S<<< B<-partition> <I<partition name for new site>> >>>
-    S<<< B<-id> <I<volume name or ID>> >>> [B<-valid>]
-    S<<< [B<-cell> <I<cell name>>] >>> [B<-noauth>] [B<-localauth>]
+    S<<< B<-id> <I<volume name or ID>> >>>
+    S<<< [B<-roid> <I<readonly volume name or ID>>] >>>
+    [B<-valid>] S<<< [B<-cell> <I<cell name>>] >>>
+    [B<-noauth>] [B<-localauth>]
     [B<-verbose>] [B<-help>]
 
 B<vos ad> S<<< B<-s> <I<machine name for new site>> >>>
     S<<< B<-p> <I<partition name for new site>> >>>
-    S<<< B<-i> <I<volume name or ID>> >>> [B<-va>]
-    S<<< [B<-c> <I<cell name>>] >>> [B<-n>] [B<-l>] [B<-ve>] [B<-h>]
+    S<<< B<-i> <I<volume name or ID>> >>>
+    S<<< [B<-r> <I<readonly volume name or ID>>] >>>
+    [B<-va>] [B<-c> <I<cell name>>] >>> [B<-n>] [B<-l>] [B<-v>] [B<-h>]
 
 =for html
 </div>
@@ -69,6 +72,21 @@ L<vos(1)>.
 Specifies either the complete name or volume ID number of the read/write
 source volume.
 
+=item B<-roid> <I<readonly volume name or ID>>
+
+Specifies either the complete name or volume ID number of the readonly
+volume. This will only be honored if the source read/write volume does not
+already have a readonly volume ID associated with it. If the source
+read/write volume already has a readonly volume ID, the specified ID will
+be ignored, and a warning will be printed.
+
+If this is not specified and the source read/write volume does not already
+have a readonly volume ID, a volume ID for the readonly volume will be
+allocated for it when the B<vos release> command is run.
+
+The automatically allocated readonly volume IDs should be fine for almost
+all cases, so you should almost never need to specify this option.
+
 =item B<-valid>
 
 Marks the site as up-to-date in the VLDB. You should only do this if the
index 29ea06a..e7b6b3d 100644 (file)
@@ -9,11 +9,13 @@ vos_create - Creates a read/write volume and associated VLDB entry
 
 B<vos create> S<<< B<-server> <I<machine name>> >>> S<<< B<-partition> <I<partition name>> >>>
     S<<< B<-name> <I<volume name>> >>> S<<< [B<-maxquota> <I<initial quota (KB)>>] >>>
+    S<<< [B<-id> <I<volume ID>>] >>> S<<< [B<-roid> <I<readonly volume ID>>] >>>
     S<<< [B<-cell> <I<cell name>>] >>> [B<-noauth>] [B<-localauth>] [B<-verbose>]
     [B<-help>]
 
 B<vos cr> S<<< B<-s> <I<machine name>> >>> S<<< B<-p> <I<partition name>> >>>
     S<<< B<-na> <I<volume name>> >>> S<<< [B<-m> <I<initial quota (KB)>>] >>>
+    S<<< [B<-i> <I<volume ID>>] >>> S<<< [B<-r> <I<readonly volume ID>>] >>>
     S<<< [B<-c> <I<cell name>>] >>> [B<-no>] [B<-l>] [B<-v>] [B<-h>]
 
 =for html
@@ -100,6 +102,32 @@ of kilobyte blocks (a value of C<1024> is one megabyte). The value C<0>
 houses the volume places an absolute limit on its size.  If this argument
 is omitted, the default value is C<5000>.
 
+=item B<-id> <I<volume ID>>
+
+Specifies the volume ID for the read/write volume. If this options is not
+specified, or the given volume ID is 0, a volume ID will be allocated for
+the volume automatically. The volume IDs allocated should be fine for
+almost all cases, so you should almost never need to specify this option.
+
+=item B<-roid> <I<readonly volume ID>>
+
+Specifies the volume ID for the readonly volume corresponding to the
+read/write volume that is being created. The readonly volume will not be
+created; this merely specifies what volume ID the readonly volume will use
+when it is created. If a volume ID of 0 is specified here, no readonly
+volume ID will be assigned to the created volume immediately. A readonly
+volume ID can still be assigned later when B<vos addsite> is run; if a
+volume does not have a readonly volume ID associated with it by the time
+B<vos release> is run, a volume ID will be allocated for it.
+
+If this option is not specified, the default readonly volume ID is one
+number higher than the read-write volume ID, whether or not that ID was
+manually specified.
+
+As with the B<-id> option, the default allocated volume IDs should be
+sufficient for almost all cases, so you should almost never need to
+specify this option.
+
 =item B<-cell> <I<cell name>>
 
 Names the cell in which to run the command. Do not combine this argument
index c7bd0a5..88f707d 100644 (file)
@@ -53,6 +53,11 @@ extern int UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
                            afs_int32 aquota, afs_int32 aspare1,
                            afs_int32 aspare2, afs_int32 aspare3,
                            afs_int32 aspare4, afs_uint32 * anewid);
+extern int UV_CreateVolume3(afs_int32 aserver, afs_int32 apart, char *aname,
+                           afs_int32 aquota, afs_int32 aspare1,
+                           afs_int32 aspare2, afs_int32 aspare3,
+                           afs_int32 aspare4, afs_uint32 * anewid,
+                           afs_uint32 * aroid, afs_uint32 * abkid);
 extern int UV_AddVLDBEntry(afs_int32 aserver, afs_int32 apart, char *aname,
                           afs_uint32 aid);
 extern int UV_DeleteVolume(afs_int32 aserver, afs_int32 apart,
@@ -86,6 +91,8 @@ extern int UV_RestoreVolume2(afs_int32 toserver, afs_int32 topart,
 extern int UV_LockRelease(afs_uint32 volid);
 extern int UV_AddSite(afs_int32 server, afs_int32 part, afs_uint32 volid,
                      afs_int32 valid);
+extern int UV_AddSite2(afs_int32 server, afs_int32 part, afs_uint32 volid,
+                      afs_uint32 rovolid, afs_int32 valid);
 extern int UV_RemoveSite(afs_int32 server, afs_int32 part, afs_uint32 volid);
 extern int UV_ChangeLocation(afs_int32 server, afs_int32 part,
                             afs_uint32 volid);
index 9c5b7a6..78caa8c 100644 (file)
@@ -1871,12 +1871,15 @@ CreateVolume(register struct cmd_syndesc *as, void *arock)
 {
     afs_int32 pnum;
     char part[10];
-    afs_uint32 volid;
+    afs_uint32 volid = 0, rovolid = 0, bkvolid = 0;
+    afs_uint32 *arovolid;
     afs_int32 code;
     struct nvldbentry entry;
     afs_int32 vcode;
     afs_int32 quota;
 
+    arovolid = &rovolid;
+
     quota = 5000;
     tserver = GetServer(as->parms[0].items->data);
     if (!tserver) {
@@ -1932,9 +1935,41 @@ CreateVolume(register struct cmd_syndesc *as, void *arock)
        }
     }
 
+    if (as->parms[4].items) {
+       if (!IsNumeric(as->parms[4].items->data)) {
+           fprintf(STDERR, "vos: Given volume ID %s should be numeric.\n",
+                   as->parms[4].items->data);
+           return EINVAL;
+       }
+
+       code = util_GetInt32(as->parms[4].items->data, &volid);
+       if (code) {
+           fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
+           return code;
+       }
+    }
+
+    if (as->parms[5].items) {
+       if (!IsNumeric(as->parms[5].items->data)) {
+           fprintf(STDERR, "vos: Given RO volume ID %s should be numeric.\n",
+                   as->parms[5].items->data);
+           return EINVAL;
+       }
+
+       code = util_GetInt32(as->parms[5].items->data, &rovolid);
+       if (code) {
+           fprintf(STDERR, "vos: bad integer specified for volume ID.\n");
+           return code;
+       }
+
+       if (rovolid == 0) {
+           arovolid = NULL;
+       }
+    }
+
     code =
-       UV_CreateVolume2(tserver, pnum, as->parms[2].items->data, quota, 0,
-                        0, 0, 0, &volid);
+       UV_CreateVolume3(tserver, pnum, as->parms[2].items->data, quota, 0,
+                        0, 0, 0, &volid, arovolid, &bkvolid);
     if (code) {
        PrintDiagnostics("create", code);
        return code;
@@ -3221,7 +3256,7 @@ static int
 AddSite(register struct cmd_syndesc *as, void *arock)
 {
     afs_uint32 avolid;
-    afs_int32 aserver, apart, code, err, valid = 0;
+    afs_int32 aserver, apart, code, err, arovolid, valid = 0;
     char apartName[10], avolname[VOLSER_MAXVOLNAME + 1];
 
     vsu_ExtractName(avolname, as->parms[2].items->data);;
@@ -3234,6 +3269,16 @@ AddSite(register struct cmd_syndesc *as, void *arock)
                    as->parms[2].items->data);
        exit(1);
     }
+    arovolid = 0;
+    if (as->parms[3].items) {
+       vsu_ExtractName(avolname, as->parms[3].items->data);
+       arovolid = vsu_GetVolumeID(avolname, cstruct, &err);
+       if (!arovolid) {
+           fprintf(STDERR, "vos: invalid ro volume id '%s'\n",
+                   as->parms[3].items->data);
+           exit(1);
+       }
+    }
     aserver = GetServer(as->parms[0].items->data);
     if (aserver == 0) {
        fprintf(STDERR, "vos: server '%s' not found in host table\n",
@@ -3255,10 +3300,10 @@ AddSite(register struct cmd_syndesc *as, void *arock)
                    as->parms[1].items->data);
        exit(1);
     }
-    if (as->parms[3].items) {
+    if (as->parms[4].items) {
        valid = 1;
     }
-    code = UV_AddSite(aserver, apart, avolid, valid);
+    code = UV_AddSite2(aserver, apart, avolid, arovolid, valid);
     if (code) {
        PrintDiagnostics("addsite", code);
        exit(1);
@@ -5709,6 +5754,8 @@ main(int argc, char **argv)
     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "volume name");
     cmd_AddParm(ts, "-maxquota", CMD_SINGLE, CMD_OPTIONAL,
                "initial quota (KB)");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "volume ID");
+    cmd_AddParm(ts, "-roid", CMD_SINGLE, CMD_OPTIONAL, "readonly volume ID");
 #ifdef notdef
     cmd_AddParm(ts, "-minquota", CMD_SINGLE, CMD_OPTIONAL, "");
 #endif
@@ -5854,6 +5901,7 @@ main(int argc, char **argv)
     cmd_AddParm(ts, "-partition", CMD_SINGLE, 0,
                "partition name for new site");
     cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
+    cmd_AddParm(ts, "-roid", CMD_SINGLE, CMD_OPTIONAL, "volume name or ID for RO");
     cmd_AddParm(ts, "-valid", CMD_FLAG, CMD_OPTIONAL, "publish as an up-to-date site in VLDB");
     COMMONPARMS;
 
index f2de346..6008658 100644 (file)
@@ -673,30 +673,67 @@ UV_PartitionInfo64(afs_int32 server, char *pname,
     return code;
 }
 
-/* old interface to create volume */
+/* old interface to create volumes */
 int
 UV_CreateVolume(afs_int32 aserver, afs_int32 apart, char *aname,
                afs_uint32 * anewid)
 {
     afs_int32 code;
+    *anewid = 0;
     code = UV_CreateVolume2(aserver, apart, aname, 5000, 0, 0, 0, 0, anewid);
     return code;
 }
 
-/* create a volume, given a server, partition number, volume name --> sends
-* back new vol id in <anewid>*/
+/* less old interface to create volumes */
 int
 UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
                 afs_int32 aquota, afs_int32 aspare1, afs_int32 aspare2,
                 afs_int32 aspare3, afs_int32 aspare4, afs_uint32 * anewid)
 {
+    afs_uint32 roid = 0, bkid = 0;
+    return UV_CreateVolume3(aserver, apart, aname, aquota, aspare1, aspare2,
+       aspare3, aspare4, anewid, &roid, &bkid);
+}
+
+/**
+ * Create a volume on the given server and partition
+ *
+ * @param aserver  server to create volume on
+ * @param spart  partition to create volume on
+ * @param aname  name of new volume
+ * @param aquota  quota for new volume
+ * @param anewid  contains the desired volume id for the new volume. If
+ *                *anewid == 0, a new id will be chosen, and will be placed
+ *                in *anewid when UV_CreateVolume3 returns.
+ * @param aroid  contains the desired RO volume id. If NULL, the RO id entry
+ *               will be unset. If *aroid == 0, an id will be chosen, and
+ *               will be placed in *anewid when UV_CreateVolume3 returns.
+ * @param abkid  same as aroid, except for the BK volume id instead of the
+ *               RO volume id.
+ * @return 0 on success, error code otherwise.
+ */
+int
+UV_CreateVolume3(afs_int32 aserver, afs_int32 apart, char *aname,
+                afs_int32 aquota, afs_int32 aspare1, afs_int32 aspare2,
+                afs_int32 aspare3, afs_int32 aspare4, afs_uint32 * anewid,
+                afs_uint32 * aroid, afs_uint32 * abkid)
+{
     register struct rx_connection *aconn;
     afs_int32 tid;
     register afs_int32 code;
     afs_int32 error;
     afs_int32 rcode, vcode;
+    afs_int32 lastid;
     struct nvldbentry entry, storeEntry;       /*the new vldb entry */
     struct volintInfo tstatus;
+    afs_int32 alloc_roid = 0, alloc_bkid = 0;
+
+    if (aroid && *aroid == 0) {
+       alloc_roid = 1;
+    }
+    if (abkid && *abkid == 0) {
+       alloc_bkid = 1;
+    }
 
     tid = 0;
     aconn = (struct rx_connection *)0;
@@ -706,11 +743,45 @@ UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
     tstatus.maxquota = aquota;
 
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
-    /* next the next 3 available ids from the VLDB */
-    vcode = ubik_VL_GetNewVolumeId(cstruct, 0, 3, anewid);
-    EGOTO1(cfail, vcode, "Could not get an Id for volume %s\n", aname);
+
+    if (*anewid) {
+        vcode = VLDB_GetEntryByID(*anewid, -1, &entry);
+       if (!vcode) {
+           fprintf(STDERR, "Volume ID %d already exists\n", *anewid);
+           return VVOLEXISTS;
+       }
+       VPRINT1("Using volume ID %d.\n", *anewid);
+    } else {
+       /* get the next 3 available ids from the VLDB */
+       int alloc_ids = 3;
+
+       /* if the RO or BK id are specified, we don't need to allocate as
+        * many IDs */
+       if (!alloc_roid) {
+           --alloc_ids;
+       }
+       if (!alloc_bkid) {
+           --alloc_ids;
+       }
+       vcode = ubik_VL_GetNewVolumeId(cstruct, 0, alloc_ids, anewid);
+       EGOTO1(cfail, vcode, "Could not get an Id for volume %s\n", aname);
+    }
+
+    /* rw,ro, bk id are related in the default case */
+    lastid = *anewid;
+    if (aroid && *aroid) {
+       VPRINT1("Using RO volume ID %d.\n", aroid);
+    } else if (aroid) {
+       *aroid = ++lastid;
+    }
+    if (abkid && *abkid) {
+       VPRINT1("Using backup volume ID %d.\n", abkid);
+    } else if (abkid) {
+       *abkid = ++lastid;
+    }
+
     code =
-      AFSVolCreateVolume_retry(aconn, apart, aname, volser_RW, 0, anewid, &tid);
+       AFSVolCreateVolume_retry(aconn, apart, aname, volser_RW, 0, anewid, &tid);
     EGOTO2(cfail, code, "Failed to create the volume %s %u \n", aname,
           *anewid);
 
@@ -719,7 +790,7 @@ UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
        EPRINT(code, "Could not change quota, continuing...\n");
 
     code = AFSVolSetFlags(aconn, tid, 0);      /* bring it online (mark it InService */
-    EGOTO2(cfail, vcode, "Could not bring the volume %s %u online \n", aname,
+    EGOTO2(cfail, code, "Could not bring the volume %s %u online \n", aname,
           *anewid);
 
     VPRINT2("Volume %s %u created and brought online\n", aname, *anewid);
@@ -734,8 +805,8 @@ UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
     entry.flags = RW_EXISTS;   /* this records that rw volume exists */
     entry.serverFlags[0] = ITSRWVOL;   /*this rep site has rw  vol */
     entry.volumeId[RWVOL] = *anewid;
-    entry.volumeId[ROVOL] = *anewid + 1;       /* rw,ro, bk id are related in the default case */
-    entry.volumeId[BACKVOL] = *anewid + 2;
+    entry.volumeId[ROVOL] = aroid ? *aroid : 0;
+    entry.volumeId[BACKVOL] = abkid ? *abkid : 0;
     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 */
@@ -4669,13 +4740,22 @@ UV_LockRelease(afs_uint32 volid)
 
 }
 
+/* old interface to add rosites */
+int
+UV_AddSite(afs_int32 server, afs_int32 part, afs_uint32 volid,
+          afs_int32 valid)
+{
+    return UV_AddSite2(server, part, volid, 0, valid);
+}
+
 /*adds <server> and <part> as a readonly replication site for <volid>
 *in vldb */
 int
-UV_AddSite(afs_int32 server, afs_int32 part, afs_uint32 volid, afs_int32 valid)
+UV_AddSite2(afs_int32 server, afs_int32 part, afs_uint32 volid,
+           afs_uint32 rovolid, afs_int32 valid)
 {
     int j, nro = 0, islocked = 0;
-    struct nvldbentry entry, storeEntry;
+    struct nvldbentry entry, storeEntry, entry2;
     afs_int32 vcode, error = 0;
     char apartName[10];
 
@@ -4742,6 +4822,25 @@ UV_AddSite(afs_int32 server, afs_int32 part, afs_uint32 volid, afs_int32 valid)
        goto asfail;
     }
 
+    /* if rovolid == 0, we leave the RO volume id alone. If the volume doesn't
+     * have an RO volid at this point (i.e. entry.volumeId[ROVOL] ==
+     * INVALID_BID) and we leave it alone, it gets an RO volid at release-time.
+     */
+    if (rovolid) {
+       if (entry.volumeId[ROVOL] == INVALID_BID) {
+           vcode = VLDB_GetEntryByID(rovolid, -1, &entry2);
+           if (!vcode) {
+               fprintf(STDERR, "Volume ID %d already exists\n", rovolid);
+               return VVOLEXISTS;
+           }
+           VPRINT1("Using RO volume id %d.\n", rovolid);
+           entry.volumeId[ROVOL] = rovolid;
+       } else {
+           fprintf(STDERR, "Ignoring given RO id %d, since volume already has RO id %d\n",
+               rovolid, entry.volumeId[ROVOL]);
+       }
+    }
+
     VPRINT("Adding a new site ...");
     entry.serverNumber[entry.nServers] = server;
     entry.serverPartition[entry.nServers] = part;