mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
pnfs/blocklayout: Fix device leaks on parse failure
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: 5c83746a0c ("pnfs/blocklayout: in-kernel GETDEVICEINFO XDR parsing")
Signed-off-by: ZhangGuoDong <zhangguodong@kylinos.cn>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
d05c2007b3
commit
c056f817e4
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user