diff options
| author | Benjamin Coddington <ben.coddington@hammerspace.com> | 2026-09-15 08:22:18 -0400 |
|---|---|---|
| committer | Anna Schumaker <anna.schumaker@hammerspace.com> | 2026-10-05 09:46:44 -0400 |
| commit | 1507df1d0bfd723e93eddcc800629acac1ec401c (patch) | |
| tree | e90e76eef75b31a855c7a6aaf12bd709acc58117 /include/linux | |
| parent | e1c7a4f94139cf2c49896653e3f1e6c4f25cff35 (diff) | |
pNFS: Discard a GETDEVICEINFO reply that raced a CHANGE notification
RFC 8881 Section 18.40.4: a GETDEVICEINFO reply in flight while the
server changes the device mapping may carry the pre-change mapping; if
it is inserted into the cache after the CHANGE notification unhashed
the stale entry, the client re-caches stale data.
Track a change epoch, bumped when a CHANGE notification is processed
before the stale entry is unhashed. nfs4_find_get_deviceid() snapshots
the epoch before issuing GETDEVICEINFO and, serialized against the
unhash by nfs4_deviceid_lock at insert time, discards the reply and
refetches if the epoch moved. A stale insert that instead precedes the
unhash is removed by the unhash itself, so the cache does not retain the
pre-change entry either way; a reference already handed to a caller in
that ordering is dropped by the re-resolve walk instead.
The refetch is bounded. The epoch is bumped once per CHANGE entry --
that is, at a rate the server chooses -- so an unbounded retry would let
a server drive GETDEVICEINFO traffic without limit, and each discarded
node can carry a DS client teardown and reconnect with it. After
NFS4_DEVICEID_FETCH_RETRIES attempts the reply is accepted. That is
safe because discarding is an optimisation rather than a correctness
requirement: it avoids caching a mapping already known to be superseded,
but before this patch the client cached whatever the reply carried, so
the bounded case is no worse than the previous behaviour and a mapping
that really is stale is corrected by the notification that follows.
The epoch lives on the nfs_client, so a CHANGE delivered on one server's
callback channel does not force an unrelated server's in-flight lookup
to discard its reply and refetch. Mounts that share an nfs_client do
share the counter; the deviceid cache is keyed per client ID, so that is
the granularity the race is defined at.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/nfs_fs_sb.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 3e6bae7e5221..482daf1fa4b0 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -74,6 +74,8 @@ struct nfs_client { u64 cl_clientid; /* constant */ nfs4_verifier cl_confirm; /* Clientid verifier */ unsigned long cl_state; + /* bumped on each CB_NOTIFY_DEVICEID CHANGE for this client */ + atomic_t cl_deviceid_change_epoch; spinlock_t cl_lock; |
