diff mbox series

btrfs: limit device extents to the device size

Message ID 158f8775fb0256a09ab4badb752e2202aa118e1d.1674077707.git.josef@toxicpanda.com (mailing list archive)
State New, archived
Headers show
Series btrfs: limit device extents to the device size | expand

Commit Message

Josef Bacik Jan. 18, 2023, 9:35 p.m. UTC
There was a recent regression in btrfs/177 that started happening with
the size class patches.  This however isn't a regression introduced by
those patches, but rather the bug was uncovered by a change in behavior
in these patches.  The patches triggered more chunk allocations in the
^free-space-tree case, which uncovered a race with device shrink.

The problem is we will set the device total size to the new size, and
use this to find a hole for a device extent.  However during shrink we
may have device extents allocated past this range, so we could
potentially find a hole in a range past our new shrink size.  We don't
actually limit our found extent to the device size anywhere, we assume
that we will not find a hole past our device size.  This isn't true with
shrink as we're relocating block groups and thus creating holes past the
device size.

Fix this by making sure we do not search past the new device size, and
if we wander into any device extents that start after our device size
simply break from the loop and use whatever hole we've already found.

cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/volumes.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Comments

David Sterba Jan. 19, 2023, 7:31 p.m. UTC | #1
On Wed, Jan 18, 2023 at 04:35:13PM -0500, Josef Bacik wrote:
> There was a recent regression in btrfs/177 that started happening with
> the size class patches.  This however isn't a regression introduced by
> those patches, but rather the bug was uncovered by a change in behavior
> in these patches.  The patches triggered more chunk allocations in the
> ^free-space-tree case, which uncovered a race with device shrink.
> 
> The problem is we will set the device total size to the new size, and
> use this to find a hole for a device extent.  However during shrink we
> may have device extents allocated past this range, so we could
> potentially find a hole in a range past our new shrink size.  We don't
> actually limit our found extent to the device size anywhere, we assume
> that we will not find a hole past our device size.  This isn't true with
> shrink as we're relocating block groups and thus creating holes past the
> device size.
> 
> Fix this by making sure we do not search past the new device size, and
> if we wander into any device extents that start after our device size
> simply break from the loop and use whatever hole we've already found.
> 
> cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Added to misc-next, thanks.
diff mbox series

Patch

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 675598c3cb35..707dd0456cea 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1600,7 +1600,7 @@  static int find_free_dev_extent_start(struct btrfs_device *device,
 	if (ret < 0)
 		goto out;
 
-	while (1) {
+	while (search_start < search_end) {
 		l = path->nodes[0];
 		slot = path->slots[0];
 		if (slot >= btrfs_header_nritems(l)) {
@@ -1623,6 +1623,9 @@  static int find_free_dev_extent_start(struct btrfs_device *device,
 		if (key.type != BTRFS_DEV_EXTENT_KEY)
 			goto next;
 
+		if (key.offset > search_end)
+			break;
+
 		if (key.offset > search_start) {
 			hole_size = key.offset - search_start;
 			dev_extent_hole_check(device, &search_start, &hole_size,
@@ -1683,6 +1686,7 @@  static int find_free_dev_extent_start(struct btrfs_device *device,
 	else
 		ret = 0;
 
+	ASSERT(max_hole_start + max_hole_size <= search_end);
 out:
 	btrfs_free_path(path);
 	*start = max_hole_start;