mirror of
https://git.openafs.org/openafs.git
synced 2025-01-18 15:00:12 +00:00
volser: Use GetLockedEntry in UV_ReleaseVolume
Change UV_ReleaseVolume() to use the new GetLockedEntry() function. Add logic to GetLockedEntry() to support the special semantics of VL_SetLock for VLOP_RELEASE, to preserve the current behavior of UV_ReleaseVolume() with the VL_RERELEASE error code. The special semantics of the VL_RERELEASE error code with VLOP_RELEASE are a bit odd: this situation can currently only happen with our vlserver if the vlentry has the VLOP_RELEASE flag set but no lock timestamp. The only way that situation can occur with our current 'vos' is during a small window after a partially failed 'vos release'. Around where UV_ReleaseVolume() prints the message "The volume %lu could not be released to the following %d sites", we call VLDB_ReplaceEntry() with LOCKREL_TIMESTAMP, clearing just the lock timestamp but not the lock flags. We then jump to the 'rfail' label where we ubik_VL_ReleaseLock() with all LOCKREL_* flags are set, clearing the lock flags. So, the only time in this codepath where the lock timestamp is cleared but the VLOP_RELEASE flag is set is after the mentioned VLDB_ReplaceEntry() call but before the ubik_VL_ReleaseLock() call. If that last ubik_VL_ReleaseLock() fails, or if vos dies before reaching it, then the vlentry is left in a state that causes the VL_RERELEASE error code in the future. This behavior has existed since at least OpenAFS 1.0. Currently, the handling of this special VL_RERELEASE case is completely silent, so it's not clear that this is happening, if it does manage to happen. These special semantics are not really safe, since two vos processes could encounter a VL_RERELEASE volume at the same time, and go through the 'vos release' process in parallel thinking they have the vlentry locked, causing all kinds of problems. This behavior may be changed in the future, but for now just preserve the existing special handling of VL_RERELEASE. Add a warning message, though, to make this special situation not silent. No functional change (other than error messages) should be incurred by this commit. [adeason@sinenomine.net: Add VL_RERELEASE warning message and additional related comments.] Change-Id: I9da50677233f63235de730b5d234a9b575e196fd Reviewed-on: https://gerrit.openafs.org/14352 Tested-by: BuildBot <buildbot@rampaginggeek.com> Reviewed-by: Michael Meffie <mmeffie@sinenomine.net> Reviewed-by: Cheyenne Wills <cwills@sinenomine.net> Reviewed-by: Mark Vitale <mvitale@sinenomine.net> Reviewed-by: Andrew Deason <adeason@sinenomine.net>
This commit is contained in:
parent
e18e94887a
commit
ab660e2537
@ -426,6 +426,10 @@ void init_volintInfo(struct volintInfo *vinfo) {
|
||||
* @param[out] vlentry on success, contains the volume entry with server
|
||||
* addresses in net byte order
|
||||
*
|
||||
* @note If the given 'vlop' is VLOP_RELEASE and the vlserver responds to our
|
||||
* VL_SetLock request with a VL_RERELEASE error, we ignore the error and
|
||||
* pretend the volume was locked, to preserve historical behavior.
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
static afs_int32
|
||||
@ -435,6 +439,32 @@ GetLockedEntry(afs_uint32 volid, afs_int32 voltype, int vlop,
|
||||
afs_int32 code;
|
||||
|
||||
code = ubik_VL_SetLock(cstruct, 0, volid, voltype, vlop);
|
||||
if (vlop == VLOP_RELEASE && code == VL_RERELEASE) {
|
||||
/*
|
||||
* VL_RERELEASE indicates that the vlentry VLOP_RELEASE lock flag is
|
||||
* set, but the lock timestamp is not. Before openafs
|
||||
* 1.0, maybe this was more common for failed/interrupted 'vos release'
|
||||
* runs, but is currently very rare in openafs: 'vos release' would
|
||||
* have to fail to VL_ReleaseLock the vlentry, which we currently
|
||||
* always try to do.
|
||||
*
|
||||
* Historically, we ignore VL_RERELEASE when doing a 'vos release', so
|
||||
* we can fix the volume by re-releasing it without the user needing to
|
||||
* manually unlock the partially locked vlentry.
|
||||
*
|
||||
* So, pretend that the lock succeeded; the volume is still (partially)
|
||||
* locked, after all. This behavior isn't ideal, since another 'vos
|
||||
* release' running in parallel could hit this same code path and also
|
||||
* pretend that they locked the volume. But this is the historical
|
||||
* behavior of vos, so preserve this behavior for now.
|
||||
*/
|
||||
fprintf(STDERR, "Warning: VLDB entry for volume %lu is still partially locked from a\n"
|
||||
"previous failed/interrupted release (VL_RERELEASE). Proceeding anyway so we can\n"
|
||||
"re-release the volume to fix it; please do not run another release for this\n"
|
||||
"volume in parallel. This behavior may change in the future.\n",
|
||||
(unsigned long)volid);
|
||||
code = 0;
|
||||
}
|
||||
if (code != 0) {
|
||||
goto error;
|
||||
}
|
||||
@ -3334,17 +3364,10 @@ UV_ReleaseVolume(afs_uint32 afromvol, afs_uint32 afromserver,
|
||||
memset(&results, 0, sizeof(results));
|
||||
memset(origflags, 0, sizeof(origflags));
|
||||
|
||||
vcode = ubik_VL_SetLock(cstruct, 0, afromvol, RWVOL, VLOP_RELEASE);
|
||||
if (vcode != VL_RERELEASE)
|
||||
ONERROR(vcode, afromvol,
|
||||
"Could not lock the VLDB entry for the volume %u.\n");
|
||||
islocked = 1;
|
||||
|
||||
/* Get the vldb entry in readable format */
|
||||
vcode = VLDB_GetEntryByID(afromvol, RWVOL, &entry);
|
||||
vcode = GetLockedEntry(afromvol, RWVOL, VLOP_RELEASE, &entry);
|
||||
ONERROR(vcode, afromvol,
|
||||
"Could not fetch the entry for the volume %u from the VLDB.\n");
|
||||
MapHostToNetwork(&entry);
|
||||
"Could not fetch locked VLDB entry for volume %u.\n");
|
||||
islocked = 1;
|
||||
|
||||
if (verbose)
|
||||
EnumerateEntry(&entry);
|
||||
|
Loading…
Reference in New Issue
Block a user