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