aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c1
-rw-r--r--fs/btrfs/extent-tree.c21
3 files changed, 22 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 54a66fa6beb1..d3562dd43c66 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1744,6 +1744,7 @@ struct btrfs_fs_info {
1744 1744
1745 spinlock_t unused_bgs_lock; 1745 spinlock_t unused_bgs_lock;
1746 struct list_head unused_bgs; 1746 struct list_head unused_bgs;
1747 struct mutex unused_bg_unpin_mutex;
1747 1748
1748 /* For btrfs to record security options */ 1749 /* For btrfs to record security options */
1749 struct security_mnt_opts security_opts; 1750 struct security_mnt_opts security_opts;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 263d1471d01a..41b320e235d7 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2242,6 +2242,7 @@ int open_ctree(struct super_block *sb,
2242 spin_lock_init(&fs_info->qgroup_op_lock); 2242 spin_lock_init(&fs_info->qgroup_op_lock);
2243 spin_lock_init(&fs_info->buffer_lock); 2243 spin_lock_init(&fs_info->buffer_lock);
2244 spin_lock_init(&fs_info->unused_bgs_lock); 2244 spin_lock_init(&fs_info->unused_bgs_lock);
2245 mutex_init(&fs_info->unused_bg_unpin_mutex);
2245 rwlock_init(&fs_info->tree_mod_log_lock); 2246 rwlock_init(&fs_info->tree_mod_log_lock);
2246 mutex_init(&fs_info->reloc_mutex); 2247 mutex_init(&fs_info->reloc_mutex);
2247 mutex_init(&fs_info->delalloc_root_mutex); 2248 mutex_init(&fs_info->delalloc_root_mutex);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 53294da0749d..857a859948a3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5735,10 +5735,13 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
5735 unpin = &fs_info->freed_extents[0]; 5735 unpin = &fs_info->freed_extents[0];
5736 5736
5737 while (1) { 5737 while (1) {
5738 mutex_lock(&fs_info->unused_bg_unpin_mutex);
5738 ret = find_first_extent_bit(unpin, 0, &start, &end, 5739 ret = find_first_extent_bit(unpin, 0, &start, &end,
5739 EXTENT_DIRTY, NULL); 5740 EXTENT_DIRTY, NULL);
5740 if (ret) 5741 if (ret) {
5742 mutex_unlock(&fs_info->unused_bg_unpin_mutex);
5741 break; 5743 break;
5744 }
5742 5745
5743 if (btrfs_test_opt(root, DISCARD)) 5746 if (btrfs_test_opt(root, DISCARD))
5744 ret = btrfs_discard_extent(root, start, 5747 ret = btrfs_discard_extent(root, start,
@@ -5746,6 +5749,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
5746 5749
5747 clear_extent_dirty(unpin, start, end, GFP_NOFS); 5750 clear_extent_dirty(unpin, start, end, GFP_NOFS);
5748 unpin_extent_range(root, start, end, true); 5751 unpin_extent_range(root, start, end, true);
5752 mutex_unlock(&fs_info->unused_bg_unpin_mutex);
5749 cond_resched(); 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 start = block_group->key.objectid; 9566 start = block_group->key.objectid;
9563 end = start + block_group->key.offset - 1; 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 ret = clear_extent_bits(&fs_info->freed_extents[0], start, end, 9580 ret = clear_extent_bits(&fs_info->freed_extents[0], start, end,
9565 EXTENT_DIRTY, GFP_NOFS); 9581 EXTENT_DIRTY, GFP_NOFS);
9566 if (ret) { 9582 if (ret) {
9583 mutex_unlock(&fs_info->unused_bg_unpin_mutex);
9567 btrfs_set_block_group_rw(root, block_group); 9584 btrfs_set_block_group_rw(root, block_group);
9568 goto end_trans; 9585 goto end_trans;
9569 } 9586 }
9570 ret = clear_extent_bits(&fs_info->freed_extents[1], start, end, 9587 ret = clear_extent_bits(&fs_info->freed_extents[1], start, end,
9571 EXTENT_DIRTY, GFP_NOFS); 9588 EXTENT_DIRTY, GFP_NOFS);
9572 if (ret) { 9589 if (ret) {
9590 mutex_unlock(&fs_info->unused_bg_unpin_mutex);
9573 btrfs_set_block_group_rw(root, block_group); 9591 btrfs_set_block_group_rw(root, block_group);
9574 goto end_trans; 9592 goto end_trans;
9575 } 9593 }
9594 mutex_unlock(&fs_info->unused_bg_unpin_mutex);
9576 9595
9577 /* Reset pinned so btrfs_put_block_group doesn't complain */ 9596 /* Reset pinned so btrfs_put_block_group doesn't complain */
9578 block_group->pinned = 0; 9597 block_group->pinned = 0;