[PATCH 01/19] nfs/localio: fix nfsd_file ref leak on nfs_local_doio() init failure
From: Jeff Layton
Date: Tue Jun 09 2026 - 13:55:25 EST
Two early return paths in nfs_local_doio() fail to release the localio
(nfsd_file) reference passed in by the caller:
- When hdr->args.count is zero, the function returns 0 without calling
nfs_local_file_put().
- When nfs_local_iocb_init() fails (e.g. -ENOMEM from allocation or
-EOPNOTSUPP if the file lacks read_iter/write_iter), the function
returns the error without releasing localio or completing the hdr
lifecycle.
A leaked nfsd_file pins the associated net namespace reference,
blocking network namespace teardown, and holds a reference on the
exported filesystem, preventing unmount.
Fix the zero-count path by adding the missing nfs_local_file_put()
call. Fix the iocb init failure path by jumping to a new cleanup label
that releases localio, sets hdr->task.tk_status, and calls
nfs_local_hdr_release() -- matching the existing error handling pattern
for the post-iocb error path.
Fixes: e77c464c31b3 ("nfs/nfsd: add "local io" support")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
fs/nfs/localio.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index e55c5977fcc3..63cf6e2cc745 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -970,12 +970,16 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
struct nfs_local_kiocb *iocb;
int status = 0;
- if (!hdr->args.count)
+ if (!hdr->args.count) {
+ nfs_local_file_put(localio);
return 0;
+ }
iocb = nfs_local_iocb_init(hdr, localio);
- if (IS_ERR(iocb))
- return PTR_ERR(iocb);
+ if (IS_ERR(iocb)) {
+ status = PTR_ERR(iocb);
+ goto out_put_localio;
+ }
switch (hdr->rw_mode) {
case FMODE_READ:
@@ -996,6 +1000,12 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
nfs_local_hdr_release(hdr, call_ops);
}
return status;
+
+out_put_localio:
+ nfs_local_file_put(localio);
+ hdr->task.tk_status = status;
+ nfs_local_hdr_release(hdr, call_ops);
+ return status;
}
static void
--
2.54.0