summaryrefslogtreecommitdiffstats
path: root/Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch
diff options
context:
space:
mode:
Diffstat (limited to 'Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch')
-rw-r--r--Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch119
1 files changed, 119 insertions, 0 deletions
diff --git a/Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch b/Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch
new file mode 100644
index 000000000..63f66fb1b
--- /dev/null
+++ b/Btrfs-fix-fitrim-discarding-device-area-reserved-for.patch
@@ -0,0 +1,119 @@
+From 259072b7a1c20f8612dcaa8e0e027004aa98f864 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Wed, 6 Jan 2016 22:42:35 +0000
+Subject: [PATCH 2/2] Btrfs: fix fitrim discarding device area reserved for
+ boot loader's use
+
+As of the 4.3 kernel release, the fitrim ioctl can now discard any region
+of a disk that is not allocated to any chunk/block group, including the
+first megabyte which is used for our primary superblock and by the boot
+loader (grub for example).
+
+Fix this by not allowing to trim/discard any region in the device starting
+with an offset not greater than min(alloc_start_mount_option, 1Mb), just
+as it was not possible before 4.3.
+
+A reproducer test case for xfstests follows.
+
+ seq=`basename $0`
+ seqres=$RESULT_DIR/$seq
+ echo "QA output created by $seq"
+ tmp=/tmp/$$
+ status=1 # failure is the default!
+ trap "_cleanup; exit \$status" 0 1 2 3 15
+
+ _cleanup()
+ {
+ cd /
+ rm -f $tmp.*
+ }
+
+ # get standard environment, filters and checks
+ . ./common/rc
+ . ./common/filter
+
+ # real QA test starts here
+ _need_to_be_root
+ _supported_fs btrfs
+ _supported_os Linux
+ _require_scratch
+
+ rm -f $seqres.full
+
+ _scratch_mkfs >>$seqres.full 2>&1
+
+ # Write to the [0, 64Kb[ and [68Kb, 1Mb[ ranges of the device. These ranges are
+ # reserved for a boot loader to use (GRUB for example) and btrfs should never
+ # use them - neither for allocating metadata/data nor should trim/discard them.
+ # The range [64Kb, 68Kb[ is used for the primary superblock of the filesystem.
+ $XFS_IO_PROG -c "pwrite -S 0xfd 0 64K" $SCRATCH_DEV | _filter_xfs_io
+ $XFS_IO_PROG -c "pwrite -S 0xfd 68K 956K" $SCRATCH_DEV | _filter_xfs_io
+
+ # Now mount the filesystem and perform a fitrim against it.
+ _scratch_mount
+ _require_batched_discard $SCRATCH_MNT
+ $FSTRIM_PROG $SCRATCH_MNT
+
+ # Now unmount the filesystem and verify the content of the ranges was not
+ # modified (no trim/discard happened on them).
+ _scratch_unmount
+ echo "Content of the ranges [0, 64Kb] and [68Kb, 1Mb[ after fitrim:"
+ od -t x1 -N $((64 * 1024)) $SCRATCH_DEV
+ od -t x1 -j $((68 * 1024)) -N $((956 * 1024)) $SCRATCH_DEV
+
+ status=0
+ exit
+
+Reported-by: Vincent Petry <PVince81@yahoo.fr>
+Reported-by: Andrei Borzenkov <arvidjaar@gmail.com>
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=109341
+Fixes: 499f377f49f0 (btrfs: iterate over unused chunk space in FITRIM)
+Cc: stable@vger.kernel.org # 4.3+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+---
+ fs/btrfs/volumes.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index b816b3a2e118..96f8c827d563 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1208,6 +1208,15 @@ int find_free_dev_extent_start(struct btrfs_transaction *transaction,
+ int ret;
+ int slot;
+ struct extent_buffer *l;
++ u64 min_search_start;
++
++ /*
++ * We don't want to overwrite the superblock on the drive nor any area
++ * used by the boot loader (grub for example), so we make sure to start
++ * at an offset of at least 1MB.
++ */
++ min_search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
++ search_start = max(search_start, min_search_start);
+
+ path = btrfs_alloc_path();
+ if (!path)
+@@ -1348,18 +1357,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device, u64 num_bytes,
+ u64 *start, u64 *len)
+ {
+- struct btrfs_root *root = device->dev_root;
+- u64 search_start;
+-
+ /* FIXME use last free of some kind */
+-
+- /*
+- * we don't want to overwrite the superblock on the drive,
+- * so we make sure to start at an offset of at least 1MB
+- */
+- search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
+ return find_free_dev_extent_start(trans->transaction, device,
+- num_bytes, search_start, start, len);
++ num_bytes, 0, start, len);
+ }
+
+ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
+--
+2.5.0
+