summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@kernel.org>2023-03-27 06:21:37 -0400
committerChuck Lever <chuck.lever@oracle.com>2023-03-31 17:29:49 -0400
commit15a8b55dbb1ba154d82627547c5761cac884d810 (patch)
tree888903dafac5768b218da64da4d0e1bc7e21e319 /fs/nfsd
parent804d8e0a6e54427268790472781e03bc243f4ee3 (diff)
downloadlinux-stable-15a8b55dbb1ba154d82627547c5761cac884d810.tar.gz
linux-stable-15a8b55dbb1ba154d82627547c5761cac884d810.tar.bz2
linux-stable-15a8b55dbb1ba154d82627547c5761cac884d810.zip
nfsd: call op_release, even when op_func returns an error
For ops with "trivial" replies, nfsd4_encode_operation will shortcut most of the encoding work and skip to just marshalling up the status. One of the things it skips is calling op_release. This could cause a memory leak in the layoutget codepath if there is an error at an inopportune time. Have the compound processing engine always call op_release, even when op_func sets an error in op->status. With this change, we also need nfsd4_block_get_device_info_scsi to set the gd_device pointer to NULL on error to avoid a double free. Reported-by: Zhi Li <yieli@redhat.com> Link: https://bugzilla.redhat.com/show_bug.cgi?id=2181403 Fixes: 34b1744c91cc ("nfsd4: define ->op_release for compound ops") Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/blocklayout.c1
-rw-r--r--fs/nfsd/nfs4xdr.c11
2 files changed, 6 insertions, 6 deletions
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 04697f8dc37d..01d7fd108cf3 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -297,6 +297,7 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
out_free_dev:
kfree(dev);
+ gdp->gd_device = NULL;
return ret;
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 67bbd2d6334c..7799835c2196 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -5400,10 +5400,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
__be32 *p;
p = xdr_reserve_space(xdr, 8);
- if (!p) {
- WARN_ON_ONCE(1);
- return;
- }
+ if (!p)
+ goto release;
*p++ = cpu_to_be32(op->opnum);
post_err_offset = xdr->buf->len;
@@ -5418,8 +5416,6 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
op->status = encoder(resp, op->status, &op->u);
if (op->status)
trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status);
- if (opdesc && opdesc->op_release)
- opdesc->op_release(&op->u);
xdr_commit_encode(xdr);
/* nfsd4_check_resp_size guarantees enough room for error status */
@@ -5460,6 +5456,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
}
status:
*p = op->status;
+release:
+ if (opdesc && opdesc->op_release)
+ opdesc->op_release(&op->u);
}
/*