From c5968304fe744399e52373c7e19dd5b2a11c4696 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Oct 2022 19:38:34 +0200 Subject: [PATCH] drop btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch --- ...rblock-to-ensure-the-fs-was-not-modi.patch | 254 ------------------ queue-5.10/series | 1 - ...rblock-to-ensure-the-fs-was-not-modi.patch | 254 ------------------ queue-5.15/series | 1 - ...rblock-to-ensure-the-fs-was-not-modi.patch | 254 ------------------ queue-5.19/series | 1 - ...rblock-to-ensure-the-fs-was-not-modi.patch | 254 ------------------ queue-6.0/series | 1 - 8 files changed, 1020 deletions(-) delete mode 100644 queue-5.10/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch delete mode 100644 queue-5.15/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch delete mode 100644 queue-5.19/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch delete mode 100644 queue-6.0/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch diff --git a/queue-5.10/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch b/queue-5.10/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch deleted file mode 100644 index f75024f9118..00000000000 --- a/queue-5.10/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch +++ /dev/null @@ -1,254 +0,0 @@ -From c51682ccc8cdebf7af7fa6f95508f6e3f87ab104 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 24 Aug 2022 20:16:22 +0800 -Subject: btrfs: check superblock to ensure the fs was not modified at thaw - time - -From: Qu Wenruo - -[ Upstream commit a05d3c9153145283ce9c58a1d7a9056fbb85f6a1 ] - -[BACKGROUND] -There is an incident report that, one user hibernated the system, with -one btrfs on removable device still mounted. - -Then by some incident, the btrfs got mounted and modified by another -system/OS, then back to the hibernated system. - -After resuming from the hibernation, new write happened into the victim btrfs. - -Now the fs is completely broken, since the underlying btrfs is no longer -the same one before the hibernation, and the user lost their data due to -various transid mismatch. - -[REPRODUCER] -We can emulate the situation using the following small script: - - truncate -s 1G $dev - mkfs.btrfs -f $dev - mount $dev $mnt - fsstress -w -d $mnt -n 500 - sync - xfs_freeze -f $mnt - cp $dev $dev.backup - - # There is no way to mount the same cloned fs on the same system, - # as the conflicting fsid will be rejected by btrfs. - # Thus here we have to wipe the fs using a different btrfs. - mkfs.btrfs -f $dev.backup - - dd if=$dev.backup of=$dev bs=1M - xfs_freeze -u $mnt - fsstress -w -d $mnt -n 20 - umount $mnt - btrfs check $dev - -The final fsck will fail due to some tree blocks has incorrect fsid. - -This is enough to emulate the problem hit by the unfortunate user. - -[ENHANCEMENT] -Although such case should not be that common, it can still happen from -time to time. - -From the view of btrfs, we can detect any unexpected super block change, -and if there is any unexpected change, we just mark the fs read-only, -and thaw the fs. - -By this we can limit the damage to minimal, and I hope no one would lose -their data by this anymore. - -Suggested-by: Goffredo Baroncelli -Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/ -Reviewed-by: Anand Jain -Signed-off-by: Qu Wenruo -Signed-off-by: David Sterba -Signed-off-by: Sasha Levin ---- - fs/btrfs/disk-io.c | 25 ++++++++++++++----- - fs/btrfs/disk-io.h | 4 +++- - fs/btrfs/super.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ - fs/btrfs/volumes.c | 2 +- - 4 files changed, 83 insertions(+), 8 deletions(-) - -diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c -index f2abd8bfd4a0..8af0d722ab9a 100644 ---- a/fs/btrfs/disk-io.c -+++ b/fs/btrfs/disk-io.c -@@ -2400,8 +2400,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) - * 1, 2 2nd and 3rd backup copy - * -1 skip bytenr check - */ --static int validate_super(struct btrfs_fs_info *fs_info, -- struct btrfs_super_block *sb, int mirror_num) -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num) - { - u64 nodesize = btrfs_super_nodesize(sb); - u64 sectorsize = btrfs_super_sectorsize(sb); -@@ -2576,7 +2576,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, - */ - static int btrfs_validate_mount_super(struct btrfs_fs_info *fs_info) - { -- return validate_super(fs_info, fs_info->super_copy, 0); -+ return btrfs_validate_super(fs_info, fs_info->super_copy, 0); - } - - /* -@@ -2590,7 +2590,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info, - { - int ret; - -- ret = validate_super(fs_info, sb, -1); -+ ret = btrfs_validate_super(fs_info, sb, -1); - if (ret < 0) - goto out; - if (!btrfs_supported_super_csum(btrfs_super_csum_type(sb))) { -@@ -3500,7 +3500,7 @@ static void btrfs_end_super_write(struct bio *bio) - } - - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num) -+ int copy_num, bool drop_cache) - { - struct btrfs_super_block *super; - struct page *page; -@@ -3511,6 +3511,19 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, - if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode)) - return ERR_PTR(-EINVAL); - -+ if (drop_cache) { -+ /* This should only be called with the primary sb. */ -+ ASSERT(copy_num == 0); -+ -+ /* -+ * Drop the page of the primary superblock, so later read will -+ * always read from the device. -+ */ -+ invalidate_inode_pages2_range(mapping, -+ bytenr >> PAGE_SHIFT, -+ (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); -+ } -+ - page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS); - if (IS_ERR(page)) - return ERR_CAST(page); -@@ -3542,7 +3555,7 @@ struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev) - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - for (i = 0; i < 1; i++) { -- super = btrfs_read_dev_one_super(bdev, i); -+ super = btrfs_read_dev_one_super(bdev, i, false); - if (IS_ERR(super)) - continue; - -diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h -index 182540bdcea0..a1bcd388dfec 100644 ---- a/fs/btrfs/disk-io.h -+++ b/fs/btrfs/disk-io.h -@@ -54,10 +54,12 @@ int __cold open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); - void __cold close_ctree(struct btrfs_fs_info *fs_info); -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num); - int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors); - struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev); - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num); -+ int copy_num, bool drop_cache); - int btrfs_commit_super(struct btrfs_fs_info *fs_info); - struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, - struct btrfs_key *key); -diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c -index 8bf8cdb62a3a..97b06c24e443 100644 ---- a/fs/btrfs/super.c -+++ b/fs/btrfs/super.c -@@ -2400,11 +2400,71 @@ static int btrfs_freeze(struct super_block *sb) - return btrfs_commit_transaction(trans); - } - -+static int check_dev_super(struct btrfs_device *dev) -+{ -+ struct btrfs_fs_info *fs_info = dev->fs_info; -+ struct btrfs_super_block *sb; -+ int ret = 0; -+ -+ /* This should be called with fs still frozen. */ -+ ASSERT(test_bit(BTRFS_FS_FROZEN, &fs_info->flags)); -+ -+ /* Missing dev, no need to check. */ -+ if (!dev->bdev) -+ return 0; -+ -+ /* Only need to check the primary super block. */ -+ sb = btrfs_read_dev_one_super(dev->bdev, 0, true); -+ if (IS_ERR(sb)) -+ return PTR_ERR(sb); -+ -+ /* Btrfs_validate_super() includes fsid check against super->fsid. */ -+ ret = btrfs_validate_super(fs_info, sb, 0); -+ if (ret < 0) -+ goto out; -+ -+ if (btrfs_super_generation(sb) != fs_info->last_trans_committed) { -+ btrfs_err(fs_info, "transid mismatch, has %llu expect %llu", -+ btrfs_super_generation(sb), -+ fs_info->last_trans_committed); -+ ret = -EUCLEAN; -+ goto out; -+ } -+out: -+ btrfs_release_disk_super(sb); -+ return ret; -+} -+ - static int btrfs_unfreeze(struct super_block *sb) - { - struct btrfs_fs_info *fs_info = btrfs_sb(sb); -+ struct btrfs_device *device; -+ int ret = 0; - -+ /* -+ * Make sure the fs is not changed by accident (like hibernation then -+ * modified by other OS). -+ * If we found anything wrong, we mark the fs error immediately. -+ * -+ * And since the fs is frozen, no one can modify the fs yet, thus -+ * we don't need to hold device_list_mutex. -+ */ -+ list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { -+ ret = check_dev_super(device); -+ if (ret < 0) { -+ btrfs_handle_fs_error(fs_info, ret, -+ "super block on devid %llu got modified unexpectedly", -+ device->devid); -+ break; -+ } -+ } - clear_bit(BTRFS_FS_FROZEN, &fs_info->flags); -+ -+ /* -+ * We still return 0, to allow VFS layer to unfreeze the fs even the -+ * above checks failed. Since the fs is either fine or read-only, we're -+ * safe to continue, without causing further damage. -+ */ - return 0; - } - -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c -index d4d89e0738ff..e14bd23cc75c 100644 ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -2069,7 +2069,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info, - struct page *page; - int ret; - -- disk_super = btrfs_read_dev_one_super(bdev, copy_num); -+ disk_super = btrfs_read_dev_one_super(bdev, copy_num, false); - if (IS_ERR(disk_super)) - continue; - --- -2.35.1 - diff --git a/queue-5.10/series b/queue-5.10/series index 5bbd91a317c..097508078fd 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -403,7 +403,6 @@ kselftest-arm64-fix-validatation-termination-record-.patch arm64-dts-imx8mq-librem5-add-bq25895-as-max17055-s-p.patch arm-orion-fix-include-path.patch btrfs-scrub-try-to-fix-super-block-errors.patch -btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch arm64-dts-uniphier-add-usb-device-support-for-pxs3-r.patch selftests-cpu-hotplug-use-return-instead-of-exit.patch clk-zynqmp-fix-stack-out-of-bounds-in-strncpy.patch diff --git a/queue-5.15/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch b/queue-5.15/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch deleted file mode 100644 index aede6a7e5f3..00000000000 --- a/queue-5.15/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch +++ /dev/null @@ -1,254 +0,0 @@ -From d490034decc9adb54e82e9804e5dfac7bb746315 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 24 Aug 2022 20:16:22 +0800 -Subject: btrfs: check superblock to ensure the fs was not modified at thaw - time - -From: Qu Wenruo - -[ Upstream commit a05d3c9153145283ce9c58a1d7a9056fbb85f6a1 ] - -[BACKGROUND] -There is an incident report that, one user hibernated the system, with -one btrfs on removable device still mounted. - -Then by some incident, the btrfs got mounted and modified by another -system/OS, then back to the hibernated system. - -After resuming from the hibernation, new write happened into the victim btrfs. - -Now the fs is completely broken, since the underlying btrfs is no longer -the same one before the hibernation, and the user lost their data due to -various transid mismatch. - -[REPRODUCER] -We can emulate the situation using the following small script: - - truncate -s 1G $dev - mkfs.btrfs -f $dev - mount $dev $mnt - fsstress -w -d $mnt -n 500 - sync - xfs_freeze -f $mnt - cp $dev $dev.backup - - # There is no way to mount the same cloned fs on the same system, - # as the conflicting fsid will be rejected by btrfs. - # Thus here we have to wipe the fs using a different btrfs. - mkfs.btrfs -f $dev.backup - - dd if=$dev.backup of=$dev bs=1M - xfs_freeze -u $mnt - fsstress -w -d $mnt -n 20 - umount $mnt - btrfs check $dev - -The final fsck will fail due to some tree blocks has incorrect fsid. - -This is enough to emulate the problem hit by the unfortunate user. - -[ENHANCEMENT] -Although such case should not be that common, it can still happen from -time to time. - -From the view of btrfs, we can detect any unexpected super block change, -and if there is any unexpected change, we just mark the fs read-only, -and thaw the fs. - -By this we can limit the damage to minimal, and I hope no one would lose -their data by this anymore. - -Suggested-by: Goffredo Baroncelli -Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/ -Reviewed-by: Anand Jain -Signed-off-by: Qu Wenruo -Signed-off-by: David Sterba -Signed-off-by: Sasha Levin ---- - fs/btrfs/disk-io.c | 25 ++++++++++++++----- - fs/btrfs/disk-io.h | 4 +++- - fs/btrfs/super.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ - fs/btrfs/volumes.c | 2 +- - 4 files changed, 83 insertions(+), 8 deletions(-) - -diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c -index f4015556cafa..c812aff63e1b 100644 ---- a/fs/btrfs/disk-io.c -+++ b/fs/btrfs/disk-io.c -@@ -2489,8 +2489,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) - * 1, 2 2nd and 3rd backup copy - * -1 skip bytenr check - */ --static int validate_super(struct btrfs_fs_info *fs_info, -- struct btrfs_super_block *sb, int mirror_num) -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num) - { - u64 nodesize = btrfs_super_nodesize(sb); - u64 sectorsize = btrfs_super_sectorsize(sb); -@@ -2673,7 +2673,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, - */ - static int btrfs_validate_mount_super(struct btrfs_fs_info *fs_info) - { -- return validate_super(fs_info, fs_info->super_copy, 0); -+ return btrfs_validate_super(fs_info, fs_info->super_copy, 0); - } - - /* -@@ -2687,7 +2687,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info, - { - int ret; - -- ret = validate_super(fs_info, sb, -1); -+ ret = btrfs_validate_super(fs_info, sb, -1); - if (ret < 0) - goto out; - if (!btrfs_supported_super_csum(btrfs_super_csum_type(sb))) { -@@ -3701,7 +3701,7 @@ static void btrfs_end_super_write(struct bio *bio) - } - - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num) -+ int copy_num, bool drop_cache) - { - struct btrfs_super_block *super; - struct page *page; -@@ -3719,6 +3719,19 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, - if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode)) - return ERR_PTR(-EINVAL); - -+ if (drop_cache) { -+ /* This should only be called with the primary sb. */ -+ ASSERT(copy_num == 0); -+ -+ /* -+ * Drop the page of the primary superblock, so later read will -+ * always read from the device. -+ */ -+ invalidate_inode_pages2_range(mapping, -+ bytenr >> PAGE_SHIFT, -+ (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); -+ } -+ - page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS); - if (IS_ERR(page)) - return ERR_CAST(page); -@@ -3750,7 +3763,7 @@ struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev) - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - for (i = 0; i < 1; i++) { -- super = btrfs_read_dev_one_super(bdev, i); -+ super = btrfs_read_dev_one_super(bdev, i, false); - if (IS_ERR(super)) - continue; - -diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h -index 1b8fd3deafc9..9de0c39f63a2 100644 ---- a/fs/btrfs/disk-io.h -+++ b/fs/btrfs/disk-io.h -@@ -56,10 +56,12 @@ int __cold open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); - void __cold close_ctree(struct btrfs_fs_info *fs_info); -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num); - int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors); - struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev); - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num); -+ int copy_num, bool drop_cache); - int btrfs_commit_super(struct btrfs_fs_info *fs_info); - struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, - struct btrfs_key *key); -diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c -index 442fcd1b14a6..135ddfb47b39 100644 ---- a/fs/btrfs/super.c -+++ b/fs/btrfs/super.c -@@ -2488,11 +2488,71 @@ static int btrfs_freeze(struct super_block *sb) - return btrfs_commit_transaction(trans); - } - -+static int check_dev_super(struct btrfs_device *dev) -+{ -+ struct btrfs_fs_info *fs_info = dev->fs_info; -+ struct btrfs_super_block *sb; -+ int ret = 0; -+ -+ /* This should be called with fs still frozen. */ -+ ASSERT(test_bit(BTRFS_FS_FROZEN, &fs_info->flags)); -+ -+ /* Missing dev, no need to check. */ -+ if (!dev->bdev) -+ return 0; -+ -+ /* Only need to check the primary super block. */ -+ sb = btrfs_read_dev_one_super(dev->bdev, 0, true); -+ if (IS_ERR(sb)) -+ return PTR_ERR(sb); -+ -+ /* Btrfs_validate_super() includes fsid check against super->fsid. */ -+ ret = btrfs_validate_super(fs_info, sb, 0); -+ if (ret < 0) -+ goto out; -+ -+ if (btrfs_super_generation(sb) != fs_info->last_trans_committed) { -+ btrfs_err(fs_info, "transid mismatch, has %llu expect %llu", -+ btrfs_super_generation(sb), -+ fs_info->last_trans_committed); -+ ret = -EUCLEAN; -+ goto out; -+ } -+out: -+ btrfs_release_disk_super(sb); -+ return ret; -+} -+ - static int btrfs_unfreeze(struct super_block *sb) - { - struct btrfs_fs_info *fs_info = btrfs_sb(sb); -+ struct btrfs_device *device; -+ int ret = 0; - -+ /* -+ * Make sure the fs is not changed by accident (like hibernation then -+ * modified by other OS). -+ * If we found anything wrong, we mark the fs error immediately. -+ * -+ * And since the fs is frozen, no one can modify the fs yet, thus -+ * we don't need to hold device_list_mutex. -+ */ -+ list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { -+ ret = check_dev_super(device); -+ if (ret < 0) { -+ btrfs_handle_fs_error(fs_info, ret, -+ "super block on devid %llu got modified unexpectedly", -+ device->devid); -+ break; -+ } -+ } - clear_bit(BTRFS_FS_FROZEN, &fs_info->flags); -+ -+ /* -+ * We still return 0, to allow VFS layer to unfreeze the fs even the -+ * above checks failed. Since the fs is either fine or read-only, we're -+ * safe to continue, without causing further damage. -+ */ - return 0; - } - -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c -index 0f22d91e2392..82db36019a3d 100644 ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -2074,7 +2074,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info, - struct page *page; - int ret; - -- disk_super = btrfs_read_dev_one_super(bdev, copy_num); -+ disk_super = btrfs_read_dev_one_super(bdev, copy_num, false); - if (IS_ERR(disk_super)) - continue; - --- -2.35.1 - diff --git a/queue-5.15/series b/queue-5.15/series index 36f86719194..7c3cceac4e4 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -540,7 +540,6 @@ btrfs-add-macros-for-annotating-wait-events-with-loc.patch btrfs-change-the-lockdep-class-of-free-space-inode-s.patch btrfs-scrub-try-to-fix-super-block-errors.patch btrfs-don-t-print-information-about-space-cache-or-t.patch -btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch arm64-dts-uniphier-add-usb-device-support-for-pxs3-r.patch arm-9242-1-kasan-only-map-modules-if-config_kasan_vm.patch selftests-cpu-hotplug-use-return-instead-of-exit.patch diff --git a/queue-5.19/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch b/queue-5.19/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch deleted file mode 100644 index a49effaeffd..00000000000 --- a/queue-5.19/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch +++ /dev/null @@ -1,254 +0,0 @@ -From e69472b7611bd51247177446c783392d45302651 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 24 Aug 2022 20:16:22 +0800 -Subject: btrfs: check superblock to ensure the fs was not modified at thaw - time - -From: Qu Wenruo - -[ Upstream commit a05d3c9153145283ce9c58a1d7a9056fbb85f6a1 ] - -[BACKGROUND] -There is an incident report that, one user hibernated the system, with -one btrfs on removable device still mounted. - -Then by some incident, the btrfs got mounted and modified by another -system/OS, then back to the hibernated system. - -After resuming from the hibernation, new write happened into the victim btrfs. - -Now the fs is completely broken, since the underlying btrfs is no longer -the same one before the hibernation, and the user lost their data due to -various transid mismatch. - -[REPRODUCER] -We can emulate the situation using the following small script: - - truncate -s 1G $dev - mkfs.btrfs -f $dev - mount $dev $mnt - fsstress -w -d $mnt -n 500 - sync - xfs_freeze -f $mnt - cp $dev $dev.backup - - # There is no way to mount the same cloned fs on the same system, - # as the conflicting fsid will be rejected by btrfs. - # Thus here we have to wipe the fs using a different btrfs. - mkfs.btrfs -f $dev.backup - - dd if=$dev.backup of=$dev bs=1M - xfs_freeze -u $mnt - fsstress -w -d $mnt -n 20 - umount $mnt - btrfs check $dev - -The final fsck will fail due to some tree blocks has incorrect fsid. - -This is enough to emulate the problem hit by the unfortunate user. - -[ENHANCEMENT] -Although such case should not be that common, it can still happen from -time to time. - -From the view of btrfs, we can detect any unexpected super block change, -and if there is any unexpected change, we just mark the fs read-only, -and thaw the fs. - -By this we can limit the damage to minimal, and I hope no one would lose -their data by this anymore. - -Suggested-by: Goffredo Baroncelli -Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/ -Reviewed-by: Anand Jain -Signed-off-by: Qu Wenruo -Signed-off-by: David Sterba -Signed-off-by: Sasha Levin ---- - fs/btrfs/disk-io.c | 25 ++++++++++++++----- - fs/btrfs/disk-io.h | 4 +++- - fs/btrfs/super.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ - fs/btrfs/volumes.c | 2 +- - 4 files changed, 83 insertions(+), 8 deletions(-) - -diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c -index 20ad619a8a97..218f62fb76a0 100644 ---- a/fs/btrfs/disk-io.c -+++ b/fs/btrfs/disk-io.c -@@ -2705,8 +2705,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) - * 1, 2 2nd and 3rd backup copy - * -1 skip bytenr check - */ --static int validate_super(struct btrfs_fs_info *fs_info, -- struct btrfs_super_block *sb, int mirror_num) -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num) - { - u64 nodesize = btrfs_super_nodesize(sb); - u64 sectorsize = btrfs_super_sectorsize(sb); -@@ -2890,7 +2890,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, - */ - static int btrfs_validate_mount_super(struct btrfs_fs_info *fs_info) - { -- return validate_super(fs_info, fs_info->super_copy, 0); -+ return btrfs_validate_super(fs_info, fs_info->super_copy, 0); - } - - /* -@@ -2904,7 +2904,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info, - { - int ret; - -- ret = validate_super(fs_info, sb, -1); -+ ret = btrfs_validate_super(fs_info, sb, -1); - if (ret < 0) - goto out; - if (!btrfs_supported_super_csum(btrfs_super_csum_type(sb))) { -@@ -3945,7 +3945,7 @@ static void btrfs_end_super_write(struct bio *bio) - } - - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num) -+ int copy_num, bool drop_cache) - { - struct btrfs_super_block *super; - struct page *page; -@@ -3963,6 +3963,19 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, - if (bytenr + BTRFS_SUPER_INFO_SIZE >= bdev_nr_bytes(bdev)) - return ERR_PTR(-EINVAL); - -+ if (drop_cache) { -+ /* This should only be called with the primary sb. */ -+ ASSERT(copy_num == 0); -+ -+ /* -+ * Drop the page of the primary superblock, so later read will -+ * always read from the device. -+ */ -+ invalidate_inode_pages2_range(mapping, -+ bytenr >> PAGE_SHIFT, -+ (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); -+ } -+ - page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS); - if (IS_ERR(page)) - return ERR_CAST(page); -@@ -3994,7 +4007,7 @@ struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev) - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - for (i = 0; i < 1; i++) { -- super = btrfs_read_dev_one_super(bdev, i); -+ super = btrfs_read_dev_one_super(bdev, i, false); - if (IS_ERR(super)) - continue; - -diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h -index b4962b7d7117..ece5a3112b4f 100644 ---- a/fs/btrfs/disk-io.h -+++ b/fs/btrfs/disk-io.h -@@ -53,10 +53,12 @@ int __cold open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); - void __cold close_ctree(struct btrfs_fs_info *fs_info); -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num); - int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors); - struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev); - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num); -+ int copy_num, bool drop_cache); - int btrfs_commit_super(struct btrfs_fs_info *fs_info); - struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, - struct btrfs_key *key); -diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c -index b2a5291e5e4b..80f480b8252c 100644 ---- a/fs/btrfs/super.c -+++ b/fs/btrfs/super.c -@@ -2571,11 +2571,71 @@ static int btrfs_freeze(struct super_block *sb) - return btrfs_commit_transaction(trans); - } - -+static int check_dev_super(struct btrfs_device *dev) -+{ -+ struct btrfs_fs_info *fs_info = dev->fs_info; -+ struct btrfs_super_block *sb; -+ int ret = 0; -+ -+ /* This should be called with fs still frozen. */ -+ ASSERT(test_bit(BTRFS_FS_FROZEN, &fs_info->flags)); -+ -+ /* Missing dev, no need to check. */ -+ if (!dev->bdev) -+ return 0; -+ -+ /* Only need to check the primary super block. */ -+ sb = btrfs_read_dev_one_super(dev->bdev, 0, true); -+ if (IS_ERR(sb)) -+ return PTR_ERR(sb); -+ -+ /* Btrfs_validate_super() includes fsid check against super->fsid. */ -+ ret = btrfs_validate_super(fs_info, sb, 0); -+ if (ret < 0) -+ goto out; -+ -+ if (btrfs_super_generation(sb) != fs_info->last_trans_committed) { -+ btrfs_err(fs_info, "transid mismatch, has %llu expect %llu", -+ btrfs_super_generation(sb), -+ fs_info->last_trans_committed); -+ ret = -EUCLEAN; -+ goto out; -+ } -+out: -+ btrfs_release_disk_super(sb); -+ return ret; -+} -+ - static int btrfs_unfreeze(struct super_block *sb) - { - struct btrfs_fs_info *fs_info = btrfs_sb(sb); -+ struct btrfs_device *device; -+ int ret = 0; - -+ /* -+ * Make sure the fs is not changed by accident (like hibernation then -+ * modified by other OS). -+ * If we found anything wrong, we mark the fs error immediately. -+ * -+ * And since the fs is frozen, no one can modify the fs yet, thus -+ * we don't need to hold device_list_mutex. -+ */ -+ list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { -+ ret = check_dev_super(device); -+ if (ret < 0) { -+ btrfs_handle_fs_error(fs_info, ret, -+ "super block on devid %llu got modified unexpectedly", -+ device->devid); -+ break; -+ } -+ } - clear_bit(BTRFS_FS_FROZEN, &fs_info->flags); -+ -+ /* -+ * We still return 0, to allow VFS layer to unfreeze the fs even the -+ * above checks failed. Since the fs is either fine or read-only, we're -+ * safe to continue, without causing further damage. -+ */ - return 0; - } - -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c -index 16e01fbdcec8..4f9c0c5b9613 100644 ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -2016,7 +2016,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info, - struct page *page; - int ret; - -- disk_super = btrfs_read_dev_one_super(bdev, copy_num); -+ disk_super = btrfs_read_dev_one_super(bdev, copy_num, false); - if (IS_ERR(disk_super)) - continue; - --- -2.35.1 - diff --git a/queue-5.19/series b/queue-5.19/series index f5cecb32d63..89a62394e4d 100644 --- a/queue-5.19/series +++ b/queue-5.19/series @@ -732,7 +732,6 @@ btrfs-scrub-properly-report-super-block-errors-in-sy.patch btrfs-scrub-try-to-fix-super-block-errors.patch btrfs-don-t-print-information-about-space-cache-or-t.patch btrfs-call-__btrfs_remove_free_space_cache_locked-on.patch -btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch arm64-dts-uniphier-add-usb-device-support-for-pxs3-r.patch arm-9233-1-stacktrace-skip-frame-pointer-boundary-ch.patch arm-9234-1-stacktrace-avoid-duplicate-saving-of-exce.patch diff --git a/queue-6.0/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch b/queue-6.0/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch deleted file mode 100644 index 36f815e499d..00000000000 --- a/queue-6.0/btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch +++ /dev/null @@ -1,254 +0,0 @@ -From e0be5b40aa9590bb5a5e2e1cda7141ab157304ea Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 24 Aug 2022 20:16:22 +0800 -Subject: btrfs: check superblock to ensure the fs was not modified at thaw - time - -From: Qu Wenruo - -[ Upstream commit a05d3c9153145283ce9c58a1d7a9056fbb85f6a1 ] - -[BACKGROUND] -There is an incident report that, one user hibernated the system, with -one btrfs on removable device still mounted. - -Then by some incident, the btrfs got mounted and modified by another -system/OS, then back to the hibernated system. - -After resuming from the hibernation, new write happened into the victim btrfs. - -Now the fs is completely broken, since the underlying btrfs is no longer -the same one before the hibernation, and the user lost their data due to -various transid mismatch. - -[REPRODUCER] -We can emulate the situation using the following small script: - - truncate -s 1G $dev - mkfs.btrfs -f $dev - mount $dev $mnt - fsstress -w -d $mnt -n 500 - sync - xfs_freeze -f $mnt - cp $dev $dev.backup - - # There is no way to mount the same cloned fs on the same system, - # as the conflicting fsid will be rejected by btrfs. - # Thus here we have to wipe the fs using a different btrfs. - mkfs.btrfs -f $dev.backup - - dd if=$dev.backup of=$dev bs=1M - xfs_freeze -u $mnt - fsstress -w -d $mnt -n 20 - umount $mnt - btrfs check $dev - -The final fsck will fail due to some tree blocks has incorrect fsid. - -This is enough to emulate the problem hit by the unfortunate user. - -[ENHANCEMENT] -Although such case should not be that common, it can still happen from -time to time. - -From the view of btrfs, we can detect any unexpected super block change, -and if there is any unexpected change, we just mark the fs read-only, -and thaw the fs. - -By this we can limit the damage to minimal, and I hope no one would lose -their data by this anymore. - -Suggested-by: Goffredo Baroncelli -Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/ -Reviewed-by: Anand Jain -Signed-off-by: Qu Wenruo -Signed-off-by: David Sterba -Signed-off-by: Sasha Levin ---- - fs/btrfs/disk-io.c | 25 ++++++++++++++----- - fs/btrfs/disk-io.h | 4 +++- - fs/btrfs/super.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ - fs/btrfs/volumes.c | 2 +- - 4 files changed, 83 insertions(+), 8 deletions(-) - -diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c -index e0e1730e67d7..d9881b54efd1 100644 ---- a/fs/btrfs/disk-io.c -+++ b/fs/btrfs/disk-io.c -@@ -2600,8 +2600,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) - * 1, 2 2nd and 3rd backup copy - * -1 skip bytenr check - */ --static int validate_super(struct btrfs_fs_info *fs_info, -- struct btrfs_super_block *sb, int mirror_num) -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num) - { - u64 nodesize = btrfs_super_nodesize(sb); - u64 sectorsize = btrfs_super_sectorsize(sb); -@@ -2785,7 +2785,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, - */ - static int btrfs_validate_mount_super(struct btrfs_fs_info *fs_info) - { -- return validate_super(fs_info, fs_info->super_copy, 0); -+ return btrfs_validate_super(fs_info, fs_info->super_copy, 0); - } - - /* -@@ -2799,7 +2799,7 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info, - { - int ret; - -- ret = validate_super(fs_info, sb, -1); -+ ret = btrfs_validate_super(fs_info, sb, -1); - if (ret < 0) - goto out; - if (!btrfs_supported_super_csum(btrfs_super_csum_type(sb))) { -@@ -3846,7 +3846,7 @@ static void btrfs_end_super_write(struct bio *bio) - } - - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num) -+ int copy_num, bool drop_cache) - { - struct btrfs_super_block *super; - struct page *page; -@@ -3864,6 +3864,19 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, - if (bytenr + BTRFS_SUPER_INFO_SIZE >= bdev_nr_bytes(bdev)) - return ERR_PTR(-EINVAL); - -+ if (drop_cache) { -+ /* This should only be called with the primary sb. */ -+ ASSERT(copy_num == 0); -+ -+ /* -+ * Drop the page of the primary superblock, so later read will -+ * always read from the device. -+ */ -+ invalidate_inode_pages2_range(mapping, -+ bytenr >> PAGE_SHIFT, -+ (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); -+ } -+ - page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS); - if (IS_ERR(page)) - return ERR_CAST(page); -@@ -3895,7 +3908,7 @@ struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev) - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - for (i = 0; i < 1; i++) { -- super = btrfs_read_dev_one_super(bdev, i); -+ super = btrfs_read_dev_one_super(bdev, i, false); - if (IS_ERR(super)) - continue; - -diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h -index 47ad8e0a2d33..aef981de672c 100644 ---- a/fs/btrfs/disk-io.h -+++ b/fs/btrfs/disk-io.h -@@ -46,10 +46,12 @@ int __cold open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); - void __cold close_ctree(struct btrfs_fs_info *fs_info); -+int btrfs_validate_super(struct btrfs_fs_info *fs_info, -+ struct btrfs_super_block *sb, int mirror_num); - int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors); - struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev); - struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, -- int copy_num); -+ int copy_num, bool drop_cache); - int btrfs_commit_super(struct btrfs_fs_info *fs_info); - struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, - struct btrfs_key *key); -diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c -index ad3ce9700eaf..079855e9c881 100644 ---- a/fs/btrfs/super.c -+++ b/fs/btrfs/super.c -@@ -2562,11 +2562,71 @@ static int btrfs_freeze(struct super_block *sb) - return btrfs_commit_transaction(trans); - } - -+static int check_dev_super(struct btrfs_device *dev) -+{ -+ struct btrfs_fs_info *fs_info = dev->fs_info; -+ struct btrfs_super_block *sb; -+ int ret = 0; -+ -+ /* This should be called with fs still frozen. */ -+ ASSERT(test_bit(BTRFS_FS_FROZEN, &fs_info->flags)); -+ -+ /* Missing dev, no need to check. */ -+ if (!dev->bdev) -+ return 0; -+ -+ /* Only need to check the primary super block. */ -+ sb = btrfs_read_dev_one_super(dev->bdev, 0, true); -+ if (IS_ERR(sb)) -+ return PTR_ERR(sb); -+ -+ /* Btrfs_validate_super() includes fsid check against super->fsid. */ -+ ret = btrfs_validate_super(fs_info, sb, 0); -+ if (ret < 0) -+ goto out; -+ -+ if (btrfs_super_generation(sb) != fs_info->last_trans_committed) { -+ btrfs_err(fs_info, "transid mismatch, has %llu expect %llu", -+ btrfs_super_generation(sb), -+ fs_info->last_trans_committed); -+ ret = -EUCLEAN; -+ goto out; -+ } -+out: -+ btrfs_release_disk_super(sb); -+ return ret; -+} -+ - static int btrfs_unfreeze(struct super_block *sb) - { - struct btrfs_fs_info *fs_info = btrfs_sb(sb); -+ struct btrfs_device *device; -+ int ret = 0; - -+ /* -+ * Make sure the fs is not changed by accident (like hibernation then -+ * modified by other OS). -+ * If we found anything wrong, we mark the fs error immediately. -+ * -+ * And since the fs is frozen, no one can modify the fs yet, thus -+ * we don't need to hold device_list_mutex. -+ */ -+ list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { -+ ret = check_dev_super(device); -+ if (ret < 0) { -+ btrfs_handle_fs_error(fs_info, ret, -+ "super block on devid %llu got modified unexpectedly", -+ device->devid); -+ break; -+ } -+ } - clear_bit(BTRFS_FS_FROZEN, &fs_info->flags); -+ -+ /* -+ * We still return 0, to allow VFS layer to unfreeze the fs even the -+ * above checks failed. Since the fs is either fine or read-only, we're -+ * safe to continue, without causing further damage. -+ */ - return 0; - } - -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c -index f63ff91e2883..b4df6f74855c 100644 ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -2017,7 +2017,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info, - struct page *page; - int ret; - -- disk_super = btrfs_read_dev_one_super(bdev, copy_num); -+ disk_super = btrfs_read_dev_one_super(bdev, copy_num, false); - if (IS_ERR(disk_super)) - continue; - --- -2.35.1 - diff --git a/queue-6.0/series b/queue-6.0/series index 7f0ec1f8e5b..3cbfe05400b 100644 --- a/queue-6.0/series +++ b/queue-6.0/series @@ -820,7 +820,6 @@ btrfs-scrub-properly-report-super-block-errors-in-sy.patch btrfs-scrub-try-to-fix-super-block-errors.patch btrfs-don-t-print-information-about-space-cache-or-t.patch btrfs-call-__btrfs_remove_free_space_cache_locked-on.patch -btrfs-check-superblock-to-ensure-the-fs-was-not-modi.patch arm64-dts-uniphier-add-usb-device-support-for-pxs3-r.patch arm-9233-1-stacktrace-skip-frame-pointer-boundary-ch.patch arm-9234-1-stacktrace-avoid-duplicate-saving-of-exce.patch -- 2.47.3