]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
block: split bdev_yield_claim() out of bdev_fput()
authorChristian Brauner <brauner@kernel.org>
Tue, 16 Jun 2026 11:58:15 +0000 (13:58 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 29 Jun 2026 08:31:49 +0000 (10:31 +0200)
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>
block/bdev.c
include/linux/blkdev.h

index 9b73487a91cab0b1cb55554c1f91c701edac8511..28b0d40c362fe8aa00e650cfb412591318453b16 100644 (file)
@@ -1195,6 +1195,39 @@ put_no_open:
        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);
index c419117be083a639d6f02323e346b0cf748ce9cc..f4e5eca5a91ff08e9572a9c0f5ba83b646397b00 100644 (file)
@@ -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;