+++ /dev/null
-From c51682ccc8cdebf7af7fa6f95508f6e3f87ab104 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <wqu@suse.com>
-
-[ 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 <kreijack@libero.it>
-Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/
-Reviewed-by: Anand Jain <anand.jain@oracle.com>
-Signed-off-by: Qu Wenruo <wqu@suse.com>
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From d490034decc9adb54e82e9804e5dfac7bb746315 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <wqu@suse.com>
-
-[ 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 <kreijack@libero.it>
-Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/
-Reviewed-by: Anand Jain <anand.jain@oracle.com>
-Signed-off-by: Qu Wenruo <wqu@suse.com>
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From e69472b7611bd51247177446c783392d45302651 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <wqu@suse.com>
-
-[ 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 <kreijack@libero.it>
-Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/
-Reviewed-by: Anand Jain <anand.jain@oracle.com>
-Signed-off-by: Qu Wenruo <wqu@suse.com>
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From e0be5b40aa9590bb5a5e2e1cda7141ab157304ea Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <wqu@suse.com>
-
-[ 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 <kreijack@libero.it>
-Link: https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/
-Reviewed-by: Anand Jain <anand.jain@oracle.com>
-Signed-off-by: Qu Wenruo <wqu@suse.com>
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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