Skip to content

Commit

Permalink
block: simplify bdev/disk lookup in blkdev_get
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
Christoph Hellwig authored and axboe committed Dec 1, 2020
1 parent 4e7b567 commit 22ae8ce
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 319 deletions.
42 changes: 21 additions & 21 deletions block/blk-cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -556,22 +556,22 @@ static struct blkcg_gq *blkg_lookup_check(struct blkcg *blkcg,
}

/**
* blkg_conf_prep - parse and prepare for per-blkg config update
* blkcg_conf_open_bdev - parse and open bdev for per-blkg config update
* @inputp: input string pointer
*
* Parse the device node prefix part, MAJ:MIN, of per-blkg config update
* from @input and get and return the matching gendisk. *@inputp is
* from @input and get and return the matching bdev. *@inputp is
* updated to point past the device node prefix. Returns an ERR_PTR()
* value on error.
*
* Use this function iff blkg_conf_prep() can't be used for some reason.
*/
struct gendisk *blkcg_conf_get_disk(char **inputp)
struct block_device *blkcg_conf_open_bdev(char **inputp)
{
char *input = *inputp;
unsigned int major, minor;
struct gendisk *disk;
int key_len, part;
struct block_device *bdev;
int key_len;

if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2)
return ERR_PTR(-EINVAL);
Expand All @@ -581,16 +581,16 @@ struct gendisk *blkcg_conf_get_disk(char **inputp)
return ERR_PTR(-EINVAL);
input = skip_spaces(input);

disk = get_gendisk(MKDEV(major, minor), &part);
if (!disk)
bdev = blkdev_get_no_open(MKDEV(major, minor));
if (!bdev)
return ERR_PTR(-ENODEV);
if (part) {
put_disk_and_module(disk);
if (bdev_is_partition(bdev)) {
blkdev_put_no_open(bdev);
return ERR_PTR(-ENODEV);
}

*inputp = input;
return disk;
return bdev;
}

/**
Expand All @@ -607,18 +607,18 @@ struct gendisk *blkcg_conf_get_disk(char **inputp)
*/
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
char *input, struct blkg_conf_ctx *ctx)
__acquires(rcu) __acquires(&disk->queue->queue_lock)
__acquires(rcu) __acquires(&bdev->bd_disk->queue->queue_lock)
{
struct gendisk *disk;
struct block_device *bdev;
struct request_queue *q;
struct blkcg_gq *blkg;
int ret;

disk = blkcg_conf_get_disk(&input);
if (IS_ERR(disk))
return PTR_ERR(disk);
bdev = blkcg_conf_open_bdev(&input);
if (IS_ERR(bdev))
return PTR_ERR(bdev);

q = disk->queue;
q = bdev->bd_disk->queue;

rcu_read_lock();
spin_lock_irq(&q->queue_lock);
Expand Down Expand Up @@ -689,7 +689,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
goto success;
}
success:
ctx->disk = disk;
ctx->bdev = bdev;
ctx->blkg = blkg;
ctx->body = input;
return 0;
Expand All @@ -700,7 +700,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
spin_unlock_irq(&q->queue_lock);
rcu_read_unlock();
fail:
put_disk_and_module(disk);
blkdev_put_no_open(bdev);
/*
* If queue was bypassing, we should retry. Do so after a
* short msleep(). It isn't strictly necessary but queue
Expand All @@ -723,11 +723,11 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep);
* with blkg_conf_prep().
*/
void blkg_conf_finish(struct blkg_conf_ctx *ctx)
__releases(&ctx->disk->queue->queue_lock) __releases(rcu)
__releases(&ctx->bdev->bd_disk->queue->queue_lock) __releases(rcu)
{
spin_unlock_irq(&ctx->disk->queue->queue_lock);
spin_unlock_irq(&ctx->bdev->bd_disk->queue->queue_lock);
rcu_read_unlock();
put_disk_and_module(ctx->disk);
blkdev_put_no_open(ctx->bdev);
}
EXPORT_SYMBOL_GPL(blkg_conf_finish);

Expand Down
36 changes: 18 additions & 18 deletions block/blk-iocost.c
Original file line number Diff line number Diff line change
Expand Up @@ -3120,23 +3120,23 @@ static const match_table_t qos_tokens = {
static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
size_t nbytes, loff_t off)
{
struct gendisk *disk;
struct block_device *bdev;
struct ioc *ioc;
u32 qos[NR_QOS_PARAMS];
bool enable, user;
char *p;
int ret;

disk = blkcg_conf_get_disk(&input);
if (IS_ERR(disk))
return PTR_ERR(disk);
bdev = blkcg_conf_open_bdev(&input);
if (IS_ERR(bdev))
return PTR_ERR(bdev);

ioc = q_to_ioc(disk->queue);
ioc = q_to_ioc(bdev->bd_disk->queue);
if (!ioc) {
ret = blk_iocost_init(disk->queue);
ret = blk_iocost_init(bdev->bd_disk->queue);
if (ret)
goto err;
ioc = q_to_ioc(disk->queue);
ioc = q_to_ioc(bdev->bd_disk->queue);
}

spin_lock_irq(&ioc->lock);
Expand Down Expand Up @@ -3231,12 +3231,12 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
ioc_refresh_params(ioc, true);
spin_unlock_irq(&ioc->lock);

put_disk_and_module(disk);
blkdev_put_no_open(bdev);
return nbytes;
einval:
ret = -EINVAL;
err:
put_disk_and_module(disk);
blkdev_put_no_open(bdev);
return ret;
}

Expand Down Expand Up @@ -3287,23 +3287,23 @@ static const match_table_t i_lcoef_tokens = {
static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
size_t nbytes, loff_t off)
{
struct gendisk *disk;
struct block_device *bdev;
struct ioc *ioc;
u64 u[NR_I_LCOEFS];
bool user;
char *p;
int ret;

disk = blkcg_conf_get_disk(&input);
if (IS_ERR(disk))
return PTR_ERR(disk);
bdev = blkcg_conf_open_bdev(&input);
if (IS_ERR(bdev))
return PTR_ERR(bdev);

ioc = q_to_ioc(disk->queue);
ioc = q_to_ioc(bdev->bd_disk->queue);
if (!ioc) {
ret = blk_iocost_init(disk->queue);
ret = blk_iocost_init(bdev->bd_disk->queue);
if (ret)
goto err;
ioc = q_to_ioc(disk->queue);
ioc = q_to_ioc(bdev->bd_disk->queue);
}

spin_lock_irq(&ioc->lock);
Expand Down Expand Up @@ -3356,13 +3356,13 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
ioc_refresh_params(ioc, true);
spin_unlock_irq(&ioc->lock);

put_disk_and_module(disk);
blkdev_put_no_open(bdev);
return nbytes;

einval:
ret = -EINVAL;
err:
put_disk_and_module(disk);
blkdev_put_no_open(bdev);
return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion block/blk.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector);

int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
void blk_free_devt(dev_t devt);
void blk_invalidate_devt(dev_t devt);
char *disk_name(struct gendisk *hd, int partno, char *buf);
#define ADDPART_FLAG_NONE 0
#define ADDPART_FLAG_RAID 1
Expand Down Expand Up @@ -384,6 +383,7 @@ static inline void hd_free_part(struct hd_struct *part)
{
free_percpu(part->dkstats);
kfree(part->info);
bdput(part->bdev);
percpu_ref_exit(&part->ref);
}

Expand Down
Loading

0 comments on commit 22ae8ce

Please sign in to comment.