* [PATCH 2/2] pnfs/blocklayout: Fix device leaks on parse failure
2026-06-25 3:20 [PATCH 1/2] NFSv4.1: Fix nfs_client refcount leak in nfs41_free_stateid zhang.guodong
@ 2026-06-25 3:20 ` zhang.guodong
0 siblings, 0 replies; 2+ messages in thread
From: zhang.guodong @ 2026-06-25 3:20 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: linux-nfs, ZhangGuoDong
From: ZhangGuoDong <zhangguodong@kylinos.cn>
bl_parse_concat() and bl_parse_stripe() allocate a child device array and
then parse each child in turn. If parsing a child fails, the failed child is
not counted in nr_children and the parent may be left with a children array
that bl_free_device() will not release when nr_children is zero.
Release the failed child and the already parsed children before returning the
error. Also make bl_free_device() release the child array whenever the
children pointer is set, so that partially initialised concat or stripe
devices are cleaned up correctly.
bl_parse_scsi() can also fail after assigning d->bdev_file and dropping the
file reference. Clear the pointer after fput() so that an outer cleanup path
does not put it again.
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
---
fs/nfs/blocklayout/dev.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c
index bb35f8850..db4bb0a62 100644
--- a/fs/nfs/blocklayout/dev.c
+++ b/fs/nfs/blocklayout/dev.c
@@ -85,15 +85,17 @@ bl_free_device(struct pnfs_block_dev *dev)
{
bl_unregister_dev(dev);
- if (dev->nr_children) {
+ if (dev->children) {
int i;
for (i = 0; i < dev->nr_children; i++)
bl_free_device(&dev->children[i]);
kfree(dev->children);
- } else {
- if (dev->bdev_file)
- fput(dev->bdev_file);
+ dev->children = NULL;
+ dev->nr_children = 0;
+ } else if (dev->bdev_file) {
+ fput(dev->bdev_file);
+ dev->bdev_file = NULL;
}
}
@@ -437,6 +439,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
out_blkdev_put:
fput(d->bdev_file);
+ d->bdev_file = NULL;
return error;
}
@@ -472,8 +475,11 @@ bl_parse_concat(struct nfs_server *server, struct pnfs_block_dev *d,
for (i = 0; i < v->concat.volumes_count; i++) {
ret = bl_parse_deviceid(server, &d->children[i],
volumes, v->concat.volumes[i], gfp_mask);
- if (ret)
+ if (ret) {
+ bl_free_device(&d->children[i]);
+ bl_free_device(d);
return ret;
+ }
d->nr_children++;
d->children[i].start += len;
@@ -501,8 +507,11 @@ bl_parse_stripe(struct nfs_server *server, struct pnfs_block_dev *d,
for (i = 0; i < v->stripe.volumes_count; i++) {
ret = bl_parse_deviceid(server, &d->children[i],
volumes, v->stripe.volumes[i], gfp_mask);
- if (ret)
+ if (ret) {
+ bl_free_device(&d->children[i]);
+ bl_free_device(d);
return ret;
+ }
d->nr_children++;
len += d->children[i].len;
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread