summaryrefslogtreecommitdiff
path: root/block/partitions
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2020-11-26 09:23:26 +0100
committerJens Axboe <axboe@kernel.dk>2020-12-01 14:53:39 -0700
commit22ae8ce8b89241c94ac00c237752c0ffa37ba5ae (patch)
treeaf6d4dfd72e76789c25c64cd1765f037d91f6b72 /block/partitions
parent4e7b5671c6a883d94b5428e1a9c141bbd56cb2a6 (diff)
block: simplify bdev/disk lookup in blkdev_get
To simplify block device lookup and a few other upcoming areas, make sure that we always have a struct block_device available for each disk and each partition, and only find existing block devices in bdget. The only downside of this is that each device and partition uses a little more memory. The upside will be that a lot of code can be simplified. With that all we need to look up the block device is to lookup the inode and do a few sanity checks on the gendisk, instead of the separate lookup for the gendisk. For blk-cgroup which wants to access a gendisk without opening it, a new blkdev_{get,put}_no_open low-level interface is added to replace the previous get_gendisk use. Note that the change to look up block device directly instead of the two step lookup using struct gendisk causes a subtile change in behavior: accessing a non-existing partition on an existing block device can now cause a call to request_module. That call is harmless, and in practice no recent system will access these nodes as they aren't created by udev and static /dev/ setups are unusual. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/partitions')
-rw-r--r--block/partitions/core.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/block/partitions/core.c b/block/partitions/core.c
index a02e22411594..696bd9ff63c6 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -340,12 +340,11 @@ void delete_partition(struct hd_struct *part)
device_del(part_to_dev(part));
/*
- * Remove gendisk pointer from idr so that it cannot be looked up
- * while RCU period before freeing gendisk is running to prevent
- * use-after-free issues. Note that the device number stays
- * "in-use" until we really free the gendisk.
+ * Remove the block device from the inode hash, so that it cannot be
+ * looked up any more even when openers still hold references.
*/
- blk_invalidate_devt(part_devt(part));
+ remove_inode_hash(part->bdev->bd_inode);
+
percpu_ref_kill(&part->ref);
}
@@ -368,6 +367,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
dev_t devt = MKDEV(0, 0);
struct device *ddev = disk_to_dev(disk);
struct device *pdev;
+ struct block_device *bdev;
struct disk_part_tbl *ptbl;
const char *dname;
int err;
@@ -402,11 +402,15 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
if (!p)
return ERR_PTR(-EBUSY);
+ err = -ENOMEM;
p->dkstats = alloc_percpu(struct disk_stats);
- if (!p->dkstats) {
- err = -ENOMEM;
+ if (!p->dkstats)
goto out_free;
- }
+
+ bdev = bdev_alloc(disk, partno);
+ if (!bdev)
+ goto out_free_stats;
+ p->bdev = bdev;
hd_sects_seq_init(p);
pdev = part_to_dev(p);
@@ -420,10 +424,8 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
struct partition_meta_info *pinfo;
pinfo = kzalloc_node(sizeof(*pinfo), GFP_KERNEL, disk->node_id);
- if (!pinfo) {
- err = -ENOMEM;
- goto out_free_stats;
- }
+ if (!pinfo)
+ goto out_bdput;
memcpy(pinfo, info, sizeof(*info));
p->info = pinfo;
}
@@ -470,6 +472,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
}
/* everything is up and running, commence */
+ bdev_add(bdev, devt);
rcu_assign_pointer(ptbl->part[partno], p);
/* suppress uevent if the disk suppresses it */
@@ -479,6 +482,8 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
out_free_info:
kfree(p->info);
+out_bdput:
+ bdput(bdev);
out_free_stats:
free_percpu(p->dkstats);
out_free: