--- /dev/null
+From 3c538de0f2a74d50aff7278c092f88ae59cee688 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <josef@toxicpanda.com>
+Date: Wed, 18 Jan 2023 16:35:13 -0500
+Subject: btrfs: limit device extents to the device size
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+commit 3c538de0f2a74d50aff7278c092f88ae59cee688 upstream.
+
+There was a recent regression in btrfs/177 that started happening with
+the size class patches ("btrfs: introduce size class to block group
+allocator"). 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 # 4.14+
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/volumes.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1418,7 +1418,7 @@ again:
+ goto out;
+ }
+
+- while (1) {
++ while (search_start < search_end) {
+ l = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(l)) {
+@@ -1441,6 +1441,9 @@ again:
+ 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;
+
+@@ -1515,6 +1518,7 @@ next:
+ else
+ ret = 0;
+
++ ASSERT(max_hole_start + max_hole_size <= search_end);
+ out:
+ btrfs_free_path(path);
+ *start = max_hole_start;