From 84a7949d409753c90dc3477b8cfc18e983b09078 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 11 Oct 2022 13:17:03 +0100 Subject: [PATCH] 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 Signed-off-by: David Sterba --- fs/btrfs/backref.c | 43 ++++++++++++++++++++++++++++++++----------- fs/btrfs/backref.h | 7 ++++++- fs/btrfs/extent_io.c | 34 ++++++++++------------------------ 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 693c99a..4caff30 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -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; } diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h index e3a2b45..8da0ba6 100644 --- a/fs/btrfs/backref.h +++ b/fs/btrfs/backref.h @@ -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); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 365ad00..e25e54d 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -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; } -- 2.7.4