mirror of https://gitee.com/openkylin/linux.git
btrfs: Refactor clustered extent allocation into find_free_extent_clustered
We have two main methods to find free extents inside a block group: 1) clustered allocation 2) unclustered allocation This patch will extract the clustered allocation into find_free_extent_clustered() to make it a little easier to read. Instead of jumping between different labels in find_free_extent(), the helper function will use return value to indicate different behavior. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
b4bd745d12
commit
d06e3bb690
|
@ -7305,6 +7305,116 @@ struct find_free_extent_ctl {
|
|||
u64 found_offset;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Helper function for find_free_extent().
|
||||
*
|
||||
* Return -ENOENT to inform caller that we need fallback to unclustered mode.
|
||||
* Return -EAGAIN to inform caller that we need to re-search this block group
|
||||
* Return >0 to inform caller that we find nothing
|
||||
* Return 0 means we have found a location and set ffe_ctl->found_offset.
|
||||
*/
|
||||
static int find_free_extent_clustered(struct btrfs_block_group_cache *bg,
|
||||
struct btrfs_free_cluster *last_ptr,
|
||||
struct find_free_extent_ctl *ffe_ctl,
|
||||
struct btrfs_block_group_cache **cluster_bg_ret)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = bg->fs_info;
|
||||
struct btrfs_block_group_cache *cluster_bg;
|
||||
u64 aligned_cluster;
|
||||
u64 offset;
|
||||
int ret;
|
||||
|
||||
cluster_bg = btrfs_lock_cluster(bg, last_ptr, ffe_ctl->delalloc);
|
||||
if (!cluster_bg)
|
||||
goto refill_cluster;
|
||||
if (cluster_bg != bg && (cluster_bg->ro ||
|
||||
!block_group_bits(cluster_bg, ffe_ctl->flags)))
|
||||
goto release_cluster;
|
||||
|
||||
offset = btrfs_alloc_from_cluster(cluster_bg, last_ptr,
|
||||
ffe_ctl->num_bytes, cluster_bg->key.objectid,
|
||||
&ffe_ctl->max_extent_size);
|
||||
if (offset) {
|
||||
/* We have a block, we're done */
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
trace_btrfs_reserve_extent_cluster(cluster_bg,
|
||||
ffe_ctl->search_start, ffe_ctl->num_bytes);
|
||||
*cluster_bg_ret = cluster_bg;
|
||||
ffe_ctl->found_offset = offset;
|
||||
return 0;
|
||||
}
|
||||
WARN_ON(last_ptr->block_group != cluster_bg);
|
||||
|
||||
release_cluster:
|
||||
/*
|
||||
* If we are on LOOP_NO_EMPTY_SIZE, we can't set up a new clusters, so
|
||||
* lets just skip it and let the allocator find whatever block it can
|
||||
* find. If we reach this point, we will have tried the cluster
|
||||
* allocator plenty of times and not have found anything, so we are
|
||||
* likely way too fragmented for the clustering stuff to find anything.
|
||||
*
|
||||
* However, if the cluster is taken from the current block group,
|
||||
* release the cluster first, so that we stand a better chance of
|
||||
* succeeding in the unclustered allocation.
|
||||
*/
|
||||
if (ffe_ctl->loop >= LOOP_NO_EMPTY_SIZE && cluster_bg != bg) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
btrfs_release_block_group(cluster_bg, ffe_ctl->delalloc);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* This cluster didn't work out, free it and start over */
|
||||
btrfs_return_cluster_to_free_space(NULL, last_ptr);
|
||||
|
||||
if (cluster_bg != bg)
|
||||
btrfs_release_block_group(cluster_bg, ffe_ctl->delalloc);
|
||||
|
||||
refill_cluster:
|
||||
if (ffe_ctl->loop >= LOOP_NO_EMPTY_SIZE) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
aligned_cluster = max_t(u64,
|
||||
ffe_ctl->empty_cluster + ffe_ctl->empty_size,
|
||||
bg->full_stripe_len);
|
||||
ret = btrfs_find_space_cluster(fs_info, bg, last_ptr,
|
||||
ffe_ctl->search_start, ffe_ctl->num_bytes,
|
||||
aligned_cluster);
|
||||
if (ret == 0) {
|
||||
/* Now pull our allocation out of this cluster */
|
||||
offset = btrfs_alloc_from_cluster(bg, last_ptr,
|
||||
ffe_ctl->num_bytes, ffe_ctl->search_start,
|
||||
&ffe_ctl->max_extent_size);
|
||||
if (offset) {
|
||||
/* We found one, proceed */
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
trace_btrfs_reserve_extent_cluster(bg,
|
||||
ffe_ctl->search_start,
|
||||
ffe_ctl->num_bytes);
|
||||
ffe_ctl->found_offset = offset;
|
||||
return 0;
|
||||
}
|
||||
} else if (!ffe_ctl->cached && ffe_ctl->loop > LOOP_CACHING_NOWAIT &&
|
||||
!ffe_ctl->retry_clustered) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
|
||||
ffe_ctl->retry_clustered = true;
|
||||
wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +
|
||||
ffe_ctl->empty_cluster + ffe_ctl->empty_size);
|
||||
return -EAGAIN;
|
||||
}
|
||||
/*
|
||||
* At this point we either didn't find a cluster or we weren't able to
|
||||
* allocate a block from our cluster. Free the cluster we've been
|
||||
* trying to use, and go to the next block group.
|
||||
*/
|
||||
btrfs_return_cluster_to_free_space(NULL, last_ptr);
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* walks the btree of allocated extents and find a hole of a given size.
|
||||
* The key ins is changed to record the hole:
|
||||
|
@ -7487,137 +7597,26 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
|
|||
* lets look there
|
||||
*/
|
||||
if (last_ptr && use_cluster) {
|
||||
struct btrfs_block_group_cache *used_block_group;
|
||||
unsigned long aligned_cluster;
|
||||
/*
|
||||
* the refill lock keeps out other
|
||||
* people trying to start a new cluster
|
||||
*/
|
||||
used_block_group = btrfs_lock_cluster(block_group,
|
||||
last_ptr,
|
||||
delalloc);
|
||||
if (!used_block_group)
|
||||
goto refill_cluster;
|
||||
struct btrfs_block_group_cache *cluster_bg = NULL;
|
||||
|
||||
if (used_block_group != block_group &&
|
||||
(used_block_group->ro ||
|
||||
!block_group_bits(used_block_group,
|
||||
ffe_ctl.flags)))
|
||||
goto release_cluster;
|
||||
ret = find_free_extent_clustered(block_group, last_ptr,
|
||||
&ffe_ctl, &cluster_bg);
|
||||
|
||||
ffe_ctl.found_offset = btrfs_alloc_from_cluster(
|
||||
used_block_group,
|
||||
last_ptr,
|
||||
num_bytes,
|
||||
used_block_group->key.objectid,
|
||||
&ffe_ctl.max_extent_size);
|
||||
if (ffe_ctl.found_offset) {
|
||||
/* we have a block, we're done */
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
trace_btrfs_reserve_extent_cluster(
|
||||
used_block_group,
|
||||
ffe_ctl.search_start,
|
||||
num_bytes);
|
||||
if (used_block_group != block_group) {
|
||||
if (ret == 0) {
|
||||
if (cluster_bg && cluster_bg != block_group) {
|
||||
btrfs_release_block_group(block_group,
|
||||
delalloc);
|
||||
block_group = used_block_group;
|
||||
block_group = cluster_bg;
|
||||
}
|
||||
goto checks;
|
||||
}
|
||||
|
||||
WARN_ON(last_ptr->block_group != used_block_group);
|
||||
release_cluster:
|
||||
/* If we are on LOOP_NO_EMPTY_SIZE, we can't
|
||||
* set up a new clusters, so lets just skip it
|
||||
* and let the allocator find whatever block
|
||||
* it can find. If we reach this point, we
|
||||
* will have tried the cluster allocator
|
||||
* plenty of times and not have found
|
||||
* anything, so we are likely way too
|
||||
* fragmented for the clustering stuff to find
|
||||
* anything.
|
||||
*
|
||||
* However, if the cluster is taken from the
|
||||
* current block group, release the cluster
|
||||
* first, so that we stand a better chance of
|
||||
* succeeding in the unclustered
|
||||
* allocation. */
|
||||
if (ffe_ctl.loop >= LOOP_NO_EMPTY_SIZE &&
|
||||
used_block_group != block_group) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
btrfs_release_block_group(used_block_group,
|
||||
delalloc);
|
||||
goto unclustered_alloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* this cluster didn't work out, free it and
|
||||
* start over
|
||||
*/
|
||||
btrfs_return_cluster_to_free_space(NULL, last_ptr);
|
||||
|
||||
if (used_block_group != block_group)
|
||||
btrfs_release_block_group(used_block_group,
|
||||
delalloc);
|
||||
refill_cluster:
|
||||
if (ffe_ctl.loop >= LOOP_NO_EMPTY_SIZE) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
goto unclustered_alloc;
|
||||
}
|
||||
|
||||
aligned_cluster = max_t(unsigned long,
|
||||
ffe_ctl.empty_cluster + empty_size,
|
||||
block_group->full_stripe_len);
|
||||
|
||||
/* allocate a cluster in this block group */
|
||||
ret = btrfs_find_space_cluster(fs_info, block_group,
|
||||
last_ptr,
|
||||
ffe_ctl.search_start,
|
||||
num_bytes,
|
||||
aligned_cluster);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* now pull our allocation out of this
|
||||
* cluster
|
||||
*/
|
||||
ffe_ctl.found_offset = btrfs_alloc_from_cluster(
|
||||
block_group, last_ptr,
|
||||
num_bytes, ffe_ctl.search_start,
|
||||
&ffe_ctl.max_extent_size);
|
||||
if (ffe_ctl.found_offset) {
|
||||
/* we found one, proceed */
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
trace_btrfs_reserve_extent_cluster(
|
||||
block_group,
|
||||
ffe_ctl.search_start,
|
||||
num_bytes);
|
||||
goto checks;
|
||||
}
|
||||
} else if (!ffe_ctl.cached &&
|
||||
ffe_ctl.loop > LOOP_CACHING_NOWAIT &&
|
||||
!ffe_ctl.retry_clustered) {
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
|
||||
ffe_ctl.retry_clustered = true;
|
||||
wait_block_group_cache_progress(block_group,
|
||||
num_bytes + ffe_ctl.empty_cluster +
|
||||
empty_size);
|
||||
} else if (ret == -EAGAIN) {
|
||||
goto have_block_group;
|
||||
} else if (ret > 0) {
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* at this point we either didn't find a cluster
|
||||
* or we weren't able to allocate a block from our
|
||||
* cluster. Free the cluster we've been trying
|
||||
* to use, and go to the next block group
|
||||
*/
|
||||
btrfs_return_cluster_to_free_space(NULL, last_ptr);
|
||||
spin_unlock(&last_ptr->refill_lock);
|
||||
goto loop;
|
||||
/* ret == -ENOENT case falls through */
|
||||
}
|
||||
|
||||
unclustered_alloc:
|
||||
/*
|
||||
* We are doing an unclustered alloc, set the fragmented flag so
|
||||
* we don't bother trying to setup a cluster again until we get
|
||||
|
|
Loading…
Reference in New Issue