ubik: allow remote dbase relabel if up to date 13/12613/4
authorMarcio Barbosa <mbarbosa@sinenomine.net>
Wed, 21 Jun 2017 20:42:37 +0000 (17:42 -0300)
committerBenjamin Kaduk <kaduk@mit.edu>
Thu, 3 Aug 2017 00:09:07 +0000 (20:09 -0400)
When a site is elected the sync-site, its database is not immediately
relabeled. The database in question will be relabeled at the end of the
first write transaction (in udisk_commit). To do so, the dbase->version
is updated on the sync-site first (1) and then the versions of the
remote sites are updated through SDISK_SetVersion() (2).

In order to make sure that the remote site holds the same database as
the sync-site, the SDISK_SetVersion() function checks if the current
version held by the remote site (ubik_dbVersion) is equal to the
original version stored by the sync-site (oldversionp). If
ubik_dbVersion is not equal to oldversionp, SDISK_SetVersion() will
fail with USYNC.

However, ubik_dbVersion can be updated by the vote thread at any time.
That is, if the sync site calls VOTE_Beacon() on the remote site between
events (1) and (2), the remote site will set ubik_dbVersion to the new
version, while ubik_dbase->version is still set to the old version. As
a result, ubik_dbVersion will not be equal to oldversionp and
SDISK_SetVersion() will fail with USYNC. This failure may cause a loss
of quorum until another election is completed.

To fix this problem, let SDISK_SetVersion() relabel the database when
ubik_dbase->version is equal to oldversionp. In order to try to only
affect the scenario described above, also check if ubik_dbVersion is
equal to newversionp.

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

src/ubik/remote.c

index fe6ea2d..1c5a6af 100644 (file)
@@ -742,8 +742,14 @@ SDISK_SetVersion(struct rx_call *rxcall, struct ubik_tid *atid,
        goto done;
     }
 
-    /* Set the label if its version matches the sync-site's */
-    if (uvote_eq_dbVersion(*oldversionp)) {
+    /* Set the label if our version matches the sync-site's. Also set the label
+     * if our on-disk version matches the old version, and our view of the
+     * sync-site's version matches the new version. This suggests that
+     * ubik_dbVersion was updated while the sync-site was setting the new
+     * version, and it already told us via VOTE_Beacon. */
+    if (uvote_eq_dbVersion(*oldversionp)
+       || (uvote_eq_dbVersion(*newversionp)
+           && vcmp(ubik_dbase->version, *oldversionp) == 0)) {
        UBIK_VERSION_LOCK;
        code = (*ubik_dbase->setlabel) (ubik_dbase, 0, newversionp);
        if (!code) {