6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: ZhangGuoDong [ Upstream commit c056f817e4200fb18079d5052c273a22f191ff0a ] 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. Fixes: 5c83746a0cf2 ("pnfs/blocklayout: in-kernel GETDEVICEINFO XDR parsing") Signed-off-by: ZhangGuoDong Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/blocklayout/dev.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index 61ee0b6c0fba2..9bb745ad8976c 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c @@ -16,12 +16,14 @@ static void bl_free_device(struct pnfs_block_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); + dev->children = NULL; + dev->nr_children = 0; } else { if (dev->pr_registered) { const struct pr_ops *ops = @@ -34,8 +36,10 @@ bl_free_device(struct pnfs_block_dev *dev) pr_err("failed to unregister PR key.\n"); } - if (dev->bdev) + if (dev->bdev) { blkdev_put(dev->bdev, NULL); + dev->bdev = NULL; + } } } @@ -377,6 +381,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d, out_blkdev_put: blkdev_put(d->bdev, NULL); + d->bdev = NULL; return error; } @@ -412,8 +417,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; @@ -441,8 +449,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.53.0