block: use the holder as indication for exclusive opens

The current interface for exclusive opens is rather confusing as it
requires both the FMODE_EXCL flag and a holder.  Remove the need to pass
FMODE_EXCL and just key off the exclusive open off a non-NULL holder.

For blkdev_put this requires adding the holder argument, which provides
better debug checking that only the holder actually releases the hold,
but at the same time allows removing the now superfluous mode argument.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Christian Brauner <brauner@kernel.org>
Acked-by: David Sterba <dsterba@suse.com>		[btrfs]
Acked-by: Jack Wang <jinpu.wang@ionos.com>		[rnbd]
Link: https://lore.kernel.org/r/20230608110258.189493-16-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Christoph Hellwig
2023-06-08 13:02:43 +02:00
committed by Jens Axboe
parent 2ef789288a
commit 2736e8eeb0
37 changed files with 183 additions and 192 deletions

View File

@@ -604,7 +604,7 @@ void bd_abort_claiming(struct block_device *bdev, void *holder)
}
EXPORT_SYMBOL(bd_abort_claiming);
static void bd_end_claim(struct block_device *bdev)
static void bd_end_claim(struct block_device *bdev, void *holder)
{
struct block_device *whole = bdev_whole(bdev);
bool unblock = false;
@@ -614,6 +614,7 @@ static void bd_end_claim(struct block_device *bdev)
* bdev_lock. open_mutex is used to synchronize disk_holder unlinking.
*/
mutex_lock(&bdev_lock);
WARN_ON_ONCE(bdev->bd_holder != holder);
WARN_ON_ONCE(--bdev->bd_holders < 0);
WARN_ON_ONCE(--whole->bd_holders < 0);
if (!bdev->bd_holders) {
@@ -750,10 +751,9 @@ void blkdev_put_no_open(struct block_device *bdev)
* @holder: exclusive holder identifier
* @hops: holder operations
*
* Open the block device described by device number @dev. If @mode includes
* %FMODE_EXCL, the block device is opened with exclusive access. Specifying
* %FMODE_EXCL with a %NULL @holder is invalid. Exclusive opens may nest for
* the same @holder.
* Open the block device described by device number @dev. If @holder is not
* %NULL, the block device is opened with exclusive access. Exclusive opens may
* nest for the same @holder.
*
* Use this interface ONLY if you really do not have anything better - i.e. when
* you are behind a truly sucky interface and all you are given is a device
@@ -785,10 +785,16 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder,
return ERR_PTR(-ENXIO);
disk = bdev->bd_disk;
if (mode & FMODE_EXCL) {
if (holder) {
mode |= FMODE_EXCL;
ret = bd_prepare_to_claim(bdev, holder, hops);
if (ret)
goto put_blkdev;
} else {
if (WARN_ON_ONCE(mode & FMODE_EXCL)) {
ret = -EIO;
goto put_blkdev;
}
}
disk_block_events(disk);
@@ -805,7 +811,7 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder,
ret = blkdev_get_whole(bdev, mode);
if (ret)
goto put_module;
if (mode & FMODE_EXCL) {
if (holder) {
bd_finish_claiming(bdev, holder, hops);
/*
@@ -829,7 +835,7 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder,
put_module:
module_put(disk->fops->owner);
abort_claiming:
if (mode & FMODE_EXCL)
if (holder)
bd_abort_claiming(bdev, holder);
mutex_unlock(&disk->open_mutex);
disk_unblock_events(disk);
@@ -845,10 +851,9 @@ EXPORT_SYMBOL(blkdev_get_by_dev);
* @mode: FMODE_* mask
* @holder: exclusive holder identifier
*
* Open the block device described by the device file at @path. If @mode
* includes %FMODE_EXCL, the block device is opened with exclusive access.
* Specifying %FMODE_EXCL with a %NULL @holder is invalid. Exclusive opens may
* nest for the same @holder.
* Open the block device described by the device file at @path. If @holder is
* not %NULL, the block device is opened with exclusive access. Exclusive opens
* may nest for the same @holder.
*
* CONTEXT:
* Might sleep.
@@ -869,7 +874,7 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
bdev = blkdev_get_by_dev(dev, mode, holder, hops);
if (!IS_ERR(bdev) && (mode & FMODE_WRITE) && bdev_read_only(bdev)) {
blkdev_put(bdev, mode);
blkdev_put(bdev, holder);
return ERR_PTR(-EACCES);
}
@@ -877,7 +882,7 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
}
EXPORT_SYMBOL(blkdev_get_by_path);
void blkdev_put(struct block_device *bdev, fmode_t mode)
void blkdev_put(struct block_device *bdev, void *holder)
{
struct gendisk *disk = bdev->bd_disk;
@@ -892,8 +897,8 @@ void blkdev_put(struct block_device *bdev, fmode_t mode)
sync_blockdev(bdev);
mutex_lock(&disk->open_mutex);
if (mode & FMODE_EXCL)
bd_end_claim(bdev);
if (holder)
bd_end_claim(bdev, holder);
/*
* Trigger event checking and tell drivers to flush MEDIA_CHANGE

View File

@@ -490,7 +490,9 @@ static int blkdev_open(struct inode *inode, struct file *filp)
if ((filp->f_flags & O_ACCMODE) == 3)
filp->f_mode |= FMODE_WRITE_IOCTL;
bdev = blkdev_get_by_dev(inode->i_rdev, filp->f_mode, filp, NULL);
bdev = blkdev_get_by_dev(inode->i_rdev, filp->f_mode,
(filp->f_mode & FMODE_EXCL) ? filp : NULL,
NULL);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
@@ -504,7 +506,7 @@ static int blkdev_release(struct inode *inode, struct file *filp)
{
struct block_device *bdev = filp->private_data;
blkdev_put(bdev, filp->f_mode);
blkdev_put(bdev, (filp->f_mode & FMODE_EXCL) ? filp : NULL);
return 0;
}

View File

@@ -365,12 +365,11 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
}
set_bit(GD_NEED_PART_SCAN, &disk->state);
bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~FMODE_EXCL, NULL,
NULL);
bdev = blkdev_get_by_dev(disk_devt(disk), mode, NULL, NULL);
if (IS_ERR(bdev))
ret = PTR_ERR(bdev);
else
blkdev_put(bdev, mode & ~FMODE_EXCL);
blkdev_put(bdev, NULL);
/*
* If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set,

View File

@@ -454,11 +454,10 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
if (mode & FMODE_EXCL)
return set_blocksize(bdev, n);
if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode | FMODE_EXCL, &bdev,
NULL)))
if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode, &bdev, NULL)))
return -EBUSY;
ret = set_blocksize(bdev, n);
blkdev_put(bdev, mode | FMODE_EXCL);
blkdev_put(bdev, &bdev);
return ret;
}