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(-)
Li Zefan
2010-Aug-23 01:22 UTC
[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. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f488fac..7edbef6 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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 -- 1.7.0.1
Remove some duplicated code. This prepares for the next patch. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 37 ++++++++++++++++--------------------- 1 files changed, 16 insertions(+), 21 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 7edbef6..017fd55 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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; -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 017fd55..631e14f 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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); -- 1.7.0.1
Li Zefan
2010-Aug-23 01:23 UTC
[PATCH 4/6] btrfs: update stats when allocating from a cluster
When allocating extent entry from a cluster, we should update the free_space and free_extents fields of the block group. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 631e14f..20f3141 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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; } -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 75 ++++++++++++++++++++++++------------------ 1 files changed, 43 insertions(+), 32 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 20f3141..faeec8f 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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); -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Li Zefan
2010-Aug-23 01:24 UTC
[PATCH 6/6] btrfs: check mergeable free space when removing a cluster
After returing extents from a cluster to the block group, some extents in the block group may be mergeable. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> --- fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ 1 files changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index faeec8f..c11f4f7 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -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); } -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Josef Bacik
2010-Aug-23 13:02 UTC
Re: [PATCH 1/6] btrfs: fix threshold calculation for block groups smaller than 1GB
On Mon, Aug 23, 2010 at 09:22:40AM +0800, Li Zefan wrote:> 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 <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 8 ++++++-- > 1 files changed, 6 insertions(+), 2 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index f488fac..7edbef6 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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 > -- > 1.7.0.1 >Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Josef Bacik
2010-Aug-23 13:03 UTC
Re: [PATCH 2/6] btrfs: add helper function free_bitmap()
On Mon, Aug 23, 2010 at 09:23:01AM +0800, Li Zefan wrote:> Remove some duplicated code. > > This prepares for the next patch. > > Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 37 ++++++++++++++++--------------------- > 1 files changed, 16 insertions(+), 21 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index 7edbef6..017fd55 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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; > -- > 1.7.0.1 >Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef
Josef Bacik
2010-Aug-23 13:04 UTC
Re: [PATCH 3/6] btrfs: free fully occupied bitmap in cluster
On Mon, Aug 23, 2010 at 09:23:16AM +0800, Li Zefan wrote:> 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 <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 2 ++ > 1 files changed, 2 insertions(+), 0 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index 017fd55..631e14f 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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); > -- > 1.7.0.1 >Oops, good catch Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Josef Bacik
2010-Aug-23 13:09 UTC
Re: [PATCH 4/6] btrfs: update stats when allocating from a cluster
On Mon, Aug 23, 2010 at 09:23:29AM +0800, Li Zefan wrote:> When allocating extent entry from a cluster, we should update > the free_space and free_extents fields of the block group. > > Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 17 ++++++++++++++--- > 1 files changed, 14 insertions(+), 3 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index 631e14f..20f3141 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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); > +Move this part up so we don''t drop the spinlock and then re-grab it. Thanks, Josef
Josef Bacik
2010-Aug-23 13:15 UTC
Re: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
On Mon, Aug 23, 2010 at 09:24:07AM +0800, Li Zefan wrote:> After returing extents from a cluster to the block group, some > extents in the block group may be mergeable. > > Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ > 1 files changed, 20 insertions(+), 6 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index faeec8f..c11f4f7 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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);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
Josef Bacik
2010-Aug-23 13:15 UTC
Re: [PATCH 5/6] btrfs: add a helper try_merge_free_space()
On Mon, Aug 23, 2010 at 09:23:44AM +0800, Li Zefan wrote:> 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 <lizf@cn.fujitsu.com> > --- > fs/btrfs/free-space-cache.c | 75 ++++++++++++++++++++++++------------------ > 1 files changed, 43 insertions(+), 32 deletions(-) > > diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > index 20f3141..faeec8f 100644 > --- a/fs/btrfs/free-space-cache.c > +++ b/fs/btrfs/free-space-cache.c > @@ -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); > -- > 1.7.0.1 >Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef
Li Zefan
2010-Aug-24 00:50 UTC
Re: [PATCH 4/6] btrfs: update stats when allocating from a cluster
>> 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); >> + > > 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. -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Li Zefan
2010-Aug-24 01:04 UTC
Re: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
Josef Bacik wrote:> On Mon, Aug 23, 2010 at 09:24:07AM +0800, Li Zefan wrote: >> After returing extents from a cluster to the block group, some >> extents in the block group may be mergeable. >> >> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> >> --- >> fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ >> 1 files changed, 20 insertions(+), 6 deletions(-) >> >> diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c >> index faeec8f..c11f4f7 100644 >> --- a/fs/btrfs/free-space-cache.c >> +++ b/fs/btrfs/free-space-cache.c >> @@ -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); > > 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, >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
2010-Aug-24 02:50 UTC
Re: [PATCH 4/6] btrfs: update stats when allocating from a cluster
On Tue, Aug 24, 2010 at 08:50:57AM +0800, Li Zefan wrote:> >> 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); > >> + > > > > 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.Ugh Jesus sorry, ignore me. Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Josef Bacik
2010-Aug-24 02:58 UTC
Re: [PATCH 6/6] btrfs: check mergeable free space when removing a cluster
On Tue, Aug 24, 2010 at 09:04:13AM +0800, Li Zefan wrote:> Josef Bacik wrote: > > On Mon, Aug 23, 2010 at 09:24:07AM +0800, Li Zefan wrote: > >> After returing extents from a cluster to the block group, some > >> extents in the block group may be mergeable. > >> > >> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> > >> --- > >> fs/btrfs/free-space-cache.c | 26 ++++++++++++++++++++------ > >> 1 files changed, 20 insertions(+), 6 deletions(-) > >> > >> diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c > >> index faeec8f..c11f4f7 100644 > >> --- a/fs/btrfs/free-space-cache.c > >> +++ b/fs/btrfs/free-space-cache.c > >> @@ -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); > > > > 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, > > > > 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.Ah ok I see now, thanks. Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html