On Mon, Jul 14, 2025 at 02:56:02PM +0930, Qu Wenruo wrote: > For the ->remove_bdev() callback, btrfs will: > > - Mark the target device as missing > > - Go degraded if the fs can afford it > > - Return error other wise > Thus falls back to the shutdown callback > > For the ->shutdown callback, btrfs will: > > - Set the SHUTDOWN flag > Which will reject all new incoming operations, and make all writeback > to fail. > > The behavior is the same as the NOLOGFLUSH behavior. > > To support the lookup from bdev to a btrfs_device, > btrfs_dev_lookup_args is enhanced to have a new @devt member. > If set, we should be able to use that @devt member to uniquely locating a > btrfs device. > > I know the shutdown can be a little overkilled, if one has a RAID1 > metadata and RAID0 data, in that case one can still read data with 50% > chance to got some good data. > > But a filesystem returning -EIO for half of the time is not really > considered usable. > Further it can also be as bad as the only device went missing for a single > device btrfs. > > So here we go safe other than sorry when handling missing device. > > And the remove_bdev callback will be hidden behind experimental features > for now, the reasons are: > > - There are not enough btrfs specific bdev removal test cases > The existing test cases are all removing the only device, thus only > exercises the ->shutdown() behavior. > > - Not yet determined what's the expected behavior > Although the current auto-degrade behavior is no worse than the old > behavior, it may not always be what the end users want. > > Before there is a concrete interface, better hide the new feature > from end users. > > Signed-off-by: Qu Wenruo <wqu@xxxxxxxx> > --- > fs/btrfs/super.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ > fs/btrfs/volumes.c | 2 ++ > fs/btrfs/volumes.h | 5 ++++ > 3 files changed, 73 insertions(+) > > diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c > index 466d0450269c..79f6ad1d44de 100644 > --- a/fs/btrfs/super.c > +++ b/fs/btrfs/super.c > @@ -2413,6 +2413,68 @@ static long btrfs_free_cached_objects(struct super_block *sb, struct shrink_cont > return 0; > } > > +#ifdef CONFIG_BTRFS_EXPERIMENTAL > +static int btrfs_remove_bdev(struct super_block *sb, struct block_device *bdev) > +{ > + struct btrfs_fs_info *fs_info = btrfs_sb(sb); > + struct btrfs_device *device; > + struct btrfs_dev_lookup_args lookup_args = { .devt = bdev->bd_dev }; > + bool can_rw; > + > + mutex_lock(&fs_info->fs_devices->device_list_mutex); > + device = btrfs_find_device(fs_info->fs_devices, &lookup_args); > + if (!device) { > + mutex_unlock(&fs_info->fs_devices->device_list_mutex); > + /* Device not found, should not affect the running fs, just give a warning. */ > + btrfs_warn(fs_info, "unable to find btrfs device for block device '%pg'", > + bdev); > + return 0; > + } I got very confused when reviewing this questioning myself how this is going to work... until I pulled btrfs/for-next. It would've been good to know that you merged patches to do bdev_file_open_by_*() calls with the superblock as owner and fs_holder_ops set. Very good to see this! Thanks everyone! So I can now go delete the whole paragraph I had about that. :)