Commit 2736e8ee authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Acked-by: default avatarChristian 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: default avatarJens Axboe <axboe@kernel.dk>
parent 2ef78928
Loading
Loading
Loading
Loading
+21 −16
Original line number Diff line number Diff line
@@ -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
+4 −2
Original line number Diff line number Diff line
@@ -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;
}

+2 −3
Original line number Diff line number Diff line
@@ -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,
+2 −3
Original line number Diff line number Diff line
@@ -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;
}
+14 −9
Original line number Diff line number Diff line
@@ -1640,8 +1640,7 @@ static struct block_device *open_backing_dev(struct drbd_device *device,
	struct block_device *bdev;
	int err = 0;

	bdev = blkdev_get_by_path(bdev_path,
				  FMODE_READ | FMODE_WRITE | FMODE_EXCL,
	bdev = blkdev_get_by_path(bdev_path, FMODE_READ | FMODE_WRITE,
				  claim_ptr, NULL);
	if (IS_ERR(bdev)) {
		drbd_err(device, "open(\"%s\") failed with %ld\n",
@@ -1654,7 +1653,7 @@ static struct block_device *open_backing_dev(struct drbd_device *device,

	err = bd_link_disk_holder(bdev, device->vdisk);
	if (err) {
		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
		blkdev_put(bdev, claim_ptr);
		drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n",
				bdev_path, err);
		bdev = ERR_PTR(err);
@@ -1696,13 +1695,13 @@ static int open_backing_devices(struct drbd_device *device,
}

static void close_backing_dev(struct drbd_device *device, struct block_device *bdev,
	bool do_bd_unlink)
		void *claim_ptr, bool do_bd_unlink)
{
	if (!bdev)
		return;
	if (do_bd_unlink)
		bd_unlink_disk_holder(bdev, device->vdisk);
	blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
	blkdev_put(bdev, claim_ptr);
}

void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev)
@@ -1710,8 +1709,11 @@ void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *
	if (ldev == NULL)
		return;

	close_backing_dev(device, ldev->md_bdev, ldev->md_bdev != ldev->backing_bdev);
	close_backing_dev(device, ldev->backing_bdev, true);
	close_backing_dev(device, ldev->md_bdev,
			  ldev->md.meta_dev_idx < 0 ?
				(void *)device : (void *)drbd_m_holder,
			  ldev->md_bdev != ldev->backing_bdev);
	close_backing_dev(device, ldev->backing_bdev, device, true);

	kfree(ldev->disk_conf);
	kfree(ldev);
@@ -2127,8 +2129,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
 fail:
	conn_reconfig_done(connection);
	if (nbc) {
		close_backing_dev(device, nbc->md_bdev, nbc->md_bdev != nbc->backing_bdev);
		close_backing_dev(device, nbc->backing_bdev, true);
		close_backing_dev(device, nbc->md_bdev,
			  nbc->disk_conf->meta_dev_idx < 0 ?
				(void *)device : (void *)drbd_m_holder,
			  nbc->md_bdev != nbc->backing_bdev);
		close_backing_dev(device, nbc->backing_bdev, device, true);
		kfree(nbc);
	}
	kfree(new_disk_conf);
Loading