Skip to content

Commit 4e3b9ce

Browse files
committed
Merge tag 'for-5.9-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "Two more fixes. One is for a lockdep warning/lockup (also caught by syzbot), that one has been seen in practice. Regarding the other syzbot reports mentioned last time, they don't seem to be urgent and reliably reproducible so they'll be fixed later. The second fix is for a potential corruption when device replace finishes and the in-memory state of trim is not copied to the new device" * tag 'for-5.9-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix filesystem corruption after a device replace btrfs: move btrfs_rm_dev_replace_free_srcdev outside of all locks btrfs: move btrfs_scratch_superblocks into btrfs_dev_replace_finishing
2 parents c513091 + 4c8f353 commit 4e3b9ce

File tree

3 files changed

+52
-10
lines changed

3 files changed

+52
-10
lines changed

fs/btrfs/dev-replace.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,37 @@ static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info)
599599
wake_up(&fs_info->dev_replace.replace_wait);
600600
}
601601

602+
/*
603+
* When finishing the device replace, before swapping the source device with the
604+
* target device we must update the chunk allocation state in the target device,
605+
* as it is empty because replace works by directly copying the chunks and not
606+
* through the normal chunk allocation path.
607+
*/
608+
static int btrfs_set_target_alloc_state(struct btrfs_device *srcdev,
609+
struct btrfs_device *tgtdev)
610+
{
611+
struct extent_state *cached_state = NULL;
612+
u64 start = 0;
613+
u64 found_start;
614+
u64 found_end;
615+
int ret = 0;
616+
617+
lockdep_assert_held(&srcdev->fs_info->chunk_mutex);
618+
619+
while (!find_first_extent_bit(&srcdev->alloc_state, start,
620+
&found_start, &found_end,
621+
CHUNK_ALLOCATED, &cached_state)) {
622+
ret = set_extent_bits(&tgtdev->alloc_state, found_start,
623+
found_end, CHUNK_ALLOCATED);
624+
if (ret)
625+
break;
626+
start = found_end + 1;
627+
}
628+
629+
free_extent_state(cached_state);
630+
return ret;
631+
}
632+
602633
static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
603634
int scrub_ret)
604635
{
@@ -673,8 +704,14 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
673704
dev_replace->time_stopped = ktime_get_real_seconds();
674705
dev_replace->item_needs_writeback = 1;
675706

676-
/* replace old device with new one in mapping tree */
707+
/*
708+
* Update allocation state in the new device and replace the old device
709+
* with the new one in the mapping tree.
710+
*/
677711
if (!scrub_ret) {
712+
scrub_ret = btrfs_set_target_alloc_state(src_device, tgt_device);
713+
if (scrub_ret)
714+
goto error;
678715
btrfs_dev_replace_update_device_in_mapping_tree(fs_info,
679716
src_device,
680717
tgt_device);
@@ -685,6 +722,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
685722
btrfs_dev_name(src_device),
686723
src_device->devid,
687724
rcu_str_deref(tgt_device->name), scrub_ret);
725+
error:
688726
up_write(&dev_replace->rwsem);
689727
mutex_unlock(&fs_info->chunk_mutex);
690728
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
@@ -745,7 +783,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
745783
/* replace the sysfs entry */
746784
btrfs_sysfs_remove_devices_dir(fs_info->fs_devices, src_device);
747785
btrfs_sysfs_update_devid(tgt_device);
748-
btrfs_rm_dev_replace_free_srcdev(src_device);
786+
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &src_device->dev_state))
787+
btrfs_scratch_superblocks(fs_info, src_device->bdev,
788+
src_device->name->str);
749789

750790
/* write back the superblocks */
751791
trans = btrfs_start_transaction(root, 0);
@@ -754,6 +794,8 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
754794

755795
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
756796

797+
btrfs_rm_dev_replace_free_srcdev(src_device);
798+
757799
return 0;
758800
}
759801

fs/btrfs/volumes.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,9 +1999,9 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
19991999
return num_devices;
20002000
}
20012001

2002-
static void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
2003-
struct block_device *bdev,
2004-
const char *device_path)
2002+
void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
2003+
struct block_device *bdev,
2004+
const char *device_path)
20052005
{
20062006
struct btrfs_super_block *disk_super;
20072007
int copy_num;
@@ -2224,11 +2224,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
22242224
struct btrfs_fs_info *fs_info = srcdev->fs_info;
22252225
struct btrfs_fs_devices *fs_devices = srcdev->fs_devices;
22262226

2227-
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &srcdev->dev_state)) {
2228-
/* zero out the old super if it is writable */
2229-
btrfs_scratch_superblocks(fs_info, srcdev->bdev,
2230-
srcdev->name->str);
2231-
}
2227+
mutex_lock(&uuid_mutex);
22322228

22332229
btrfs_close_bdev(srcdev);
22342230
synchronize_rcu();
@@ -2258,6 +2254,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
22582254
close_fs_devices(fs_devices);
22592255
free_fs_devices(fs_devices);
22602256
}
2257+
mutex_unlock(&uuid_mutex);
22612258
}
22622259

22632260
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)

fs/btrfs/volumes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
573573
void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
574574
bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
575575
struct btrfs_device *failing_dev);
576+
void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
577+
struct block_device *bdev,
578+
const char *device_path);
576579

577580
int btrfs_bg_type_to_factor(u64 flags);
578581
const char *btrfs_bg_type_to_raid_name(u64 flags);

0 commit comments

Comments
 (0)