summaryrefslogtreecommitdiff
path: root/fs/nfs/flexfilelayout
AgeCommit message (Collapse)Author
10 daysNFSv4/flexfiles: fail I/O to the data server once a lock is lostBenjamin Coddington
When a client loses a byte-range lock, because its lease expired and it may not recover the lock (nfs.recover_lost_locks=0) or because reclaim failed, it marks the lock state NFS_LOCK_LOST and fails further I/O by that lock owner. Otherwise an application that believes it holds a lock over a range is never told that the lock is gone, and can overwrite data that another client has since written under its own lock on that range. The NFSv4 READ/WRITE and file layout I/O paths apply this in rpc_call_prepare, where nfs4_set_rw_stateid() returns -EIO for a lost lock. The flexfiles data server I/O path does not: the NFSv3 data server path never checked, and the check on the NFSv4 path was removed when the data server stateid began to be taken from the layout. Fail read and write RPCs to the data server in rpc_call_prepare when the lock is lost. The data server path has no use for the stateid that nfs4_set_rw_stateid() selects, and selecting it looks up a delegation or open stateid on every I/O. Instead add nfs4_lock_context_lost(), which only tests NFS_LOCK_LOST, and check it alongside the open state. Its lookup, __nfs4_lookup_lock_state(), is split out of __nfs4_find_lock_state() and takes no reference: a lock state is only unlinked from state->lock_states under state->state_lock, so one found while holding that lock cannot be freed before it is released. Use it in nfs4_copy_lock_stateid() as well, which only reads the lock state under that lock. That drops a reference get and put from stateid selection for all NFSv4 I/O without changing the stateid selected. Terminating the RPC in rpc_call_prepare is not enough on its own. The done callback reads the -EIO as a data server connection error, forgets the device ID, and resets the I/O to pNFS (or, for an NFSv4 data server, possibly to the MDS). After a reset to pNFS a new LAYOUTGET is granted and rpc_call_prepare fails the I/O again, without end. The existing NFS_CONTEXT_BAD check does not loop, since the open state is then invalid and pnfs_update_layout() fails the reset I/O, but it still forgets the device ID. So when an RPC that was never sent fails and the open context is bad, the open state is invalid, or the lock is lost, complete it with -EIO without error handling. An RPC that was sent and failed is handled as before, so a real data server error is still reported to the MDS. Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Fixes: bb21ce0ad227 ("flexfiles: use per-mirror specified stateid for IO") Cc: stable@vger.kernel.org Tested-by: Arun Potharaju <arun.potharaju@hammerspace.com> Assisted-by: LLM Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
10 dayspNFS/flexfiles: don't report an interrupted DS connect as a DS errorTigran Mkrtchyan
If nfs4_pnfs_ds_connect() is interrupted by a signal, nfs4_ff_layout_prepare_ds() records an NFS4ERR_NXIO error for the data server, sends a LAYOUTERROR to the MDS and may mark the layout for return. The data server is healthy in this case; only the calling task was killed. A bpftrace log of a killed task shows the connect failing with -ERESTARTSYS, followed by a LAYOUTERROR for a data server that completed the TCP handshake with the same client microseconds later (time in microseconds, abridged): python3 rpc_create (ret) 1xx.yy.50.179:24009 err=-512 kworker inet_sock_set_state :735 -> 1xx.yy.50.179:24009 CLOSE -> SYN_SENT swapper inet_sock_set_state :735 -> 1xx.yy.50.179:24009 SYN_SENT -> ESTABLISHED kworker inet_sock_set_state :735 -> 1xx.yy.50.179:24009 ESTABLISHED -> FIN_WAIT1 python3 nfs4_pnfs_ds_connect (ret) status=-512 python3 nfs4_ff_layout_prepare_ds (ret) err=-512 kworker rpc_request nfs v4 LAYOUTERROR async task=3/6752 kworker rpc_stats_latency LAYOUTERROR backlog=66us rtt=315us exec=421us Return the error to the caller without reporting a DS failure when the connect ended with -ERESTARTSYS or -EINTR. Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
10 dayspNFS/flexfiles: make pg_init retry loops killableTigran Mkrtchyan
When a task is killed while the pNFS client connects to a data server, nfs4_pnfs_ds_connect() fails with -ERESTARTSYS. If the layout has FF_FLAGS_NO_IO_THRU_MDS set, ff_layout_pg_init_read() cannot fall back to the MDS and retries after an uninterruptible ssleep. As the fatal signal stays pending, every new connect attempt is aborted the same way and the task loops forever without returning to user space: # grep -E 'SigPnd|ShdPnd' /proc/156021/status SigPnd: 0000000000000100 ShdPnd: 0000000000000100 # cat /proc/156021/stack msleep+0x2e/0x50 ff_layout_pg_init_read+0x267/0x310 [nfs_layout_flexfiles] __nfs_pageio_add_request+0x1c1/0x480 [nfs] nfs_pageio_add_request+0x21d/0x2c0 [nfs] nfs_read_add_folio+0x143/0x200 [nfs] nfs_readahead+0x204/0x290 [nfs] read_pages+0x62/0x230 page_cache_ra_unbounded+0x136/0x180 filemap_get_pages+0xf2/0x350 filemap_read+0xd5/0x320 nfs_file_read+0x6d/0xc0 [nfs] vfs_read+0x24f/0x3a0 __x64_sys_pread64+0x90/0xc0 do_syscall_64+0x5f/0xe0 Previous attempt propagates the error from nfs4_ff_layout_prepare_ds(), but only ff_layout_{read,write}_pagelist() look at it. The pg_init functions test IS_ERR() and retry on any error. Check for a fatal signal or an exiting task before sleeping in ff_layout_pg_init_read() and ff_layout_pg_init_write() and fail the I/O instead of retrying. Fixes: f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05pNFS/flexfiles: don't reset to MDS for v4 error when previous layout forbid itMike Snitzer
ff_layout_async_handle_error_v4() ends in -NFS4ERR_RESET_TO_MDS, which makes ff_layout_read_release() / ff_layout_write_release() call ff_layout_reset_read() or ff_layout_reset_write(hdr, false), and those call pnfs_read_done_resend_to_mds() / pnfs_write_done_resend_to_mds(). Those build a page I/O descriptor with force_mds set, so the flexfiles ->pg_init() never runs and no layout is consulted anywhere on the way: the READ or WRITE goes to the metadata server unconditionally. For a layout carrying FF_FLAGS_NO_IO_THRU_MDS that is exactly what the server forbade. The fall-through into reset: is already safe, because ff_layout_avoid_mds_available_ds() returns true for a segment with the flag and so answers -NFS4ERR_RESET_TO_PNFS first. What is not safe is the goto: the invalid-layout errors (NFS4ERR_PNFS_NO_LAYOUT, STALE, BADHANDLE, ISDIR, FHEXPIRED, WRONG_TYPE) call pnfs_destroy_layout() and jump straight to reset:, over that check. That is the case where the file had a perfectly good layout, something forced it to be given back, and the client answers by writing to the MDS behind the server's back. Test at reset: itself, so it covers the goto and any future one, and ask the inode (NFS_INO_NO_IO_THRU_MDS): the callers that jump here have just destroyed the layout hdr, so the hdr-level flag is no longer reachable, while the inode-level one is set for the life of the in-core inode. -NFS4ERR_RESET_TO_PNFS is the right answer rather than an error. It is what the fall-through already returns for the same flag, and the resends it drives - ff_layout_resend_pnfs_read() and ff_layout_reset_write(hdr, true) - re-enter the pgio path with force_mds clear, so a fresh LAYOUTGET is taken, which is precisely what a destroyed layout needs. A LAYOUTGET that fails fatally makes pnfs_update_layout() return an error, which ->pg_init() reports; a non-fatal refusal (NFS4ERR_LAYOUTUNAVAILABLE, NFS4ERR_TOOSMALL) returns no segment instead, and the client keeps retrying through pNFS rather than falling back. ff_layout_async_handle_error_v3() needs no such change: it returns only -NFS4ERR_RESET_TO_PNFS or -EAGAIN. Fixes: 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS") Assisted-by: Claude:claude-opus-5[1m] Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05pNFS/flexfiles: don't read through MDS when previous layout forbid itMike Snitzer
ff_layout_pg_init_read() falls back to the MDS whenever pnfs_update_layout() returns no segment and no error: a bulk CB_LAYOUTRECALL (FSID, DEVICEID or ALL), LAYOUTGETs blocked behind a layout being returned, or a LAYOUTGET refused with NFS4ERR_LAYOUTUNAVAILABLE or NFS4ERR_TOOSMALL, which set the per-iomode fail bit for PNFS_LAYOUTGET_RETRY_TIMEOUT. That is the read-side twin of the write path fixed by commit 1d62e659c0bf ("NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_write"), and it is reached in exactly the situation that matters most: the file had a valid layout, the layout had to go back, and the next one has not arrived yet. The write side could answer -EAGAIN because writeback owns the retry and redirties the page. A read has no such owner, so -EAGAIN here would surface as an I/O error to the application. Wait for a layout instead, on the same terms the function already uses when the layout lookup itself returns -EAGAIN: sleep a second and retry, bounded by pg_maxretrans, which ff_layout_pg_init_read() sets only for soft and softerr mounts. A hard mount therefore waits, which is what a hard mount is for, and matches what the FF_FLAGS_NO_IO_THRU_MDS check on the data server selection a few lines above already does. That includes waiting out NFS4ERR_LAYOUTUNAVAILABLE: a file that was given a layout with this flag must not be read off the MDS, whatever the server says afterwards. The test asks the inode (NFS_INO_NO_IO_THRU_MDS) rather than the layout hdr, because in this path there is no segment, and the hdr that carried the flag may already have been destroyed. Where a segment is in hand - the data server selection above, ff_layout_read_pagelist() - the existing per-segment ff_layout_no_fallback_to_mds() test stays, since it is the more precise question. Fixes: 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS") Assisted-by: Claude:claude-opus-5[1m] Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05pNFS/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS over the mdsthreshold hintMike Snitzer
A flexfiles layout may carry FF_FLAGS_NO_IO_THRU_MDS, which tells the client that this file's data must not be read or written through the metadata server. The RFC 5661 mdsthreshold hint pulls the other way. When a server returns one, pnfs_within_mdsthreshold() answers "use MDS I/O" for every I/O below the threshold, pnfs_update_layout() then hands back no segment, and ff_layout_pg_init_read() reads through the MDS - the very thing the layout forbids. A server that sets both is asking for two incompatible things; the layout flag is the stronger statement, and the one whose violation the client cannot recover from. Record the policy on the inode, where it outlives the layout hdr that carried it, and consult it before the hint: - ff_layout_alloc_lseg() sets NFS_INO_NO_IO_THRU_MDS beside the existing sticky hdr-level NFS4_FF_HDR_NO_IO_THRU_MDS bit. - pnfs_within_mdsthreshold() returns false at once for such an inode, so no I/O is diverted to the MDS on the strength of the hint. The bit is never cleared for the life of the in-core inode. Servers are assumed to be consistent in their no-fallback policy per file, which is the assumption ff_layout_hdr_no_fallback_to_mds() already makes; a server that was not would lose the effect of its mdsthreshold hint - a SHOULD - on an inode that is already in core, and nothing else. Fixes: 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS") Assisted-by: Claude:claude-opus-5[1m] Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05nfs/flexfile: fix doc of nfs4_ff_layout_prepare_ds functionTigran Mkrtchyan
fix mismatch between function doc description and actual code introduced in commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: only cancel I/O to a failed mirror instanceBenjamin Coddington
When an error causes the flexfiles driver to return a layout, ff_layout_cancel_io() kills every in-flight RPC for the layout segment, across all mirror instances. Cancelled requests that had already been transmitted to a healthy data server cannot be un-sent: they complete on the data server after the client has sent its LAYOUTRETURN, and the metadata server then observes writes to a file for which no write layout is outstanding. RFC 8881 Section 20.3.4 recommends that the client wait for the response from in-process or in-flight READ, WRITE, or COMMIT operations before returning the layout, and the machinery for that wait already exists: the LAYOUTRETURN is deferred until every request drops its layout segment reference, and requests that have not yet been transmitted exit at RPC prepare time once the segment has been invalidated. Cancellation is only needed to avoid waiting forever on a device that will never answer. Pass the failed instance's device ID when marking the layout for return, so that ff_layout_cancel_io() cancels only I/O directed at the device we have given up on. In-flight I/O to the remaining healthy instances drains normally -- typically within a round trip -- before the LAYOUTRETURN is sent. If a spared instance turns out to be unresponsive, its requests fail with their own device error, and the resulting layout return cancels its I/O in turn. Layout recalls with clora_changed set, bulk returns, and layout revocations continue to cancel I/O to every device, as do error paths where no single failed device can be identified. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05pNFS: allow layout drivers to cancel I/O to a single deviceBenjamin Coddington
The ->cancel_io() layout operation cancels all in-flight I/O for a layout segment that is being returned. When the return is triggered by the failure of a single mirror instance, cancelling I/O to the healthy mirrors is both unnecessary and harmful: requests that were already transmitted cannot be un-sent, and will complete on the data servers after the layout has been returned. Give ->cancel_io() a device ID argument identifying the failed device, and thread it through pnfs_error_mark_layout_for_return() and pnfs_mark_matching_lsegs_return(). The flexfiles implementation compares it against the raw device ID from the layout, so that it can identify the failed mirror instance even when its device ID node was never instantiated. A NULL device ID preserves the existing cancel-everything behavior, and all callers pass NULL for now, so this patch makes no change in behavior. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: report the intended opnum when DS connection setup failsBenjamin Coddington
When nfs4_ff_layout_prepare_ds() cannot establish a connection to a data server, it records a device error with opnum OP_ILLEGAL, since no operation ever made it to the wire. But servers can use the ff_ioerr4 opnum to distinguish failed read-class operations from write-class operations when deciding how to recover the affected mirror -- a mirror that may have missed writes needs to be brought back in sync, while one that merely failed to serve a read does not. OP_ILLEGAL gives the server nothing to act on. Every caller of nfs4_ff_layout_prepare_ds() knows which operation it was preparing to send, and the existing fail_return argument already divides the callers along the same boundary (false for READ, true for WRITE and COMMIT). Replace the boolean with the intended opnum, derive the layout return decision from it, and report it in the tracked device error instead of OP_ILLEGAL. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Add a dataserver_nconnect capBenjamin Coddington
Data-server clients inherit the MDS nconnect setting. A striping mount multiplies that by every distinct data server: at the anticipated scale of 1024 and nconnect=16 the client opens 16k sockets plus their sunrpc slot tables, and striping already spreads I/O across the data servers, so a high per-DS transport count buys little for that workload. Add a dataserver_nconnect module parameter to the flexfiles layout driver alongside its existing dataserver_timeo and dataserver_retrans knobs, and thread the value through nfs4_pnfs_ds_connect() to both the v3 and v4 data-server client setup paths. The default of 0 preserves today's inherit-from-MDS behavior, so the cap is opt-in and non-regressing. The files layout passes 0, unchanged. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05pNFS: Add deviceid reference query and collection walkersBenjamin Coddington
The CB_NOTIFY_DEVICEID DELETE race recovery (RFC 8881 Section 18.40.4) needs to ask whether any live layout still references a deviceID, and to enumerate those layouts for TEST_STATEID. Add a layout_references_deviceid hook (sibling of reresolve_deviceid; the flexfiles implementation memcmps each mirror stripe's decoded devid, valid independent of the pinned device node) and two walkers over the byserver pattern: - pnfs_layout_deviceid_referenced_byclid(): boolean existence query, early-stopping, entirely under i_lock. - pnfs_layout_collect_deviceid_refs(): collects each matching layout with the hdr pinned, the inode grabbed with its superblock active (a pinned hdr does not hold its inode -- same discipline as the bulk-destroy walker), and the layout stateid and cred snapshotted under i_lock, so the caller can issue sleeping RPCs against the collection. The collection walker pins each matching header with a plain pnfs_get_layout_hdr(), which cannot resurrect a dying header because the walker holds i_lock and has checked NFS_I()->layout == lo. pnfs_put_layout_hdr() drops the last reference under i_lock -- refcount_dec_and_lock() only decrements one to zero once it holds the lock -- and clears NFS_I()->layout in that same critical section, before it unlocks and frees. So a header still installed on its inode cannot have reached a zero refcount. That argument deliberately does not rest on NFS_LAYOUT_INVALID_STID. A header can reach its final put while still valid: a full LAYOUTRETURN ends in pnfs_layoutreturn_free_lsegs(), which resets the layout stateid rather than invalidating it, and that is the ordinary end of life for a return-on-close layout. The validity check the walkers do apply is a policy filter, not a lifetime guarantee. Because pnfs_put_layout_hdr() can send a layoutreturn and sleep, a header pinned for a layout whose inode can no longer be grabbed is put after the RCU read-side critical section, not within it. Both ways the walk can end early report it. A GFP_ATOMIC allocation failure aborts with -ENOMEM, and an inode that can no longer be grabbed -- igrab() fails from I_FREEING on, while the layout may still be valid and still name the deviceID -- aborts with -EAGAIN. Either way the caller is told the collection is partial instead of receiving a short list it would read as "no references". No callers yet; no behavior change. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Honor ndc_immediate on CB_NOTIFY_DEVICEID CHANGEBenjamin Coddington
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. A superseded node is distinguishable by hashed-ness: it 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 <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Implement in-place device re-resolve on CHANGEBenjamin Coddington
Implement the reresolve_deviceid hook: walk the layout's mirrors and, for every stripe whose raw deviceid matches the changed one, exchange the pinned device node out for NULL. In-flight I/O completes on the old node through its own reference; the next I/O to the stripe re-resolves via ff_layout_get_mirror_ds() and picks up the server's new mapping with a fresh GETDEVICEINFO. The un-pinned references are handed back on the walker's list to be put outside the locks. Matching uses the raw deviceid decoded from the layout (dss[].devid), so a stripe that was never resolved, or already exchanged, is left alone. A stripe whose resolution previously failed holds an ERR_PTR sentinel rather than a node; that is cleared too, so the stripe retries GETDEVICEINFO on its next I/O. Nothing dispatches CHANGE to the walker yet: no behavior change. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Make the pinned device node pointer RCU-managedBenjamin Coddington
Annotate mirror->dss[dss_id].mirror_ds as __rcu and convert the remaining readers, completing the preparation for re-pointing the pinned node while I/O is in flight: - ff_layout_get_mirror_ds() takes its reference under rcu_read_lock() with atomic_inc_not_zero(), retrying if it races a reset. The resolve path takes the caller's reference before publishing the node with cmpxchg(), so a concurrent reset cannot drop the last reference under the caller: one reference is held for the installed pointer and one for the caller, and the pointer's reference is released elsewhere by xchg + put. - The availability scans hold rcu_read_lock() across the walk; they only test flags on the RCU-freed node. - ff_layout_cancel_io() holds a reference across the cancel and disconnect calls. Both of its callers hold i_lock and nothing on that path sleeps, so the reference is not about blocking: it is what keeps the node alive between the RCU-protected read and the use of mirror_ds->ds. The final put is never reached here, because the mirror's own pin outlives the loop -- which matters, since that put ends in nfs_put_client() and cannot run under a spinlock. - ff_layout_mirror_prepare_stats() reads the pointer with rcu_dereference() under rcu_read_lock(). i_lock, which both callers hold, is what excludes the re-pointing walk added later in this series; it does not exclude the resolve path's cmpxchg(), which runs from I/O submission, so the read cannot claim i_lock as its update- side lock. A non-NULL pointer read there is stable regardless: the resolve path only ever installs over NULL. - ff_layout_free_mirror() tears down the last reference; no concurrency. The pointer is still only ever set once per mirror lifetime, so there is no behavior change; this commit makes the subsequent in-place re-resolve on CB_NOTIFY_DEVICEID CHANGE safe to introduce. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Hold a device node reference for layoutstats encodingBenjamin Coddington
ff_layout_mirror_prepare_stats() records a stripe's device under i_lock, but the layoutstats/layoutreturn XDR encode runs later and dereferences the mirror's pinned device node (for the DS netaddr) with no reference of its own. Once a CHANGE notification can re-point the pinned node, that read becomes use-after-free. Take a node reference at prepare time and carry it with the stripe in a per-devinfo nfs4_ff_layoutstat_priv, released in ff_layout_free_layoutstats(). The priv entries live alongside the devinfo array: co-allocated for LAYOUTSTATS, an additional member of nfs4_flexfile_layoutreturn_args for LAYOUTRETURN. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Carry the device node reference across each I/OBenjamin Coddington
Rather than dropping the device node reference when DS setup completes, transfer it to the in-flight I/O: carry it on nfs_pgio_header and nfs_commit_data as ds_dev, and release it when the header or commit data is released, alongside the lseg reference. Convert the completion paths to use the carried node instead of re-reading the mirror's pinned pointer: DS error tracking, marking the deviceid available/unavailable, and deleting the deviceid on connection errors now act on the node the I/O was actually sent to. Once a CHANGE notification can re-point the pinned pointer mid-flight, this keeps error attribution on the old device rather than its replacement (and removes a NULL dereference had the pointer been reset to NULL). FF_LAYOUT_DEVID_NODE() is now unused; remove it. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Reference the device node across DS setupBenjamin Coddington
The flexfiles I/O setup paths read the mirror's pinned per-stripe device node (mirror->dss[dss_id].mirror_ds) repeatedly and locklessly, relying on the mirror's lifetime pin. To prepare for re-resolving that pointer in place on CB_NOTIFY_DEVICEID CHANGE, readers must hold their own reference on the node they are using rather than trusting the pin. Replace ff_layout_init_mirror_ds() with ff_layout_get_mirror_ds(), which resolves on first use as before but returns the node with its own reference held. Thread the referenced node through nfs4_ff_layout_prepare_ds() and the DS selection helpers so each setup path snapshots the node once, and drop the reference when setup is done. No functional change: the pointer is still resolved once and pinned for the life of the mirror. Each reference this adds is released on every exit from the path that took it, error paths included. Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Bound page coalescing on the absolute stripe offsetBenjamin Coddington
ff_layout_pg_test() was copied from the files layout, which partitions data servers relative to pattern_offset and bounds coalescing with a segment-relative offset. Flexfiles has no pattern_offset: nfs4_ff_layout_calc_dss_id() partitions on the absolute file offset (RFC 8435 Section 6). So when a layout segment's offset is not stripe-unit-aligned, the segment-relative coalescing window is shifted off the absolute stripe grid and a coalesced I/O can straddle a stripe boundary, sending the bytes past it to the wrong data server. Bound coalescing on the absolute offset to match calc_dss_id(). Aligned segments, including all whole-file layouts, are unchanged. Fixes: 4934ccbeaed3 ("NFSv4/flexfiles: Read path updates for striped layouts") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Use the full 64-bit offset for read DS selectionBenjamin Coddington
The read data-server selection helpers declare their offset parameter as u32, truncating the file offset before nfs4_ff_layout_calc_dss_id() computes the stripe index. The write path already passes the full offset; make the read path match. Fixes: 4934ccbeaed3 ("NFSv4/flexfiles: Read path updates for striped layouts") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: Use the full 64-bit stripe_unitBenjamin Coddington
ff_layout_alloc_lseg() decodes stripe_unit as the 64-bit value the protocol defines and struct nfs4_ff_layout_segment stores it as one, but both consumers narrow it back to 32 bits: nfs4_ff_layout_calc_dss_id() divides with do_div(), which casts the divisor, and ff_layout_pg_test() copies it into a u32 first. A stripe_unit that does not fit is silently truncated, so the client stripes on a unit the server did not specify -- or divides by zero, if the low 32 bits happen to be clear. Divide by the full value, with div64_u64() and div64_u64_rem(). Fixes: 20b1d75fb840 ("NFSv4/flexfiles: Add support for striped layouts") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-fable-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/pnfs: Free the netid when draining a data-server address listBenjamin Coddington
nfs4_pnfs_ds_addr_free() releases all three of an address entry's allocations, but the four sites that drain a decoded list before it reaches a data server open-code the loop and free only da_remotestr and the entry, leaking da_netid. Both layout drivers drain that list when nfs4_pnfs_ds_add() returned a data server already in the cache, and again on their error exits. Lift the drain into nfs4_pnfs_ds_addr_list_free() so an address list has one owner. A striping mount reaches the cached case on nearly every GETDEVICEINFO, since many deviceIDs name the same data servers. Fixes: 4be78d26810b ("NFSv4/pNFS: Store the transport type in struct nfs4_pnfs_ds_addr") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-5 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-10-05NFSv4/flexfiles: allocate the per-mirror stripe array with kvzalloc_objsBenjamin Coddington
Each mirror's stripe array is a single contiguous allocation of dss_count * sizeof(struct nfs4_ff_layout_ds_stripe) -- roughly 300 bytes per stripe. With the LAYOUTGET reply buffer no longer capped at a single page, a wide striped layout can push this well past the high-order allocation comfort zone (a 2048-stripe mirror is a ~600KB contiguous allocation) where it can fail under memory fragmentation. Use kvzalloc_objs() so wide stripe arrays fall back to vmalloc. Note the vmalloc fallback is unavailable when the pageio path allocates under memalloc_noio (swap over pNFS); that case simply behaves as before. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-08-20NFSv4/pnfs: key the data server cache on the NFS versionJunrui Luo
nfs4_pnfs_ds_add() keys the per-net data server cache on the multipath address set alone, and struct nfs4_pnfs_ds records no version. That suffices for the files layout driver, which always connects with version 4, but flexfiles takes its version tuple from GETDEVICEINFO per device, and one address can legitimately serve both NFSv3 and NFSv4. Two deviceids on one address with different ds_versions[0].version therefore share a single nfs4_pnfs_ds, and whichever mirror connects first pins ds_clp to its own version. The other one is handed that client anyway, so it selects rpc_call_ops for a version the connection does not speak, and the mismatched sequence-slot handling dereferences NULL. Add the version to the cache key so the two cannot alias, giving each version its own nfs4_pnfs_ds and connection while both mirrors stay usable. Only the major version is compared, since that is what selects rpc_call_ops and rpc_ops; v4.0 and v4.1 keep sharing a client. The files layout driver passes the 4 it already hardcodes at connect time. Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Reported-by: Yuhao Jiang <danisjiang@gmail.com> Assisted-by: Claude:claude-opus-5 Signed-off-by: Junrui Luo <moonafterrain@outlook.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2026-08-17NFSv4/flexfiles: support loosely coupled data serversJeuk Kim
A flexfiles storage device is tightly coupled to the MDS only when the decoded ds_versions[0].tightly_coupled flag is set (RFC 8435, sections 2.3 and 4.1). The client currently ignores that flag and treats every data server as tightly coupled, which breaks I/O to loosely coupled DSes. Two things force that assumption on an NFSv4.1+ DS: 1) nfs4_set_ds_client() always sets NFS_CS_PNFS on the new client, so EXCHANGE_ID is sent with EXCHGID4_FLAG_USE_PNFS_DS. 2) nfs4_init_ds_session() then calls is_ds_client() and returns -ENODEV if the reply does not carry EXCHGID4_FLAG_USE_PNFS_DS. A loosely coupled DS is just a normal NFS server and does not act in the pNFS DS role, so the client must not require it to advertise that role. Thread the ds_versions[0].tightly_coupled flag from the flexfiles driver down to the DS connect path. When it is false, skip both the NFS_CS_PNFS flag and the is_ds_client() check. The file layout driver always passes true because NFSv4.1 file layout data servers use the pNFS DS role. Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2026-08-17NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data serversJeuk Kim
flexfiles accepts NFSv4.0 data servers, but two NFSv4 code paths assume the data server client has a session. Unlike NFSv4.1+, an NFSv4.0 client has no session (clp->cl_session is NULL; it uses clp->cl_slot_tbl), so I/O to a v4.0 flexfiles DS oopses: - nfs4_init_ds_session() dereferences clp->cl_session->session_state while seeding the DS lease. It also only seeds cl_lease_time when NFS4_SESSION_INITING is set; without a session that never happens, so cl_lease_time stays 0 and nfs4_renew_state() busy-loops, requeuing every 5 seconds. Seed the lease whenever there is no session and return before touching session state. - ff_layout_async_handle_error_v4() dereferences clp->cl_session->fc_slot_table on every DS I/O error. Fall back to the v4.0 transport slot table (clp->cl_slot_tbl) when there is no session. Fixes: a7878ca14008 ("nfs: flexfilelayout: remove v3-only data server limitation") Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2026-08-17NFSv4/flexfiles: report cancelled I/O as a layout errorBenjamin Coddington
When a layout is recalled or revoked the client cancels its in-flight I/O so the layout can be returned. The metadata server needs to learn that this I/O to the storage device did not complete, so that it can reconcile the affected mirror instance (or, if none remains, take other action). The cancellation completed with -EAGAIN, which ff_layout_io_track_ds_error() does not recognise: it fell through the switch and recorded nothing, so no error was reported to the server. -EAGAIN is overloaded in the RPC layer, so rather than key the reporting on it, cancel the I/O with -ECANCELED and map that to NFS4ERR_NXIO in ff_layout_io_track_ds_error() -- the status the client already reports for the transport errors that leave an in-flight write incomplete. The cancelled I/O is then reported to the server via LAYOUTERROR / LAYOUTRETURN. Unlike a genuine transport error, though, we aborted the I/O ourselves and have no evidence the device is at fault, so once the error is recorded we skip marking the device unreachable and forcing a further layout return. The retry disposition is unchanged from the original -EAGAIN cancellation: both NFS4ERR_NXIO and -ECANCELED are no-ops in ff_layout_async_handle_error(), which still resets the I/O to pNFS (or the MDS), so it is re-driven as before. Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2026-06-08NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_writeMike Snitzer
The FF_FLAGS_NO_IO_THRU_MDS flag lives on each lseg, so any fallback decision made when there is no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) cannot run the per-lseg check. Introduce a sticky hdr-level ditto for FF_FLAGS_NO_IO_THRU_MDS in struct nfs4_flexfile_layout::flags (NFS4_FF_HDR_NO_IO_THRU_MDS bit), set whenever ff_layout_alloc_lseg() parses an lseg with the flag. The bit is never cleared for the lifetime of the layout hdr; the server is assumed to be consistent in its no-fallback policy per file. kzalloc() in ff_layout_alloc_layout_hdr() zero-initializes the field. Use the new ff_layout_hdr_no_fallback_to_mds() helper to gate ff_layout_pg_get_mirror_count_write(): when pnfs_update_layout() returns NULL (e.g. NFS_LAYOUT_BULK_RECALL, pnfs_layout_io_test_failed, pnfs_layoutgets_blocked) the existing code unconditionally calls nfs_pageio_reset_write_mds(). This is a source of unwanted WRITE to MDS. Fix it by checking NFS4_FF_HDR_NO_IO_THRU_MDS bit, and if set surface -EAGAIN instead; the writepage-side caller (nfs_do_writepage() for buffered, nfs_direct_write_reschedule() for O_DIRECT) then redirties the request so writeback retries via pNFS. Fixes: 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS") Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-06-08NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS on fatal DS connect errorsMike Snitzer
Commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") teaches ff_layout_{read,write}_pagelist() to return PNFS_NOT_ATTEMPTED when nfs4_ff_layout_prepare_ds() fails with a nfs_error_is_fatal() errno (e.g. -ETIMEDOUT from a SOFTCONN connect deadline, -ENOMEM, -ERESTARTSYS), so that the client gives up instead of spinning. pnfs_do_{read,write}() then dispatches the I/O through pnfs_{read,write}_through_mds() → nfs_pageio_reset_{read,write}_mds(). That fallback is unconditional and silently violates FF_FLAGS_NO_IO_THRU_MDS: when the layout segment carries the flag (typically single-mirror appliance layouts where MDS I/O is explicitly forbidden), the out_failed: path's \`&& !ds_fatal_error\` clause overrides the flag's short-circuit through ff_layout_avoid_mds_available_ds() and routes the I/O to the MDS file handle anyway. This is reachable in practice during a data-server restart: SOFTCONN exhaustion produces -ETIMEDOUT, which is fatal per nfs_error_is_fatal(), which triggers PNFS_NOT_ATTEMPTED, which silently goes to MDS. Preserve the upstream "don't spin on fatal errors" intent for layouts that permit MDS fallback. For layouts with FF_FLAGS_NO_IO_THRU_MDS set, mark the layout for return and request PNFS_TRY_AGAIN instead; if the server cannot supply a usable layout the failure now surfaces cleanly via pnfs_update_layout(), rather than via silent MDS I/O that contradicts the flag. Fixes: f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-06-08NFSv4/flexfiles: reject zero filehandle version countMichael Bommarito
ff_layout_alloc_lseg() decodes the filehandle-version array count from the flexfiles layout body. The value is used as the count for kzalloc_objs(), and the current code only rejects NULL. A zero count yields ZERO_SIZE_PTR, which can be stored in dss_info->fh_versions even though later flexfiles paths assume that at least one filehandle version exists. Reject fh_count == 0 before the allocation, matching the existing zero version_count validation in the flexfiles GETDEVICEINFO parser. A QEMU/KASAN run with a malformed flexfiles layout hit: KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] RIP: 0010:ff_layout_encode_ff_layoutupdate.isra.0+0x15f/0x750 ff_layout_encode_layoutreturn+0x683/0x970 nfs4_xdr_enc_layoutreturn+0x278/0x3a0 Kernel panic - not syncing: Fatal exception The patched kernel rejects the malformed layout without KASAN/oops/panic, and a valid fh_count=1 regression still opens, reads, and unmounts cleanly. Cc: stable@vger.kernel.org Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-06-08nfs: replace NFS_FILEID() and nfsi->fileid with inode->i_inoJeff Layton
Now that inode->i_ino stores the full 64-bit NFS fileid, replace all uses of NFS_FILEID(), set_nfs_fileid(), and direct nfsi->fileid accesses with inode->i_ino throughout the NFS client. Remove the NFS_FILEID() and set_nfs_fileid() helper functions from include/linux/nfs_fs.h since they are no longer needed. Also fix two pre-existing truncation bugs in nfs4trace.h where fileid trace fields were declared as u32 instead of u64. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
2026-04-24Merge tag 'nfs-for-7.1-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfsLinus Torvalds
Pull NFS client updates from Trond Myklebust: "Bugfixes: - Fix handling of ENOSPC so that if we have to resend writes, they are written synchronously - SUNRPC RDMA transport fixes from Chuck - Several fixes for delegated timestamps in NFSv4.2 - Failure to obtain a directory delegation should not cause stat() to fail with NFSv4 - Rename was failing to update timestamps when a directory delegation is held on NFSv4 - Ensure we check rsize/wsize after crossing a NFSv4 filesystem boundary - NFSv4/pnfs: - If the server is down, retry the layout returns on reboot - Fallback to MDS could result in a short write being incorrectly logged Cleanups: - Use memcpy_and_pad in decode_fh" * tag 'nfs-for-7.1-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (21 commits) NFS: Fix RCU dereference of cl_xprt in nfs_compare_super_address NFS: remove redundant __private attribute from nfs_page_class NFSv4.2: fix CLONE/COPY attrs in presence of delegated attributes NFS: fix writeback in presence of errors nfs: use memcpy_and_pad in decode_fh NFSv4.1: Apply session size limits on clone path NFSv4: retry GETATTR if GET_DIR_DELEGATION failed NFS: fix RENAME attr in presence of directory delegations pnfs/flexfiles: validate ds_versions_cnt is non-zero NFS/blocklayout: print each device used for SCSI layouts xprtrdma: Post receive buffers after RPC completion xprtrdma: Scale receive batch size with credit window xprtrdma: Replace rpcrdma_mr_seg with xdr_buf cursor xprtrdma: Decouple frwr_wp_create from frwr_map xprtrdma: Close lost-wakeup race in xprt_rdma_alloc_slot xprtrdma: Avoid 250 ms delay on backlog wakeup xprtrdma: Close sendctx get/put race that can block a transport nfs: update inode ctime after removexattr operation nfs: fix utimensat() for atime with delegated timestamps NFS: improve "Server wrote zero bytes" error ...
2026-04-13pnfs/flexfiles: validate ds_versions_cnt is non-zeroJenny Guanni Qu
nfs4_ff_alloc_deviceid_node() reads version_count from XDR without checking it is non-zero. When a malicious NFS server sends a pNFS LAYOUTGET response with version_count=0, kcalloc(0, ...) returns ZERO_SIZE_PTR (0x10). The subsequent ds_versions[0] access in nfs4_ff_layout_ds_version() and other callers dereferences this invalid pointer, causing an out-of-bounds read. Add a check for version_count == 0 after parsing it from XDR, before the allocation. The OOB read was confirmed with KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] from accessing ZERO_SIZE_PTR. Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Reported-by: Klaudia Kloc <klaudia@vidocsecurity.com> Reported-by: Dawid Moczadło <dawid@vidocsecurity.com> Tested-by: Jenny Guanni Qu <qguanni@gmail.com> Signed-off-by: Jenny Guanni Qu <qguanni@gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2026-03-06treewide: change inode->i_ino from unsigned long to u64Jeff Layton
On 32-bit architectures, unsigned long is only 32 bits wide, which causes 64-bit inode numbers to be silently truncated. Several filesystems (NFS, XFS, BTRFS, etc.) can generate inode numbers that exceed 32 bits, and this truncation can lead to inode number collisions and other subtle bugs on 32-bit systems. Change the type of inode->i_ino from unsigned long to u64 to ensure that inode numbers are always represented as 64-bit values regardless of architecture. Update all format specifiers treewide from %lu/%lx to %llu/%llx to match the new type, along with corresponding local variable types. This is the bulk treewide conversion. Earlier patches in this series handled trace events separately to allow trace field reordering for better struct packing on 32-bit. Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20260304-iino-u64-v3-12-2257ad83d372@kernel.org Acked-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
2026-02-21treewide: Replace kmalloc with kmalloc_obj for non-scalar typesKees Cook
This is the result of running the Coccinelle script from scripts/coccinelle/api/kmalloc_objs.cocci. The script is designed to avoid scalar types (which need careful case-by-case checking), and instead replace kmalloc-family calls that allocate struct or union object instances: Single allocations: kmalloc(sizeof(TYPE), ...) are replaced with: kmalloc_obj(TYPE, ...) Array allocations: kmalloc_array(COUNT, sizeof(TYPE), ...) are replaced with: kmalloc_objs(TYPE, COUNT, ...) Flex array allocations: kmalloc(struct_size(PTR, FAM, COUNT), ...) are replaced with: kmalloc_flex(*PTR, FAM, COUNT, ...) (where TYPE may also be *VAR) The resulting allocations no longer return "void *", instead returning "TYPE *". Signed-off-by: Kees Cook <kees@kernel.org>
2026-01-04pnfs/flexfiles: Fix memory leak in nfs4_ff_alloc_deviceid_node()Zilin Guan
In nfs4_ff_alloc_deviceid_node(), if the allocation for ds_versions fails, the function jumps to the out_scratch label without freeing the already allocated dsaddrs list, leading to a memory leak. Fix this by jumping to the out_err_drain_dsaddrs label, which properly frees the dsaddrs list before cleaning up other resources. Fixes: d67ae825a59d6 ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Zilin Guan <zilin@seu.edu.cn> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2025-10-13NFSv4/flexfiles: fix to allocate mirror->dss before useMike Snitzer
Move mirror_array's dss_count initialization and dss allocation to ff_layout_alloc_mirror(), just before the loop that initializes each nfs4_ff_layout_ds_stripe's nfs_file_localio. Also handle NULL return from kcalloc() and remove one level of indent in ff_layout_alloc_mirror(). This commit fixes dangling nfsd_serv refcount issues seen when using NFS LOCALIO and then attempting to stop the NFSD service. Fixes: 20b1d75fb840 ("NFSv4/flexfiles: Add support for striped layouts") Signed-off-by: Mike Snitzer <snitzer@kernel.org> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Add support for striped layoutsJonathan Curley
Updates lseg creation path to parse and add striped layouts. Enable support for striped layouts. Limitations: 1. All mirrors must have the same number of stripes. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Update layout stats & error paths for striped layoutsJonathan Curley
Updates the layout stats logic to be stripe aware. Read and write stats are accumulated on a per DS stripe basis. Also updates error paths to use dss_id where appropraite. Limitations: 1. The layout stats structure is still statically sized to 4 and there is no deduplication logic for deviceids that may appear more than once in a striped layout. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Write path updates for striped layoutsJonathan Curley
Updates write path to calculate and use dss_id to direct IO to the appropriate stripe DS. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Commit path updates for striped layoutsJonathan Curley
Updates the commit path to be stripe aware. This required updating the ds_commit_idx to be stripe aware. ds_commit_idx == mirror_idx * dss_count + dss_id. Updates code paths to utilize the new ds_commit_idx and derive dss_id & mirror_idx where appropriate to contact the correct DS using the corresponding parameters. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Read path updates for striped layoutsJonathan Curley
Updates read path to calculate and use dss_id to direct IO to the appropriate stripe DS. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Update low level helper functions to be DS stripe aware.Jonathan Curley
Updates common helper functions to be dss_id aware. Most cases simply add a dss_id parameter. The has_available functions have been updated with a loop. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Add data structure support for striped layoutsJonathan Curley
Adds a new struct nfs4_ff_layout_ds_stripe that represents a data server stripe within a layout. A new dynamically allocated array of this type has been added to nfs4_ff_layout_mirror and per stripe configuration information has been moved from the mirror type to the stripe based on the RFC. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-26NFSv4/flexfiles: Remove cred local variable dependencyJonathan Curley
No-op preparation change to remove dependency on cred local variable. Subsequent striping diff has a cred per stripe so this local variable can't be trusted to be the same. Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-23NFS: Update the flexfilelayout driver to use xdr_set_scratch_folio()Anna Schumaker
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
2025-09-08NFSv4/flexfiles: Fix layout merge mirror check.Jonathan Curley
Typo in ff_lseg_match_mirrors makes the diff ineffective. This results in merge happening all the time. Merge happening all the time is problematic because it marks lsegs invalid. Marking lsegs invalid causes all outstanding IO to get restarted with EAGAIN and connections to get closed. Closing connections constantly triggers race conditions in the RDMA implementation... Fixes: 660d1eb22301c ("pNFS/flexfile: Don't merge layout segments if the mirrors don't match") Signed-off-by: Jonathan Curley <jcurley@purestorage.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2025-09-06flexfiles/pNFS: fix NULL checks on result of ff_layout_choose_ds_for_readTigran Mkrtchyan
Recent commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") has changed the error return type of ff_layout_choose_ds_for_read() from NULL to an error pointer. However, not all code paths have been updated to match the change. Thus, some non-NULL checks will accept error pointers as a valid return value. Reported-by: Dan Carpenter <dan.carpenter@linaro.org> Suggested-by: Dan Carpenter <dan.carpenter@linaro.org> Fixes: f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2025-07-22pNFS/flexfiles: don't attempt pnfs on fatal DS errorsTigran Mkrtchyan
When an applications get killed (SIGTERM/SIGINT) while pNFS client performs a connection to DS, client ends in an infinite loop of connect-disconnect. This source of the issue, it that flexfilelayoutdev#nfs4_ff_layout_prepare_ds gets an error on nfs4_pnfs_ds_connect with status ERESTARTSYS, which is set by rpc_signal_task, but the error is treated as transient, thus retried. The issue is reproducible with Ctrl+C the following script(there should be ~1000 files in a directory, client should must not have any connections to DSes): ``` echo 3 > /proc/sys/vm/drop_caches for i in * do head -1 $i done ``` The change aims to propagate the nfs4_ff_layout_prepare_ds error state to the caller that can decide whatever this is a retryable error or not. Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Link: https://lore.kernel.org/r/20250627071751.189663-1-tigran.mkrtchyan@desy.de Fixes: 260f32adb88d ("pNFS/flexfiles: Check the result of nfs4_pnfs_ds_connect") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
2025-06-26NFSv4/flexfiles: Fix handling of NFS level errors in I/OTrond Myklebust
Allow the flexfiles error handling to recognise NFS level errors (as opposed to RPC level errors) and handle them separately. The main motivator is the NFSERR_PERM errors that get returned if the NFS client connects to the data server through a port number that is lower than 1024. In that case, the client should disconnect and retry a READ on a different data server, or it should retry a WRITE after reconnecting. Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de> Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>