Skip to content

Commit 3c17916

Browse files
lorddoskiaskdave
authored andcommitted
btrfs: fix race between extent freeing/allocation when using bitmaps
During allocation the allocator will try to allocate an extent using cluster policy. Once the current cluster is exhausted it will remove the entry under btrfs_free_cluster::lock and subsequently acquire btrfs_free_space_ctl::tree_lock to dispose of the already-deleted entry and adjust btrfs_free_space_ctl::total_bitmap. This poses a problem because there exists a race condition between removing the entry under one lock and doing the necessary accounting holding a different lock since extent freeing only uses the 2nd lock. This can result in the following situation: T1: T2: btrfs_alloc_from_cluster insert_into_bitmap <holds tree_lock> if (entry->bytes == 0) if (block_group && !list_empty(&block_group->cluster_list)) { rb_erase(entry) spin_unlock(&cluster->lock); (total_bitmaps is still 4) spin_lock(&cluster->lock); <doesn't find entry in cluster->root> spin_lock(&ctl->tree_lock); <goes to new_bitmap label, adds <blocked since T2 holds tree_lock> <a new entry and calls add_new_bitmap> recalculate_thresholds <crashes, due to total_bitmaps becoming 5 and triggering an ASSERT> To fix this ensure that once depleted, the cluster entry is deleted when both cluster lock and tree locks are held in the allocator (T1), this ensures that even if there is a race with a concurrent insert_into_bitmap call it will correctly find the entry in the cluster and add the new space to it. CC: <stable@vger.kernel.org> # 4.4+ Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 04d4ba4 commit 3c17916

1 file changed

Lines changed: 4 additions & 2 deletions

File tree

fs/btrfs/free-space-cache.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,8 +3125,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group *block_group,
31253125
entry->bytes -= bytes;
31263126
}
31273127

3128-
if (entry->bytes == 0)
3129-
rb_erase(&entry->offset_index, &cluster->root);
31303128
break;
31313129
}
31323130
out:
@@ -3143,7 +3141,10 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group *block_group,
31433141
ctl->free_space -= bytes;
31443142
if (!entry->bitmap && !btrfs_free_space_trimmed(entry))
31453143
ctl->discardable_bytes[BTRFS_STAT_CURR] -= bytes;
3144+
3145+
spin_lock(&cluster->lock);
31463146
if (entry->bytes == 0) {
3147+
rb_erase(&entry->offset_index, &cluster->root);
31473148
ctl->free_extents--;
31483149
if (entry->bitmap) {
31493150
kmem_cache_free(btrfs_free_space_bitmap_cachep,
@@ -3156,6 +3157,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group *block_group,
31563157
kmem_cache_free(btrfs_free_space_cachep, entry);
31573158
}
31583159

3160+
spin_unlock(&cluster->lock);
31593161
spin_unlock(&ctl->tree_lock);
31603162

31613163
return ret;

0 commit comments

Comments
 (0)