@@ -5735,17 +5735,21 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
5735
5735
unpin = & fs_info -> freed_extents [0 ];
5736
5736
5737
5737
while (1 ) {
5738
+ mutex_lock (& fs_info -> unused_bg_unpin_mutex );
5738
5739
ret = find_first_extent_bit (unpin , 0 , & start , & end ,
5739
5740
EXTENT_DIRTY , NULL );
5740
- if (ret )
5741
+ if (ret ) {
5742
+ mutex_unlock (& fs_info -> unused_bg_unpin_mutex );
5741
5743
break ;
5744
+ }
5742
5745
5743
5746
if (btrfs_test_opt (root , DISCARD ))
5744
5747
ret = btrfs_discard_extent (root , start ,
5745
5748
end + 1 - start , NULL );
5746
5749
5747
5750
clear_extent_dirty (unpin , start , end , GFP_NOFS );
5748
5751
unpin_extent_range (root , start , end , true);
5752
+ mutex_unlock (& fs_info -> unused_bg_unpin_mutex );
5749
5753
cond_resched ();
5750
5754
}
5751
5755
@@ -9561,18 +9565,33 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
9561
9565
*/
9562
9566
start = block_group -> key .objectid ;
9563
9567
end = start + block_group -> key .offset - 1 ;
9568
+ /*
9569
+ * Hold the unused_bg_unpin_mutex lock to avoid racing with
9570
+ * btrfs_finish_extent_commit(). If we are at transaction N,
9571
+ * another task might be running finish_extent_commit() for the
9572
+ * previous transaction N - 1, and have seen a range belonging
9573
+ * to the block group in freed_extents[] before we were able to
9574
+ * clear the whole block group range from freed_extents[]. This
9575
+ * means that task can lookup for the block group after we
9576
+ * unpinned it from freed_extents[] and removed it, leading to
9577
+ * a BUG_ON() at btrfs_unpin_extent_range().
9578
+ */
9579
+ mutex_lock (& fs_info -> unused_bg_unpin_mutex );
9564
9580
ret = clear_extent_bits (& fs_info -> freed_extents [0 ], start , end ,
9565
9581
EXTENT_DIRTY , GFP_NOFS );
9566
9582
if (ret ) {
9583
+ mutex_unlock (& fs_info -> unused_bg_unpin_mutex );
9567
9584
btrfs_set_block_group_rw (root , block_group );
9568
9585
goto end_trans ;
9569
9586
}
9570
9587
ret = clear_extent_bits (& fs_info -> freed_extents [1 ], start , end ,
9571
9588
EXTENT_DIRTY , GFP_NOFS );
9572
9589
if (ret ) {
9590
+ mutex_unlock (& fs_info -> unused_bg_unpin_mutex );
9573
9591
btrfs_set_block_group_rw (root , block_group );
9574
9592
goto end_trans ;
9575
9593
}
9594
+ mutex_unlock (& fs_info -> unused_bg_unpin_mutex );
9576
9595
9577
9596
/* Reset pinned so btrfs_put_block_group doesn't complain */
9578
9597
block_group -> pinned = 0 ;
0 commit comments