vos: take RO volume offline during convertROtoRW 66/14066/2
authorMarcio Barbosa <mbarbosa@sinenomine.net>
Thu, 13 Feb 2020 03:39:00 +0000 (00:39 -0300)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 20 Mar 2020 04:14:46 +0000 (00:14 -0400)
The vos convertROtoRW command converts a RO volume into a RW volume.
Unfortunately, the RO volume in question is not set as "out of service"
during this process. As a result, accesses to the volume being converted
can leave volume objects in an inconsistent state.

Consider the following scenario:

1. Create a volume on host_b and add replicas on host_a and host_b.

$ vos create host_b a vol_1
$ vos addsite host_b a vol_1
$ vos addiste host_a a vol_1

2. Mount the volume:

$ fs mkmount /afs/.mycell/vol_1 vol_1
$ vos release vol_1
$ vos release root.cell

3. Shutdown dafs on host_b:

$ bos shutdown host_b dafs

4. Remove RO reference to host_b from the vldb:

$ vos remsite host_b a vol_1

5. Attach the RO copy by touching it:

$ fs flushall
$ ls /afs/mycell/vol_1

6. Convert RO copy to RW:

$ vos convertROtoRW host_a a vol_1

Notice that FSYNC_com_VolDone fails silently (FSYNC_BAD_STATE), leaving
the volume object for the RO copy set as VOL_STATE_ATTACHED (on success,
this volume should be set as VOL_STATE_DELETED).

7. Add replica on host_a:

$ vos addsite host_a a vol_1

8. Wait until the "inUse" flag of the RO entry is cleared (or force this
to happen by attaching multiple volumes).

9. Release the volume:

$ vos release vol_1

Failed to start transaction on volume 536870922
Volume not attached, does not exist, or not on line
Error in vos release command.
Volume not attached, does not exist, or not on line

To fix this problem, take the RO volume offline during the vos
convertROtoRW operation.

Change-Id: I1e417a026ed819fab4435e8992311fcd4f339341
Reviewed-on: https://gerrit.openafs.org/14066
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/volser/vsprocs.c

index 53e8190..cddacac 100644 (file)
@@ -1342,6 +1342,14 @@ UV_ConvertRO(afs_uint32 server, afs_uint32 partition, afs_uint32 volid,
        }
     }
 
+    /* volume must be inaccessible during this process */
+    code = UV_SetVolume(server, partition, volid, ITOffline, VTOutOfService, 0);
+    if (code != 0) {
+       fprintf(STDERR, "Taking RO volume %u offline failed with code %d.\n",
+               volid, code);
+       goto error_exit;
+    }
+
     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
     if (code) {
@@ -1351,6 +1359,18 @@ UV_ConvertRO(afs_uint32 server, afs_uint32 partition, afs_uint32 volid,
        PrintError("convertROtoRW ", code);
        goto error_exit;
     }
+
+    /*
+     * Since the inService flag is copied from the RO volume, the new RW copy is
+     * offline. Change the status of this RW volume to online.
+     */
+    code = UV_SetVolume(server, partition, entry->volumeId[RWVOL], ITOffline,
+                       0 /* online */, 0);
+    if (code != 0) {
+       fprintf(STDERR, "Warning: Attempt to set RW volume %u as online failed "
+                       "with code %d.\n", entry->volumeId[RWVOL], code);
+    }
+
     /* 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) {