summaryrefslogtreecommitdiff
path: root/block/bdev.c
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-06-16 13:58:15 +0200
committerChristian Brauner <brauner@kernel.org>2026-06-29 10:31:49 +0200
commit822d87bc520fee8d95448c0aa3c728a4c1a595af (patch)
tree580647067f343da2de95e698d161b83853481eb8 /block/bdev.c
parentea4e4cc263011910eb7c62f3bb4fa094a1573c61 (diff)
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>
Diffstat (limited to 'block/bdev.c')
-rw-r--r--block/bdev.c50
1 files changed, 34 insertions, 16 deletions
diff --git a/block/bdev.c b/block/bdev.c
index 9b73487a91ca..28b0d40c362f 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1196,6 +1196,39 @@ put_no_open:
}
/**
+ * 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);