]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs: add a new remove_bdev() callback
authorQu Wenruo <wqu@suse.com>
Mon, 14 Jul 2025 05:25:57 +0000 (14:55 +0930)
committerChristian Brauner <brauner@kernel.org>
Tue, 15 Jul 2025 11:36:40 +0000 (13:36 +0200)
Currently all filesystems which implement super_operations::shutdown()
can not afford losing a device.

Thus fs_bdev_mark_dead() will just call the ->shutdown() callback for the
involved filesystem.

But it will no longer be the case, as multi-device filesystems like
btrfs and bcachefs can handle certain device loss without the need to
shutdown the whole filesystem.

To allow those multi-device filesystems to be integrated to use
fs_holder_ops:

- Add a new super_operations::remove_bdev() callback

- Try ->remove_bdev() callback first inside fs_bdev_mark_dead()
  If the callback returned 0, meaning the fs can handling the device
  loss, then exit without doing anything else.

  If there is no such callback or the callback returned non-zero value,
  continue to shutdown the filesystem as usual.

This means the new remove_bdev() should only do the check on whether the
operation can continue, and if so do the fs specific handlings.
The shutdown handling should still be handled by the existing
->shutdown() callback.

For all existing filesystems with shutdown callback, there is no change
to the code nor behavior.

Btrfs is going to implement both the ->remove_bdev() and ->shutdown()
callbacks soon.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Link: https://lore.kernel.org/09909fcff7f2763cc037fec97ac2482bdc0a12cb.1752470276.git.wqu@suse.com
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/super.c
include/linux/fs.h

index 21799e213fd74709eb334b799b1be81613eeaa7f..53e135d84867e10fbf10b6c55fd28c55b049c11e 100644 (file)
@@ -1457,6 +1457,17 @@ static void fs_bdev_mark_dead(struct block_device *bdev, bool surprise)
        if (!sb)
                return;
 
+       if (sb->s_op->remove_bdev) {
+               int ret;
+
+               ret = sb->s_op->remove_bdev(sb, bdev);
+               if (!ret) {
+                       super_unlock_shared(sb);
+                       return;
+               }
+               /* Fallback to shutdown. */
+       }
+
        if (!surprise)
                sync_filesystem(sb);
        shrink_dcache_sb(sb);
index 96c7925a655199ebdfefafa587ea5ae3e3665867..5150db41109a94160d0d99cef5880b3f519fbd95 100644 (file)
@@ -2363,6 +2363,15 @@ struct super_operations {
                                  struct shrink_control *);
        long (*free_cached_objects)(struct super_block *,
                                    struct shrink_control *);
+       /*
+        * If a filesystem can support graceful removal of a device and
+        * continue read-write operations, implement this callback.
+        *
+        * Return 0 if the filesystem can continue read-write.
+        * Non-zero return value or no such callback means the fs will be shutdown
+        * as usual.
+        */
+       int (*remove_bdev)(struct super_block *sb, struct block_device *bdev);
        void (*shutdown)(struct super_block *sb);
 };