From: Qu Wenruo Date: Mon, 14 Jul 2025 05:25:57 +0000 (+0930) Subject: fs: add a new remove_bdev() callback X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d9c37a4904ec21ef7d45880fe023c11341869c28;p=thirdparty%2Flinux.git fs: add a new remove_bdev() callback 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 Link: https://lore.kernel.org/09909fcff7f2763cc037fec97ac2482bdc0a12cb.1752470276.git.wqu@suse.com Reviewed-by: Jan Kara Signed-off-by: Christian Brauner --- diff --git a/fs/super.c b/fs/super.c index 21799e213fd74..53e135d84867e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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); diff --git a/include/linux/fs.h b/include/linux/fs.h index 96c7925a65519..5150db41109a9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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); };