summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2021-07-22 09:53:58 +0200
committerJens Axboe <axboe@kernel.dk>2021-08-02 13:37:28 -0600
commit9d3b8813895d737fcef4ec8df518f67e5cc381b8 (patch)
tree13db699bd15205a45a9b571c4d8643000f9b61dc /block
parent0468c5323413c6903e4cbcef841a55e6c5578cd2 (diff)
downloadlinux-9d3b8813895d737fcef4ec8df518f67e5cc381b8.tar.gz
linux-9d3b8813895d737fcef4ec8df518f67e5cc381b8.tar.bz2
linux-9d3b8813895d737fcef4ec8df518f67e5cc381b8.zip
block: change the refcounting for partitions
Instead of acquiring an inode reference on open make sure partitions always hold device model references to the disk while alive, and switch open to grab only a device model reference to the opened block device. If that is a partition the disk reference is transitively held by the partition already. Link: https://lore.kernel.org/r/20210722075402.983367-6-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/partitions/core.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/block/partitions/core.c b/block/partitions/core.c
index 09c58a110a89..4f7a1a9cd544 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -261,6 +261,7 @@ static void part_release(struct device *dev)
{
if (MAJOR(dev->devt) == BLOCK_EXT_MAJOR)
blk_free_ext_minor(MINOR(dev->devt));
+ put_disk(dev_to_bdev(dev)->bd_disk);
bdput(dev_to_bdev(dev));
}
@@ -349,9 +350,13 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
if (xa_load(&disk->part_tbl, partno))
return ERR_PTR(-EBUSY);
+ /* ensure we always have a reference to the whole disk */
+ get_device(disk_to_dev(disk));
+
+ err = -ENOMEM;
bdev = bdev_alloc(disk, partno);
if (!bdev)
- return ERR_PTR(-ENOMEM);
+ goto out_put_disk;
bdev->bd_start_sect = start;
bdev_set_nr_sectors(bdev, len);
@@ -420,6 +425,8 @@ out_del:
device_del(pdev);
out_put:
put_device(pdev);
+out_put_disk:
+ put_disk(disk);
return ERR_PTR(err);
}