btrfs: move ulists to data extent sharedness check context
When calling btrfs_is_data_extent_shared() we pass two ulists that were allocated by the caller. This is because the single caller, fiemap, calls btrfs_is_data_extent_shared() multiple times and the ulists can be reused, instead of allocating new ones before each call and freeing them after each call. Now that we have a context structure/object that we pass to btrfs_is_data_extent_shared(), we can move those ulists to it, and hide their allocation and the context's allocation in a helper function, as well as the freeing of the ulists and the context object. This allows to reduce the number of parameters passed to btrfs_is_data_extent_shared(), the need to pass the ulists from extent_fiemap() to fiemap_process_hole() and having the caller deal with allocating and releasing the ulists. Also rename one of the ulists from 'tmp' / 'tmp_ulist' to 'refs', since that's a much better name as it reflects what the list is used for (and matching the argument name for find_parent_nodes()). Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
61dbb952f0
commit
84a7949d40
@ -1655,6 +1655,30 @@ static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx
|
||||
}
|
||||
}
|
||||
|
||||
struct btrfs_backref_share_check_ctx *btrfs_alloc_backref_share_check_ctx(void)
|
||||
{
|
||||
struct btrfs_backref_share_check_ctx *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ulist_init(&ctx->refs);
|
||||
ulist_init(&ctx->roots);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void btrfs_free_backref_share_ctx(struct btrfs_backref_share_check_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
ulist_release(&ctx->refs);
|
||||
ulist_release(&ctx->roots);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a data extent is shared or not.
|
||||
*
|
||||
@ -1662,8 +1686,6 @@ static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx
|
||||
* @bytenr: Logical bytenr of the extent we are checking.
|
||||
* @extent_gen: Generation of the extent (file extent item) or 0 if it is
|
||||
* not known.
|
||||
* @roots: List of roots this extent is shared among.
|
||||
* @tmp: Temporary list used for iteration.
|
||||
* @ctx: A backref sharedness check context.
|
||||
*
|
||||
* btrfs_is_data_extent_shared uses the backref walking code but will short
|
||||
@ -1679,7 +1701,6 @@ static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx
|
||||
*/
|
||||
int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
u64 extent_gen,
|
||||
struct ulist *roots, struct ulist *tmp,
|
||||
struct btrfs_backref_share_check_ctx *ctx)
|
||||
{
|
||||
struct btrfs_root *root = inode->root;
|
||||
@ -1697,8 +1718,8 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
};
|
||||
int level;
|
||||
|
||||
ulist_init(roots);
|
||||
ulist_init(tmp);
|
||||
ulist_init(&ctx->roots);
|
||||
ulist_init(&ctx->refs);
|
||||
|
||||
trans = btrfs_join_transaction_nostart(root);
|
||||
if (IS_ERR(trans)) {
|
||||
@ -1720,8 +1741,8 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
bool is_shared;
|
||||
bool cached;
|
||||
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp,
|
||||
roots, NULL, &shared, false);
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, &ctx->refs,
|
||||
&ctx->roots, NULL, &shared, false);
|
||||
if (ret == BACKREF_FOUND_SHARED) {
|
||||
/* this is the only condition under which we return 1 */
|
||||
ret = 1;
|
||||
@ -1760,13 +1781,13 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
* deal with), we can not use it if we have multiple leaves
|
||||
* (which implies multiple paths).
|
||||
*/
|
||||
if (level == -1 && tmp->nnodes > 1)
|
||||
if (level == -1 && ctx->refs.nnodes > 1)
|
||||
ctx->use_path_cache = false;
|
||||
|
||||
if (level >= 0)
|
||||
store_backref_shared_cache(ctx, root, bytenr,
|
||||
level, false);
|
||||
node = ulist_next(tmp, &uiter);
|
||||
node = ulist_next(&ctx->refs, &uiter);
|
||||
if (!node)
|
||||
break;
|
||||
bytenr = node->val;
|
||||
@ -1789,8 +1810,8 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
up_read(&fs_info->commit_root_sem);
|
||||
}
|
||||
out:
|
||||
ulist_release(roots);
|
||||
ulist_release(tmp);
|
||||
ulist_release(&ctx->roots);
|
||||
ulist_release(&ctx->refs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,9 @@ struct btrfs_backref_shared_cache_entry {
|
||||
};
|
||||
|
||||
struct btrfs_backref_share_check_ctx {
|
||||
/* Ulists used during backref walking. */
|
||||
struct ulist refs;
|
||||
struct ulist roots;
|
||||
/*
|
||||
* A path from a root to a leaf that has a file extent item pointing to
|
||||
* a given data extent should never exceed the maximum b+tree height.
|
||||
@ -35,6 +38,9 @@ struct btrfs_backref_share_check_ctx {
|
||||
typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
|
||||
void *ctx);
|
||||
|
||||
struct btrfs_backref_share_check_ctx *btrfs_alloc_backref_share_check_ctx(void);
|
||||
void btrfs_free_backref_share_ctx(struct btrfs_backref_share_check_ctx *ctx);
|
||||
|
||||
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
||||
struct btrfs_path *path, struct btrfs_key *found_key,
|
||||
u64 *flags);
|
||||
@ -79,7 +85,6 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
|
||||
u64 *found_off);
|
||||
int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
|
||||
u64 extent_gen,
|
||||
struct ulist *roots, struct ulist *tmp,
|
||||
struct btrfs_backref_share_check_ctx *ctx);
|
||||
|
||||
int __init btrfs_prelim_ref_init(void);
|
||||
|
@ -3708,7 +3708,6 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
|
||||
struct btrfs_backref_share_check_ctx *backref_ctx,
|
||||
u64 disk_bytenr, u64 extent_offset,
|
||||
u64 extent_gen,
|
||||
struct ulist *roots, struct ulist *tmp_ulist,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
const u64 i_size = i_size_read(&inode->vfs_inode);
|
||||
@ -3752,10 +3751,9 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
|
||||
if (prealloc_len > 0) {
|
||||
if (!checked_extent_shared && fieinfo->fi_extents_max) {
|
||||
ret = btrfs_is_data_extent_shared(inode,
|
||||
disk_bytenr,
|
||||
extent_gen, roots,
|
||||
tmp_ulist,
|
||||
backref_ctx);
|
||||
disk_bytenr,
|
||||
extent_gen,
|
||||
backref_ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret > 0)
|
||||
@ -3803,8 +3801,7 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
|
||||
if (!checked_extent_shared && fieinfo->fi_extents_max) {
|
||||
ret = btrfs_is_data_extent_shared(inode,
|
||||
disk_bytenr,
|
||||
extent_gen, roots,
|
||||
tmp_ulist,
|
||||
extent_gen,
|
||||
backref_ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -3905,8 +3902,6 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
struct btrfs_path *path;
|
||||
struct fiemap_cache cache = { 0 };
|
||||
struct btrfs_backref_share_check_ctx *backref_ctx;
|
||||
struct ulist *roots;
|
||||
struct ulist *tmp_ulist;
|
||||
u64 last_extent_end;
|
||||
u64 prev_extent_end;
|
||||
u64 lockstart;
|
||||
@ -3914,11 +3909,9 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
bool stopped = false;
|
||||
int ret;
|
||||
|
||||
backref_ctx = kzalloc(sizeof(*backref_ctx), GFP_KERNEL);
|
||||
backref_ctx = btrfs_alloc_backref_share_check_ctx();
|
||||
path = btrfs_alloc_path();
|
||||
roots = ulist_alloc(GFP_KERNEL);
|
||||
tmp_ulist = ulist_alloc(GFP_KERNEL);
|
||||
if (!backref_ctx || !path || !roots || !tmp_ulist) {
|
||||
if (!backref_ctx || !path) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -3979,7 +3972,6 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
|
||||
ret = fiemap_process_hole(inode, fieinfo, &cache,
|
||||
backref_ctx, 0, 0, 0,
|
||||
roots, tmp_ulist,
|
||||
prev_extent_end, range_end);
|
||||
if (ret < 0) {
|
||||
goto out_unlock;
|
||||
@ -4021,13 +4013,12 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
ret = fiemap_process_hole(inode, fieinfo, &cache,
|
||||
backref_ctx,
|
||||
disk_bytenr, extent_offset,
|
||||
extent_gen, roots, tmp_ulist,
|
||||
key.offset, extent_end - 1);
|
||||
extent_gen, key.offset,
|
||||
extent_end - 1);
|
||||
} else if (disk_bytenr == 0) {
|
||||
/* We have an explicit hole. */
|
||||
ret = fiemap_process_hole(inode, fieinfo, &cache,
|
||||
backref_ctx, 0, 0, 0,
|
||||
roots, tmp_ulist,
|
||||
key.offset, extent_end - 1);
|
||||
} else {
|
||||
/* We have a regular extent. */
|
||||
@ -4035,8 +4026,6 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
ret = btrfs_is_data_extent_shared(inode,
|
||||
disk_bytenr,
|
||||
extent_gen,
|
||||
roots,
|
||||
tmp_ulist,
|
||||
backref_ctx);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
@ -4087,8 +4076,7 @@ check_eof_delalloc:
|
||||
|
||||
if (!stopped && prev_extent_end < lockend) {
|
||||
ret = fiemap_process_hole(inode, fieinfo, &cache, backref_ctx,
|
||||
0, 0, 0, roots, tmp_ulist,
|
||||
prev_extent_end, lockend - 1);
|
||||
0, 0, 0, prev_extent_end, lockend - 1);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
prev_extent_end = lockend;
|
||||
@ -4119,10 +4107,8 @@ check_eof_delalloc:
|
||||
out_unlock:
|
||||
unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
|
||||
out:
|
||||
kfree(backref_ctx);
|
||||
btrfs_free_backref_share_ctx(backref_ctx);
|
||||
btrfs_free_path(path);
|
||||
ulist_free(roots);
|
||||
ulist_free(tmp_ulist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user