mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 16:53:20 -04:00
block: split bdev_yield_claim() out of bdev_fput()
bdev_fput() yields the holder claim and then closes the file, which is a deferred operation. Split the yield half into bdev_yield_claim() so a caller can give up the holder while the file - and therefore the block device - is still open, act on the device, and only then bdev_fput(). A filesystem that made a device unfreezable for a membership change with bdev_deny_freeze() undoes the deny on release with bdev_yield_claim(bdev_file); bdev_allow_freeze(file_bdev(bdev_file)); bdev_fput(bdev_file); Re-allowing only after the holder is yielded avoids stranding the filesystem on a racing freeze, and doing it while the file is still open avoids touching the block device after bdev_fput(). bdev_fput() yields again, which is a no-op once the claim has already been given up. Link: https://patch.msgid.link/20260616-work-super-freeze_deny_upstream-v2-2-b3567c7f994b@kernel.org Reviewed-by: Jan Kara <jack@suse.cz> Reviewd-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
50
block/bdev.c
50
block/bdev.c
@@ -1195,6 +1195,39 @@ void bdev_release(struct file *bdev_file)
|
||||
blkdev_put_no_open(bdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* bdev_yield_claim - give up the holder claim on an open block device
|
||||
* @bdev_file: open block device
|
||||
*
|
||||
* Yield the holder and any write access for @bdev_file without closing it, so
|
||||
* the caller can still act on the device - e.g. bdev_allow_freeze() it - before
|
||||
* the final bdev_fput(). bdev_fput() yields too, so calling it afterwards is
|
||||
* safe.
|
||||
*/
|
||||
void bdev_yield_claim(struct file *bdev_file)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
struct gendisk *disk;
|
||||
|
||||
if (!bdev_file->private_data)
|
||||
return;
|
||||
|
||||
bdev = file_bdev(bdev_file);
|
||||
disk = bdev->bd_disk;
|
||||
|
||||
mutex_lock(&disk->open_mutex);
|
||||
bdev_yield_write_access(bdev_file);
|
||||
bd_yield_claim(bdev_file);
|
||||
/*
|
||||
* Tell release we already gave up our hold on the
|
||||
* device and if write restrictions are available that
|
||||
* we already gave up write access to the device.
|
||||
*/
|
||||
bdev_file->private_data = BDEV_I(bdev_file->f_mapping->host);
|
||||
mutex_unlock(&disk->open_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bdev_yield_claim);
|
||||
|
||||
/**
|
||||
* bdev_fput - yield claim to the block device and put the file
|
||||
* @bdev_file: open block device
|
||||
@@ -1208,22 +1241,7 @@ void bdev_fput(struct file *bdev_file)
|
||||
if (WARN_ON_ONCE(bdev_file->f_op != &def_blk_fops))
|
||||
return;
|
||||
|
||||
if (bdev_file->private_data) {
|
||||
struct block_device *bdev = file_bdev(bdev_file);
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
|
||||
mutex_lock(&disk->open_mutex);
|
||||
bdev_yield_write_access(bdev_file);
|
||||
bd_yield_claim(bdev_file);
|
||||
/*
|
||||
* Tell release we already gave up our hold on the
|
||||
* device and if write restrictions are available that
|
||||
* we already gave up write access to the device.
|
||||
*/
|
||||
bdev_file->private_data = BDEV_I(bdev_file->f_mapping->host);
|
||||
mutex_unlock(&disk->open_mutex);
|
||||
}
|
||||
|
||||
bdev_yield_claim(bdev_file);
|
||||
fput(bdev_file);
|
||||
}
|
||||
EXPORT_SYMBOL(bdev_fput);
|
||||
|
||||
@@ -1840,6 +1840,7 @@ int bdev_thaw(struct block_device *bdev);
|
||||
int bdev_deny_freeze(struct block_device *bdev);
|
||||
void bdev_allow_freeze(struct block_device *bdev);
|
||||
void bdev_fput(struct file *bdev_file);
|
||||
void bdev_yield_claim(struct file *bdev_file);
|
||||
|
||||
struct io_comp_batch {
|
||||
struct rq_list req_list;
|
||||
|
||||
Reference in New Issue
Block a user