]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs,block: get holder during claim
authorChristian Brauner <brauner@kernel.org>
Thu, 14 Mar 2024 14:24:13 +0000 (15:24 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 18 Mar 2024 09:32:44 +0000 (10:32 +0100)
Now that we open block devices as files we need to deal with the
realities that closing is a deferred operation. An operation on the
block device such as e.g., freeze, thaw, or removal that runs
concurrently with umount, tries to acquire a stable reference on the
holder. The holder might already be gone though. Make that reliable by
grabbing a passive reference to the holder during bdev_open() and
releasing it during bdev_release().

Fixes: f3a608827d1f ("bdev: open block device as files") # mainline only
Reported-by: Christoph Hellwig <hch@infradead.org>
Link: https://lore.kernel.org/r/ZfEQQ9jZZVes0WCZ@infradead.org
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@infradead.org>
Tested-by: Yi Zhang <yi.zhang@redhat.com>
Reported-by: https://lore.kernel.org/r/CAHj4cs8tbDwKRwfS1=DmooP73ysM__xAb2PQc6XsAmWR+VuYmg@mail.gmail.com
Link: https://lore.kernel.org/r/20240315-freibad-annehmbar-ca68c375af91@brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
block/bdev.c
fs/super.c
include/linux/blkdev.h

index e7adaaf1c21927a71d93e64817e22732fc72f2a3..7a5f611c3d2e3e83eb00be12b9131f49d8348f5e 100644 (file)
@@ -583,6 +583,9 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder,
        mutex_unlock(&bdev->bd_holder_lock);
        bd_clear_claiming(whole, holder);
        mutex_unlock(&bdev_lock);
+
+       if (hops && hops->get_holder)
+               hops->get_holder(holder);
 }
 
 /**
@@ -605,6 +608,7 @@ EXPORT_SYMBOL(bd_abort_claiming);
 static void bd_end_claim(struct block_device *bdev, void *holder)
 {
        struct block_device *whole = bdev_whole(bdev);
+       const struct blk_holder_ops *hops = bdev->bd_holder_ops;
        bool unblock = false;
 
        /*
@@ -627,6 +631,9 @@ static void bd_end_claim(struct block_device *bdev, void *holder)
                whole->bd_holder = NULL;
        mutex_unlock(&bdev_lock);
 
+       if (hops && hops->put_holder)
+               hops->put_holder(holder);
+
        /*
         * If this was the last claim, remove holder link and unblock evpoll if
         * it was a write holder.
index ee05ab6b37e769a16a3b1e40cd820c17e0b76d85..71d9779c42b10aca8bd4e0b7b667fc62386e2305 100644 (file)
@@ -1515,11 +1515,29 @@ static int fs_bdev_thaw(struct block_device *bdev)
        return error;
 }
 
+static void fs_bdev_super_get(void *data)
+{
+       struct super_block *sb = data;
+
+       spin_lock(&sb_lock);
+       sb->s_count++;
+       spin_unlock(&sb_lock);
+}
+
+static void fs_bdev_super_put(void *data)
+{
+       struct super_block *sb = data;
+
+       put_super(sb);
+}
+
 const struct blk_holder_ops fs_holder_ops = {
        .mark_dead              = fs_bdev_mark_dead,
        .sync                   = fs_bdev_sync,
        .freeze                 = fs_bdev_freeze,
        .thaw                   = fs_bdev_thaw,
+       .get_holder             = fs_bdev_super_get,
+       .put_holder             = fs_bdev_super_put,
 };
 EXPORT_SYMBOL_GPL(fs_holder_ops);
 
index f9b87c39cab0478aac030e50174dd5b3fd7c8f16..c3e8f7cf96be9e1c10169d2e7afe31696082eb8f 100644 (file)
@@ -1505,6 +1505,16 @@ struct blk_holder_ops {
         * Thaw the file system mounted on the block device.
         */
        int (*thaw)(struct block_device *bdev);
+
+       /*
+        * If needed, get a reference to the holder.
+        */
+       void (*get_holder)(void *holder);
+
+       /*
+        * Release the holder.
+        */
+       void (*put_holder)(void *holder);
 };
 
 /*