[PATCH v2 14/23] NFSv4/flexfiles: Honor ndc_immediate on CB_NOTIFY_DEVICEID CHANGE
Benjamin Coddington <[email protected]>
| Newsgroups | org.kernel.vger.linux-nfs |
|---|---|
| Message-ID | <da98de51fe276a11faef6b42d469ed73dd4ff53f.1787327939.git.bcodding@hammerspace.com> |
When a CHANGE notification carries ndc_immediate, RFC 8881 Section 20.12 says the change is enforced immediately and the client might not be able to complete pending I/O. In addition to un-pinning the stripe's device node, mark the old node unavailable. Marking does not recall the references already handed out. A write whose DS connection is already up keeps using the old node until that I/O errors: nfs4_ff_layout_prepare_ds() returns early on a live ds_clp, and the unavailable flag is only consulted when a connection is being established. What the mark does change is that a read skips the node while another mirror is usable, and that an IOMODE_RW segment still pinning it stops counting as fully available -- so I/O the server rejects falls back to the MDS rather than being retried against a mapping the server has already withdrawn. The walk can also exchange out a node that already carries the new mapping: a re-resolve that completed between the unhash and the walk reaching the stripe, raced by this walk or by the walk of a later CHANGE for the same deviceid. Ripping such a node out is harmless (it is still hashed, so the next I/O re-pins it from the cache), but it must not be marked unavailable. Stale vintages are distinguishable by hashed-ness: every superseded node was unhashed before its walk began and is never re-inserted, while a fresh node is inserted before it is installed. Only mark nodes that are no longer hashed. That test is hlist_unhashed_lockless(): the hook runs under the layout inode's i_lock and rcu_read_lock(), but not under nfs4_deviceid_lock, which is what serializes the writers of node.pprev -- and __hlist_del() stores a neighbour's pprev with WRITE_ONCE(), so removing any other entry in the same bucket can write the field this test reads. Without ndc_immediate, pending I/O drains on the old mapping and only new I/O re-resolves, as before. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <[email protected]> --- fs/nfs/flexfilelayout/flexfilelayout.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 46ca58e8e96b..ebb19a919f9d 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -2541,6 +2541,14 @@ static void ff_layout_reresolve_deviceid(struct pnfs_layout_hdr *lo, kfree(put); continue; } + /* Only mark stale vintages: a node still hashed was + * fetched after the unhash and carries the new + * mapping. Lockless -- nfs4_deviceid_lock, which + * serialises pprev, is not held here. + */ + if (immediate && + hlist_unhashed_lockless(&old->id_node.node)) + nfs4_mark_deviceid_unavailable(&old->id_node); put->dev = &old->id_node; list_add(&put->node, head); } -- 2.53.0