diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 3cdf73277e7e..49c52cced5a5 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -3193,12 +3193,14 @@ static int compare_extent_item_range(struct btrfs_path *path,
  * return the extent item. This is for data extent crossing stripe boundary.
  *
  * Return 0 if we found such extent item, and @path will point to the extent item.
- * Return >0 if no such extent item can be found, and @path will be released.
+ * Return >0 if no such extent item can be found, @path will be released, and
+ * update @found_next to the first extent we found after the search range.
  * Return <0 if hit fatal error, and @path will be released.
  */
 static int find_first_extent_item(struct btrfs_root *extent_root,
 				  struct btrfs_path *path,
-				  u64 search_start, u64 search_len)
+				  u64 search_start, u64 search_len,
+				  u64 *found_next)
 {
 	struct btrfs_fs_info *fs_info = extent_root->fs_info;
 	struct btrfs_key key;
@@ -3234,8 +3236,11 @@ static int find_first_extent_item(struct btrfs_root *extent_root,
 search_forward:
 	while (true) {
 		btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
-		if (key.objectid >= search_start + search_len)
+		if (key.objectid >= search_start + search_len) {
+			if (found_next)
+				*found_next = key.objectid;
 			break;
+		}
 		if (key.type != BTRFS_METADATA_ITEM_KEY &&
 		    key.type != BTRFS_EXTENT_ITEM_KEY)
 			goto next;
@@ -3243,8 +3248,11 @@ static int find_first_extent_item(struct btrfs_root *extent_root,
 		ret = compare_extent_item_range(path, search_start, search_len);
 		if (ret == 0)
 			return ret;
-		if (ret > 0)
+		if (ret > 0) {
+			if (found_next)
+				*found_next = key.objectid;
 			break;
+		}
 next:
 		path->slots[0]++;
 		if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
@@ -3252,6 +3260,10 @@ static int find_first_extent_item(struct btrfs_root *extent_root,
 			if (ret) {
 				/* Either no more item or fatal error */
 				btrfs_release_path(path);
+
+				/* No more extent tree items. */
+				if (ret > 0 && found_next)
+					*found_next = U64_MAX;
 				return ret;
 			}
 		}
@@ -3318,7 +3330,8 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
 		u64 extent_mirror_num;
 
 		ret = find_first_extent_item(extent_root, path, cur_logical,
-					     logical + BTRFS_STRIPE_LEN - cur_logical);
+					     logical + BTRFS_STRIPE_LEN - cur_logical,
+					     NULL);
 		/* No more extent item in this data stripe */
 		if (ret > 0) {
 			ret = 0;
@@ -3513,7 +3526,8 @@ static int scrub_simple_mirror(struct scrub_ctx *sctx,
 			       struct map_lookup *map,
 			       u64 logical_start, u64 logical_length,
 			       struct btrfs_device *device,
-			       u64 physical, int mirror_num)
+			       u64 physical, int mirror_num,
+			       u64 *found_next)
 {
 	struct btrfs_fs_info *fs_info = sctx->fs_info;
 	struct btrfs_root *csum_root = btrfs_csum_root(fs_info, bg->start);
@@ -3567,7 +3581,8 @@ static int scrub_simple_mirror(struct scrub_ctx *sctx,
 		spin_unlock(&bg->lock);
 
 		ret = find_first_extent_item(extent_root, &path, cur_logical,
-					     logical_end - cur_logical);
+					     logical_end - cur_logical,
+					     found_next);
 		if (ret > 0) {
 			/* No more extent, just update the accounting */
 			sctx->stat.last_physical = physical + logical_length;
@@ -3681,6 +3696,8 @@ static int scrub_simple_stripe(struct scrub_ctx *sctx,
 	int ret = 0;
 
 	while (cur_logical < bg->start + bg->length) {
+		u64 found_next = 0;
+
 		/*
 		 * Inside each stripe, RAID0 is just SINGLE, and RAID10 is
 		 * just RAID1, so we can reuse scrub_simple_mirror() to scrub
@@ -3688,13 +3705,23 @@ static int scrub_simple_stripe(struct scrub_ctx *sctx,
 		 */
 		ret = scrub_simple_mirror(sctx, bg, map, cur_logical,
 					  BTRFS_STRIPE_LEN, device, cur_physical,
-					  mirror_num);
+					  mirror_num, &found_next);
 		if (ret)
 			return ret;
 		/* Skip to next stripe which belongs to the target device */
 		cur_logical += logical_increment;
 		/* For physical offset, we just go to next stripe */
 		cur_physical += BTRFS_STRIPE_LEN;
+
+		/*
+		 * If the next extent is still beyond our current range, we
+		 * can skip them until the @found_next.
+		 */
+		while (cur_logical + BTRFS_STRIPE_LEN < found_next &&
+		       cur_logical < bg->start + bg->length) {
+			cur_logical += logical_increment;
+			cur_physical += BTRFS_STRIPE_LEN;
+		}
 	}
 	return ret;
 }
@@ -3761,7 +3788,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 		 */
 		ret = scrub_simple_mirror(sctx, bg, map, bg->start, bg->length,
 				scrub_dev, map->stripes[stripe_index].physical,
-				stripe_index + 1);
+				stripe_index + 1, NULL);
 		offset = 0;
 		goto out;
 	}
@@ -3813,7 +3840,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 		 * is still based on @mirror_num.
 		 */
 		ret = scrub_simple_mirror(sctx, bg, map, logical, BTRFS_STRIPE_LEN,
-					  scrub_dev, physical, 1);
+					  scrub_dev, physical, 1, NULL);
 		if (ret < 0)
 			goto out;
 next:
