btrfs: some bug fixes for free space cache
cover btrfs: some bug fixes for free space cache
Those bugs are not critical, which means they won't crash the filesystem, so they're hardly noticeable and no one noticed them.
--- fs/btrfs/free-space-cache.c | 161 ++++++++++++++++++++++++++----------------- 1 files changed, 99 insertions(+), 62 deletions(-)
PATCH 1/6 btrfs: fix threshold calculation for block groups smaller than 1GB
If a block group is smaller than 1GB, the extent entry threadhold calculation will always set the threshold to 0.
So as free space gets fragmented, btrfs will switch to use bitmap to manage free space, but then will never switch back to extents due to this bug.
--- fs/btrfs/free-space-cache.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-)
fs/btrfs/free-space-cache.c +6 -2
@@ -263,14 +263,18 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)u64 max_bytes;u64 bitmap_bytes;u64 extent_bytes; +u64 size = block_group->key.offset;/* * The goal is to keep the total amount of memory used per 1gb of space * at or below 32k, so we need to adjust how much memory we allow to be * used by extent based free space tracking */ - max_bytes =MAX_CACHE_BYTES_PER_GIG * - (div64_u64 (block_group->key.offset,1024 *1024 *1024 )); +if (size <1024 *1024 *1024 ) + max_bytes =MAX_CACHE_BYTES_PER_GIG ; +else + max_bytes =MAX_CACHE_BYTES_PER_GIG * +div64_u64 (size,1024 *1024 *1024 );/* * we want to account for 1 more bitmap than what we have so we can make
Signature · 1 line
1.7.0.1
PATCH 2/6 btrfs: add helper function free_bitmap()
In reply to Li ZefanRemove some duplicated code.
This prepares for the next patch.
--- fs/btrfs/free-space-cache.c | 37 ++++++++++++++++--------------------- 1 files changed, 16 insertions(+), 21 deletions(-)
fs/btrfs/free-space-cache.c +16 -21
@@ -422,6 +422,16 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group,recalculate_thresholds (block_group); } +static void free_bitmap (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *bitmap_info) +{ +unlink_free_space (block_group, bitmap_info); +kfree (bitmap_info->bitmap); +kfree (bitmap_info); + block_group->total_bitmaps--; +recalculate_thresholds (block_group); +} + static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,struct btrfs_free_space *bitmap_info,u64 *offset,u64 *bytes)
@@ -462,13 +472,8 @@ again:if (*bytes) {struct rb_node *next =rb_next (&bitmap_info->offset_index); -if (!bitmap_info->bytes) { -unlink_free_space (block_group, bitmap_info); -kfree (bitmap_info->bitmap); -kfree (bitmap_info); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } +if (!bitmap_info->bytes) +free_bitmap (block_group, bitmap_info);/* * no entry after this bitmap, but we still have bytes to
@@ -501,13 +506,8 @@ again:return -EAGAIN ; goto again; - }else if (!bitmap_info->bytes) { -unlink_free_space (block_group, bitmap_info); -kfree (bitmap_info->bitmap); -kfree (bitmap_info); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } + }else if (!bitmap_info->bytes) +free_bitmap (block_group, bitmap_info);return 0 ; }
@@ -936,13 +936,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, ret = offset;if (entry->bitmap) {bitmap_clear_bits (block_group, entry, offset, bytes); -if (!entry->bytes) { -unlink_free_space (block_group, entry); -kfree (entry->bitmap); -kfree (entry); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } +if (!entry->bytes) +free_bitmap (block_group, entry); }else {unlink_free_space (block_group, entry); entry->offset += bytes;
Signature · 1 line
1.7.0.1
PATCH 3/6 btrfs: free fully occupied bitmap in cluster
In reply to Li ZefanIf there's no more free space in a bitmap, we should free it, otherwise seems it won't get freed until we free the block group.
--- fs/btrfs/free-space-cache.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
fs/btrfs/free-space-cache.c +2 -0
@@ -1035,6 +1035,8 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, ret = search_start;bitmap_clear_bits (block_group, entry, ret, bytes); +if (entry->bytes ==0 ) +free_bitmap (block_group, entry); out:spin_unlock (&cluster->lock);spin_unlock (&block_group->tree_lock);
Signature · 1 line
1.7.0.1
PATCH 4/6 btrfs: update stats when allocating from a cluster
In reply to Li ZefanWhen allocating extent entry from a cluster, we should update the free_space and free_extents fields of the block group.
--- fs/btrfs/free-space-cache.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-)
fs/btrfs/free-space-cache.c +14 -3
@@ -1090,15 +1090,26 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, entry->offset += bytes; entry->bytes -= bytes; -if (entry->bytes ==0 ) { +if (entry->bytes ==0 )rb_erase (&entry->offset_index, &cluster->root); -kfree (entry); - }break ; } out:spin_unlock (&cluster->lock); +if (!ret) +return 0 ; + +spin_lock (&block_group->tree_lock); + + block_group->free_space -= bytes; +if (entry->bytes ==0 ) { + block_group->free_extents--; +kfree (entry); + } + +spin_unlock (&block_group->tree_lock); +return ret; }
Signature · 1 line
1.7.0.1
PATCH 5/6 btrfs: add a helper try_merge_free_space()
In reply to Li ZefanWhen adding a new extent, we'll firstly see if we can merge this extent to the left or/and right extent. Extract this as a helper try_merge_free_space().
As a side effect, we fix a small bug that if the new extent has non-bitmap left entry but is unmergeble, we'll directly link the extent without trying to drop it into bitmap.
This also prepares for the next patch.
--- fs/btrfs/free-space-cache.c | 75 ++++++++++++++++++++++++------------------ 1 files changed, 43 insertions(+), 32 deletions(-)
fs/btrfs/free-space-cache.c +43 -32
@@ -610,22 +610,14 @@ out:return ret; } -int btrfs_add_free_space (struct btrfs_block_group_cache *block_group, -u64 offset,u64 bytes) +bool try_merge_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) { -struct btrfs_free_space *right_info =NULL ; -struct btrfs_free_space *left_info =NULL ; -struct btrfs_free_space *info =NULL ; -int ret =0 ; - - info =kzalloc (sizeof (struct btrfs_free_space ),GFP_NOFS ); -if (!info) -return -ENOMEM ; - - info->offset = offset; - info->bytes = bytes; - -spin_lock (&block_group->tree_lock); +struct btrfs_free_space *left_info; +struct btrfs_free_space *right_info; +bool merged = false; +u64 offset = info->offset; +u64 bytes = info->bytes;/* * first we want to see if there is free space adjacent to the range we
@@ -639,27 +631,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,else left_info =tree_search_offset (block_group, offset -1 ,0 ,0 ); -/* -* If there was no extent directly to the left or right of this new -* extent then we know we're going to have to allocate a new extent, so -* before we do that see if we need to drop this into a bitmap -*/ -if ((!left_info || left_info->bitmap) && - (!right_info || right_info->bitmap)) { - ret =insert_into_bitmap (block_group, info); - -if (ret <0 ) { - goto out; - }else if (ret) { - ret =0 ; - goto out; - } - } -if (right_info && !right_info->bitmap) {unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); + merged = true; } if (left_info && !left_info->bitmap &&
@@ -668,8 +644,43 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info); + merged = true; } +return merged; +} + +int btrfs_add_free_space (struct btrfs_block_group_cache *block_group, +u64 offset,u64 bytes) +{ +struct btrfs_free_space *info; +int ret =0 ; + + info =kzalloc (sizeof (struct btrfs_free_space ),GFP_NOFS ); +if (!info) +return -ENOMEM ; + + info->offset = offset; + info->bytes = bytes; + +spin_lock (&block_group->tree_lock); + +if (try_merge_free_space (block_group, info)) + goto link; + +/* +* There was no extent directly to the left or right of this new +* extent then we know we're going to have to allocate a new extent, so +* before we do that see if we need to drop this into a bitmap +*/ + ret =insert_into_bitmap (block_group, info); +if (ret <0 ) { + goto out; + }else if (ret) { + ret =0 ; + goto out; + } +link: ret =link_free_space (block_group, info);if (ret)kfree (info);
Signature · 1 line
1.7.0.1
PATCH 6/6 btrfs: check mergeable free space when removing a cluster
In reply to Li ZefanAfter returing extents from a cluster to the block group, some extents in the block group may be mergeable.
--- fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-)
fs/btrfs/free-space-cache.c +20 -6
@@ -234,11 +234,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,return entry; } -static void unlink_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +static inline void +__unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) {rb_erase (&info->offset_index, &block_group->free_space_offset); block_group->free_extents--; +} + +static void unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) +{ +__unlink_free_space (block_group, info); block_group->free_space -= info->bytes; }
@@ -611,7 +618,7 @@ out: }bool try_merge_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +struct btrfs_free_space *info,bool update_stat) {struct btrfs_free_space *left_info;struct btrfs_free_space *right_info;
@@ -632,7 +639,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, left_info =tree_search_offset (block_group, offset -1 ,0 ,0 );if (right_info && !right_info->bitmap) { -unlink_free_space (block_group, right_info); +if (update_stat) +unlink_free_space (block_group, right_info); +else +__unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); merged = true;
@@ -640,7 +650,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { -unlink_free_space (block_group, left_info); +if (update_stat) +unlink_free_space (block_group, left_info); +else +__unlink_free_space (block_group, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info);
@@ -665,7 +678,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,spin_lock (&block_group->tree_lock); -if (try_merge_free_space (block_group, info)) +if (try_merge_free_space (block_group, info, true)) goto link;/*
@@ -883,6 +896,7 @@ __btrfs_return_cluster_to_free_space( node =rb_next (&entry->offset_index);rb_erase (&entry->offset_index, &cluster->root);BUG_ON (entry->bitmap); +try_merge_free_space (block_group, entry, false);tree_insert_offset (&block_group->free_space_offset, entry->offset, &entry->offset_index,0 ); }
Signature · 1 line
1.7.0.1
Re: [PATCH 1/6] btrfs: fix threshold calculation for block groups smaller than 1GB
In reply to Li ZefanQuoted 40 lines · Li Zefan
If a block group is smaller than 1GB, the extent entry threadhold calculation will always set the threshold to 0.
So as free space gets fragmented, btrfs will switch to use bitmap to manage free space, but then will never switch back to extents due to this bug.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-)fs/btrfs/free-space-cache.c +6
-2@@ -263,14 +263,18 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)u64 max_bytes;u64 bitmap_bytes;u64 extent_bytes; +u64 size = block_group->key.offset;/* * The goal is to keep the total amount of memory used per 1gb of space * at or below 32k, so we need to adjust how much memory we allow to be * used by extent based free space tracking */ - max_bytes =MAX_CACHE_BYTES_PER_GIG * - (div64_u64 (block_group->key.offset,1024 *1024 *1024 )); +if (size <1024 *1024 *1024 ) + max_bytes =MAX_CACHE_BYTES_PER_GIG ; +else + max_bytes =MAX_CACHE_BYTES_PER_GIG * +div64_u64 (size,1024 *1024 *1024 );/* * we want to account for 1 more bitmap than what we have so we can make Signature · 1 line
1.7.0.1
Thanks,
Josef
Re: [PATCH 2/6] btrfs: add helper function free_bitmap()
In reply to Li ZefanQuoted 81 lines · Li Zefan
Remove some duplicated code.
This prepares for the next patch.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 37 ++++++++++++++++--------------------- 1 files changed, 16 insertions(+), 21 deletions(-)fs/btrfs/free-space-cache.c +16
-21@@ -422,6 +422,16 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group,recalculate_thresholds (block_group); } +static void free_bitmap (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *bitmap_info) +{ +unlink_free_space (block_group, bitmap_info); +kfree (bitmap_info->bitmap); +kfree (bitmap_info); + block_group->total_bitmaps--; +recalculate_thresholds (block_group); +} + static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,struct btrfs_free_space *bitmap_info,u64 *offset,u64 *bytes)@@ -462,13 +472,8 @@ again:if (*bytes) {struct rb_node *next =rb_next (&bitmap_info->offset_index); -if (!bitmap_info->bytes) { -unlink_free_space (block_group, bitmap_info); -kfree (bitmap_info->bitmap); -kfree (bitmap_info); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } +if (!bitmap_info->bytes) +free_bitmap (block_group, bitmap_info);/* * no entry after this bitmap, but we still have bytes to @@ -501,13 +506,8 @@ again:return -EAGAIN ; goto again; - }else if (!bitmap_info->bytes) { -unlink_free_space (block_group, bitmap_info); -kfree (bitmap_info->bitmap); -kfree (bitmap_info); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } + }else if (!bitmap_info->bytes) +free_bitmap (block_group, bitmap_info);return 0 ; }@@ -936,13 +936,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, ret = offset;if (entry->bitmap) {bitmap_clear_bits (block_group, entry, offset, bytes); -if (!entry->bytes) { -unlink_free_space (block_group, entry); -kfree (entry->bitmap); -kfree (entry); - block_group->total_bitmaps--; -recalculate_thresholds (block_group); - } +if (!entry->bytes) +free_bitmap (block_group, entry); }else {unlink_free_space (block_group, entry); entry->offset += bytes;Signature · 1 line
1.7.0.1
Thanks,
Josef
Re: [PATCH 3/6] btrfs: free fully occupied bitmap in cluster
In reply to Li ZefanQuoted 24 lines · Li Zefan
If there's no more free space in a bitmap, we should free it, otherwise seems it won't get freed until we free the block group.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)fs/btrfs/free-space-cache.c +2
-0@@ -1035,6 +1035,8 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, ret = search_start;bitmap_clear_bits (block_group, entry, ret, bytes); +if (entry->bytes ==0 ) +free_bitmap (block_group, entry); out:spin_unlock (&cluster->lock);spin_unlock (&block_group->tree_lock);Signature · 1 line
1.7.0.1
Oops, good catch
Thanks,
Josef
Re: [PATCH 4/6] btrfs: update stats when allocating from a cluster
In reply to Li ZefanQuoted 29 lines · Li Zefan
When allocating extent entry from a cluster, we should update the
free_spaceandfree_extentsfields of the block group.Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-)fs/btrfs/free-space-cache.c +4
-3@@ -1090,15 +1090,26 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, entry->offset += bytes; entry->bytes -= bytes; -if (entry->bytes ==0 ) { +if (entry->bytes ==0 )rb_erase (&entry->offset_index, &cluster->root); -kfree (entry); - }break ; } out:spin_unlock (&cluster->lock); +if (!ret) +return 0 ; +
fs/btrfs/free-space-cache.c u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, · line 1112
Quoted 10 lines
fs/btrfs/free-space-cache.c +10
-0+spin_lock (&block_group->tree_lock); + + block_group->free_space -= bytes; +if (entry->bytes ==0 ) { + block_group->free_extents--; +kfree (entry); + } + +spin_unlock (&block_group->tree_lock); +
Move this part up so we don't drop the spinlock and then re-grab it. Thanks,
Josef
Re: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
In reply to Li ZefanQuoted 76 lines · Li Zefan
After returing extents from a cluster to the block group, some extents in the block group may be mergeable.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-)fs/btrfs/free-space-cache.c +19
-6@@ -234,11 +234,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,return entry; } -static void unlink_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +static inline void +__unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) {rb_erase (&info->offset_index, &block_group->free_space_offset); block_group->free_extents--; +} + +static void unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) +{ +__unlink_free_space (block_group, info); block_group->free_space -= info->bytes; }@@ -611,7 +618,7 @@ out: }bool try_merge_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +struct btrfs_free_space *info,bool update_stat) {struct btrfs_free_space *left_info;struct btrfs_free_space *right_info;@@ -632,7 +639,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, left_info =tree_search_offset (block_group, offset -1 ,0 ,0 );if (right_info && !right_info->bitmap) { -unlink_free_space (block_group, right_info); +if (update_stat) +unlink_free_space (block_group, right_info); +else +__unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); merged = true;@@ -640,7 +650,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { -unlink_free_space (block_group, left_info); +if (update_stat) +unlink_free_space (block_group, left_info); +else +__unlink_free_space (block_group, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info);@@ -665,7 +678,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,spin_lock (&block_group->tree_lock); -if (try_merge_free_space (block_group, info)) +if (try_merge_free_space (block_group, info, true)) goto link;/*
fs/btrfs/free-space-cache.c __btrfs_return_cluster_to_free_space( · line 901
Quoted 6 lines
fs/btrfs/free-space-cache.c +1
-0@@ -883,6 +896,7 @@ __btrfs_return_cluster_to_free_space( node =rb_next (&entry->offset_index);rb_erase (&entry->offset_index, &cluster->root);BUG_ON (entry->bitmap); +try_merge_free_space (block_group, entry, false);tree_insert_offset (&block_group->free_space_offset, entry->offset, &entry->offset_index,0 );
It's early in the morning here, so forgive me if I'm missing something obvious, but if try_merge_free_space() succeeds here, then won't tree_insert_offset() then add an entry that overlaps the same spot? Should we do something like
merged = try_merge_free_space();
if (!merged)
tree_insert_offset();
? Thanks,
Josef
Re: [PATCH 5/6] btrfs: add a helper try_merge_free_space()
In reply to Li ZefanQuoted 125 lines · Li Zefan
When adding a new extent, we'll firstly see if we can merge this extent to the left or/and right extent. Extract this as a helper
try_merge_free_space().As a side effect, we fix a small bug that if the new extent has non-bitmap left entry but is unmergeble, we'll directly link the extent without trying to drop it into bitmap.
This also prepares for the next patch.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 75 ++++++++++++++++++++++++------------------ 1 files changed, 43 insertions(+), 32 deletions(-)fs/btrfs/free-space-cache.c +43
-32@@ -610,22 +610,14 @@ out:return ret; } -int btrfs_add_free_space (struct btrfs_block_group_cache *block_group, -u64 offset,u64 bytes) +bool try_merge_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) { -struct btrfs_free_space *right_info =NULL ; -struct btrfs_free_space *left_info =NULL ; -struct btrfs_free_space *info =NULL ; -int ret =0 ; - - info =kzalloc (sizeof (struct btrfs_free_space ),GFP_NOFS ); -if (!info) -return -ENOMEM ; - - info->offset = offset; - info->bytes = bytes; - -spin_lock (&block_group->tree_lock); +struct btrfs_free_space *left_info; +struct btrfs_free_space *right_info; +bool merged = false; +u64 offset = info->offset; +u64 bytes = info->bytes;/* * first we want to see if there is free space adjacent to the range we @@ -639,27 +631,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,else left_info =tree_search_offset (block_group, offset -1 ,0 ,0 ); -/* -* If there was no extent directly to the left or right of this new -* extent then we know we're going to have to allocate a new extent, so -* before we do that see if we need to drop this into a bitmap -*/ -if ((!left_info || left_info->bitmap) && - (!right_info || right_info->bitmap)) { - ret =insert_into_bitmap (block_group, info); - -if (ret <0 ) { - goto out; - }else if (ret) { - ret =0 ; - goto out; - } - } -if (right_info && !right_info->bitmap) {unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); + merged = true; } if (left_info && !left_info->bitmap &&@@ -668,8 +644,43 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info); + merged = true; } +return merged; +} + +int btrfs_add_free_space (struct btrfs_block_group_cache *block_group, +u64 offset,u64 bytes) +{ +struct btrfs_free_space *info; +int ret =0 ; + + info =kzalloc (sizeof (struct btrfs_free_space ),GFP_NOFS ); +if (!info) +return -ENOMEM ; + + info->offset = offset; + info->bytes = bytes; + +spin_lock (&block_group->tree_lock); + +if (try_merge_free_space (block_group, info)) + goto link; + +/* +* There was no extent directly to the left or right of this new +* extent then we know we're going to have to allocate a new extent, so +* before we do that see if we need to drop this into a bitmap +*/ + ret =insert_into_bitmap (block_group, info); +if (ret <0 ) { + goto out; + }else if (ret) { + ret =0 ; + goto out; + } +link: ret =link_free_space (block_group, info);if (ret)kfree (info);Signature · 1 line
1.7.0.1
Thanks,
Josef
Re: [PATCH 4/6] btrfs: update stats when allocating from a cluster
In reply to Josef BacikQuoted 18 lines
Quoted 5 lines
fs/btrfs/free-space-cache.c +3
-0spin_unlock (&cluster->lock); +if (!ret) +return 0 ; +fs/btrfs/free-space-cache.c u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, · line 1112
Quoted 10 lines
fs/btrfs/free-space-cache.c +10
-0+spin_lock (&block_group->tree_lock); + + block_group->free_space -= bytes; +if (entry->bytes ==0 ) { + block_group->free_extents--; +kfree (entry); + } + +spin_unlock (&block_group->tree_lock); +Move this part up so we don't drop the spinlock and then re-grab it. Thanks,
But they are 2 different locks. ;)
And we can't grab block_group->tree_lock when holding cluster->lock.
Re: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
In reply to Josef BacikQuoted 88 lines · Josef Bacik
Quoted 76 lines · Li Zefan
After returing extents from a cluster to the block group, some extents in the block group may be mergeable.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-)fs/btrfs/free-space-cache.c +19
-6@@ -234,11 +234,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,return entry; } -static void unlink_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +static inline void +__unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) {rb_erase (&info->offset_index, &block_group->free_space_offset); block_group->free_extents--; +} + +static void unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) +{ +__unlink_free_space (block_group, info); block_group->free_space -= info->bytes; }@@ -611,7 +618,7 @@ out: }bool try_merge_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +struct btrfs_free_space *info,bool update_stat) {struct btrfs_free_space *left_info;struct btrfs_free_space *right_info;@@ -632,7 +639,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, left_info =tree_search_offset (block_group, offset -1 ,0 ,0 );if (right_info && !right_info->bitmap) { -unlink_free_space (block_group, right_info); +if (update_stat) +unlink_free_space (block_group, right_info); +else +__unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); merged = true;@@ -640,7 +650,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { -unlink_free_space (block_group, left_info); +if (update_stat) +unlink_free_space (block_group, left_info); +else +__unlink_free_space (block_group, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info);@@ -665,7 +678,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,spin_lock (&block_group->tree_lock); -if (try_merge_free_space (block_group, info)) +if (try_merge_free_space (block_group, info, true)) goto link;/* fs/btrfs/free-space-cache.c __btrfs_return_cluster_to_free_space( · line 901
Quoted 6 lines
fs/btrfs/free-space-cache.c +1
-0@@ -883,6 +896,7 @@ __btrfs_return_cluster_to_free_space( node =rb_next (&entry->offset_index);rb_erase (&entry->offset_index, &cluster->root);BUG_ON (entry->bitmap); +try_merge_free_space (block_group, entry, false);tree_insert_offset (&block_group->free_space_offset, entry->offset, &entry->offset_index,0 );It's early in the morning here, so forgive me if I'm missing something obvious, but if
try_merge_free_space()succeeds here, then won'ttree_insert_offset()then add an entry that overlaps the same spot? Should we do something like
Quoted 6 lines
merged =
try_merge_free_space();
if (!merged)tree_insert_offset();? Thanks,
In try_merge_free_space() we try to merge the left and right entry into @entry, and then the caller has to insert the @entry into the tree by itself.
Similarly, In btrfs_add_free_space() we call link_free_space() no matter try_merge_free_space() returns success or not.
Josef Bacik
Reviewed-byRe: [PATCH 4/6] btrfs: update stats when allocating from a cluster
In reply to Li ZefanQuoted 19 lines · Li Zefan
Quoted 18 lines
Quoted 5 lines
fs/btrfs/free-space-cache.c +3
-0spin_unlock (&cluster->lock); +if (!ret) +return 0 ; +fs/btrfs/free-space-cache.c u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, · line 1112
Quoted 10 lines
fs/btrfs/free-space-cache.c +10
-0+spin_lock (&block_group->tree_lock); + + block_group->free_space -= bytes; +if (entry->bytes ==0 ) { + block_group->free_extents--; +kfree (entry); + } + +spin_unlock (&block_group->tree_lock); +Move this part up so we don't drop the spinlock and then re-grab it. Thanks,
Quoted 3 lines
But they are 2 different locks. ;)
And we can't grab
block_group->tree_lockwhen holdingcluster->lock.
Ugh Jesus sorry, ignore me.
Thanks,
Josef
Josef Bacik
Reviewed-byRe: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
In reply to Li ZefanQuoted 96 lines · Li Zefan
Quoted 88 lines · Josef Bacik
Quoted 76 lines · Li Zefan
After returing extents from a cluster to the block group, some extents in the block group may be mergeable.
Signed-off-by Li Zefan <[email protected]>--- fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-)fs/btrfs/free-space-cache.c +19
-6@@ -234,11 +234,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,return entry; } -static void unlink_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +static inline void +__unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) {rb_erase (&info->offset_index, &block_group->free_space_offset); block_group->free_extents--; +} + +static void unlink_free_space (struct btrfs_block_group_cache *block_group, +struct btrfs_free_space *info) +{ +__unlink_free_space (block_group, info); block_group->free_space -= info->bytes; }@@ -611,7 +618,7 @@ out: }bool try_merge_free_space (struct btrfs_block_group_cache *block_group, -struct btrfs_free_space *info) +struct btrfs_free_space *info,bool update_stat) {struct btrfs_free_space *left_info;struct btrfs_free_space *right_info;@@ -632,7 +639,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, left_info =tree_search_offset (block_group, offset -1 ,0 ,0 );if (right_info && !right_info->bitmap) { -unlink_free_space (block_group, right_info); +if (update_stat) +unlink_free_space (block_group, right_info); +else +__unlink_free_space (block_group, right_info); info->bytes += right_info->bytes;kfree (right_info); merged = true;@@ -640,7 +650,10 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group,if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { -unlink_free_space (block_group, left_info); +if (update_stat) +unlink_free_space (block_group, left_info); +else +__unlink_free_space (block_group, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes;kfree (left_info);@@ -665,7 +678,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,spin_lock (&block_group->tree_lock); -if (try_merge_free_space (block_group, info)) +if (try_merge_free_space (block_group, info, true)) goto link;/* fs/btrfs/free-space-cache.c __btrfs_return_cluster_to_free_space( · line 901
Quoted 6 lines
fs/btrfs/free-space-cache.c +1
-0@@ -883,6 +896,7 @@ __btrfs_return_cluster_to_free_space( node =rb_next (&entry->offset_index);rb_erase (&entry->offset_index, &cluster->root);BUG_ON (entry->bitmap); +try_merge_free_space (block_group, entry, false);tree_insert_offset (&block_group->free_space_offset, entry->offset, &entry->offset_index,0 );It's early in the morning here, so forgive me if I'm missing something obvious, but if
try_merge_free_space()succeeds here, then won'ttree_insert_offset()then add an entry that overlaps the same spot? Should we do something likeQuoted 6 lines
merged =
try_merge_free_space();
if (!merged)tree_insert_offset();? Thanks,
Quoted 6 lines
In
try_merge_free_space()we try to merge the left and right entry into @entry, and then the caller has to insert the @entry into the tree by itself.Similarly, In
btrfs_add_free_space()we calllink_free_space()no mattertry_merge_free_space()returns success or not.
Ah ok I see now, thanks.
Thanks,
Josef