diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 0d250d052487..0a1302c726f1 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1809,6 +1809,62 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl,
 	return entry;
 }
 
+static bool need_relink_free_space_offset(struct btrfs_free_space_ctl *ctl,
+					  struct btrfs_free_space *info,
+					  u64 bytes)
+{
+	struct rb_node *node = NULL;
+	struct btrfs_free_space *entry = NULL;
+
+	/* the free space will be zero size after alloc, it then needs unlink and release */
+	if (bytes >= info->bytes)
+		return true;
+
+	/*we are not the entry that may stride the start of a bitmap, so no offset changing will cause relink */
+	if (!(info->flags & FREE_SPACE_FLAG_CROSS_BITMAP))
+		return false;
+
+	node = rb_next(&info->offset_index);
+	/* we are the last node, no offset changing will cause relink */
+	if (!node)
+		return false;
+
+	entry = rb_entry(node, struct btrfs_free_space, offset_index);
+
+	/* there is no bitmap existed to be crossed by our info, no offset changing will cause relink */
+	if (!entry->bitmap)
+		return false;
+
+	/* our start will still ahead start of the bitmap after alloc, no need of relink */
+	if (info->offset + bytes <= entry->offset)
+		return false;
+
+	/* our start will cross the start of the bitmap after alloc, that needs a relink */
+	return true;
+}
+
+static bool need_relink_free_space_bytes(struct btrfs_free_space_ctl *ctl,
+					 struct btrfs_free_space *info,
+					 u64 bytes)
+{
+	struct rb_node *node = NULL;
+	struct btrfs_free_space *entry = NULL;
+
+	if (bytes >= info->bytes)
+		return true;
+
+	node = rb_next(&info->bytes_index);
+	if (!node)
+		return false;
+
+	entry = rb_entry(node, struct btrfs_free_space, bytes_index);
+
+	if ((info->bytes - bytes) >= entry->bytes)
+		return false;
+
+	return true;
+}
+
 static inline void unlink_free_space(struct btrfs_free_space_ctl *ctl,
 				     struct btrfs_free_space *info,
 				     bool update_stat)
@@ -1830,8 +1886,18 @@ static int link_free_space(struct btrfs_free_space_ctl *ctl,
 			   struct btrfs_free_space *info)
 {
 	int ret = 0;
+	u64 b_offset;
 
 	ASSERT(info->bytes || info->bitmap);
+
+	if (info->bitmap == NULL) {
+		b_offset = offset_to_bitmap(ctl, info->offset + info->bytes);
+		if (b_offset >= info->offset)
+			info->flags |= FREE_SPACE_FLAG_CROSS_BITMAP;
+		else
+			info->flags &= ~FREE_SPACE_FLAG_CROSS_BITMAP;
+	}
+
 	ret = tree_insert_offset(&ctl->free_space_offset, info->offset,
 				 &info->offset_index, (info->bitmap != NULL));
 	if (ret)
@@ -3078,6 +3144,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
 	u64 align_gap_len = 0;
 	enum btrfs_trim_state align_gap_trim_state = BTRFS_TRIM_STATE_UNTRIMMED;
 	bool use_bytes_index = (offset == block_group->start);
+	u64 new_offset, new_bytes; 
+	bool need_reln_offset, need_reln_bytes;
 
 	ASSERT(!btrfs_is_zoned(block_group->fs_info));
 
@@ -3098,7 +3166,6 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
 		if (!entry->bytes)
 			free_bitmap(ctl, entry);
 	} else {
-		unlink_free_space(ctl, entry, true);
 		align_gap_len = offset - entry->offset;
 		align_gap = entry->offset;
 		align_gap_trim_state = entry->trim_state;
@@ -3106,14 +3173,36 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
 		if (!btrfs_free_space_trimmed(entry))
 			atomic64_add(bytes, &discard_ctl->discard_bytes_saved);
 
-		entry->offset = offset + bytes;
+		new_offset = offset + bytes;
 		WARN_ON(entry->bytes < bytes + align_gap_len);
 
-		entry->bytes -= bytes + align_gap_len;
-		if (!entry->bytes)
+		new_bytes = entry->bytes - (bytes + align_gap_len);
+
+		if (!new_bytes) {
+			unlink_free_space(ctl, entry, true);
 			kmem_cache_free(btrfs_free_space_cachep, entry);
-		else
-			link_free_space(ctl, entry);
+		} else {
+			need_reln_offset = need_relink_free_space_offset(ctl, entry, bytes);
+
+			if (need_reln_offset)
+				rb_erase(&entry->offset_index, &ctl->free_space_offset);
+
+			need_reln_bytes = need_relink_free_space_bytes(ctl, entry, bytes);
+			
+			if (need_reln_bytes)
+				rb_erase_cached(&entry->bytes_index, &ctl->free_space_bytes);
+
+			entry->offset = new_offset;
+			entry->bytes = new_bytes;
+
+			if (need_reln_offset)
+				tree_insert_offset(&ctl->free_space_offset, entry->offset,
+					&entry->offset_index, (entry->bitmap != NULL));
+
+			if (need_reln_bytes)
+				rb_add_cached(&entry->bytes_index, &ctl->free_space_bytes,
+					entry_less);
+		}
 	}
 out:
 	btrfs_discard_update_discardable(block_group);
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index a855e0483e03..2a165df394d6 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -20,6 +20,8 @@ enum btrfs_trim_state {
 	BTRFS_TRIM_STATE_TRIMMING,
 };
 
+#define FREE_SPACE_FLAG_CROSS_BITMAP	(1ULL << 5)
+
 struct btrfs_free_space {
 	struct rb_node offset_index;
 	struct rb_node bytes_index;
@@ -30,6 +32,7 @@ struct btrfs_free_space {
 	struct list_head list;
 	enum btrfs_trim_state trim_state;
 	s32 bitmap_extents;
+	u32 flags;
 };
 
 static inline bool btrfs_free_space_trimmed(struct btrfs_free_space *info)
