mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
btrfs: send: always use the rbtree based inode ref management infrastructure
After the patch "btrfs: send: fix sending link commands for existing file paths", we now have two infrastructures to detect and eliminate duplicated inode references (due to names that got removed and re-added between the send and parent snapshots): 1) One that works on a single inode ref/extref item; 2) A new one that works acrosss all ref/extref items for an inode, and it's also more efficient because even in the single ref/extref item case, it does not do a linear search for all the names encoded in the ref/extref item, it uses red black trees to speedup up the search. There's no good reason to keep both infrastructures, we can use the new one everywhere, and it's always more efficient. So remove the old infrastructure and change all sites that are using it to use the new one. Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
3aa5bd367f
commit
0d8869fb6b
193
fs/btrfs/send.c
193
fs/btrfs/send.c
@ -2195,7 +2195,7 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
|
||||
/*
|
||||
* If the inode is not existent yet, add the orphan name and return 1.
|
||||
* This should only happen for the parent dir that we determine in
|
||||
* __record_new_ref
|
||||
* record_new_ref_if_needed().
|
||||
*/
|
||||
ret = is_inode_existent(sctx, ino, gen);
|
||||
if (ret < 0)
|
||||
@ -2830,27 +2830,6 @@ static void set_ref_path(struct recorded_ref *ref, struct fs_path *path)
|
||||
ref->name_len = ref->full_path->end - ref->name;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process new refs before deleted refs, but compare_tree gives us
|
||||
* everything mixed. So we first record all refs and later process them.
|
||||
* This function is a helper to record one ref.
|
||||
*/
|
||||
static int __record_ref(struct list_head *head, u64 dir,
|
||||
u64 dir_gen, struct fs_path *path)
|
||||
{
|
||||
struct recorded_ref *ref;
|
||||
|
||||
ref = recorded_ref_alloc();
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
|
||||
ref->dir = dir;
|
||||
ref->dir_gen = dir_gen;
|
||||
set_ref_path(ref, path);
|
||||
list_add_tail(&ref->list, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dup_ref(struct recorded_ref *ref, struct list_head *list)
|
||||
{
|
||||
struct recorded_ref *new;
|
||||
@ -4377,55 +4356,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int record_ref(struct btrfs_root *root, u64 dir, struct fs_path *name,
|
||||
void *ctx, struct list_head *refs)
|
||||
{
|
||||
int ret = 0;
|
||||
struct send_ctx *sctx = ctx;
|
||||
struct fs_path *p;
|
||||
u64 gen;
|
||||
|
||||
p = fs_path_alloc();
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = get_cur_path(sctx, dir, gen, p);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = fs_path_add_path(p, name);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = __record_ref(refs, dir, gen, p);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
fs_path_free(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __record_new_ref(int num, u64 dir, int index,
|
||||
struct fs_path *name,
|
||||
void *ctx)
|
||||
{
|
||||
struct send_ctx *sctx = ctx;
|
||||
return record_ref(sctx->send_root, dir, name, ctx, &sctx->new_refs);
|
||||
}
|
||||
|
||||
|
||||
static int __record_deleted_ref(int num, u64 dir, int index,
|
||||
struct fs_path *name,
|
||||
void *ctx)
|
||||
{
|
||||
struct send_ctx *sctx = ctx;
|
||||
return record_ref(sctx->parent_root, dir, name, ctx,
|
||||
&sctx->deleted_refs);
|
||||
}
|
||||
|
||||
static int rbtree_ref_comp(const void *k, const struct rb_node *node)
|
||||
{
|
||||
const struct recorded_ref *data = k;
|
||||
@ -4592,120 +4522,16 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct find_ref_ctx {
|
||||
u64 dir;
|
||||
u64 dir_gen;
|
||||
struct btrfs_root *root;
|
||||
struct fs_path *name;
|
||||
int found_idx;
|
||||
};
|
||||
|
||||
static int __find_iref(int num, u64 dir, int index,
|
||||
struct fs_path *name,
|
||||
void *ctx_)
|
||||
{
|
||||
struct find_ref_ctx *ctx = ctx_;
|
||||
u64 dir_gen;
|
||||
int ret;
|
||||
|
||||
if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) &&
|
||||
strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) {
|
||||
/*
|
||||
* To avoid doing extra lookups we'll only do this if everything
|
||||
* else matches.
|
||||
*/
|
||||
ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (dir_gen != ctx->dir_gen)
|
||||
return 0;
|
||||
ctx->found_idx = num;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_iref(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
struct btrfs_key *key,
|
||||
u64 dir, u64 dir_gen, struct fs_path *name)
|
||||
{
|
||||
int ret;
|
||||
struct find_ref_ctx ctx;
|
||||
|
||||
ctx.dir = dir;
|
||||
ctx.name = name;
|
||||
ctx.dir_gen = dir_gen;
|
||||
ctx.found_idx = -1;
|
||||
ctx.root = root;
|
||||
|
||||
ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ctx.found_idx == -1)
|
||||
return -ENOENT;
|
||||
|
||||
return ctx.found_idx;
|
||||
}
|
||||
|
||||
static int __record_changed_new_ref(int num, u64 dir, int index,
|
||||
struct fs_path *name,
|
||||
void *ctx)
|
||||
{
|
||||
u64 dir_gen;
|
||||
int ret;
|
||||
struct send_ctx *sctx = ctx;
|
||||
|
||||
ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = find_iref(sctx->parent_root, sctx->right_path,
|
||||
sctx->cmp_key, dir, dir_gen, name);
|
||||
if (ret == -ENOENT)
|
||||
ret = record_new_ref_if_needed(num, dir, index, name, sctx);
|
||||
else if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __record_changed_deleted_ref(int num, u64 dir, int index,
|
||||
struct fs_path *name,
|
||||
void *ctx)
|
||||
{
|
||||
u64 dir_gen;
|
||||
int ret;
|
||||
struct send_ctx *sctx = ctx;
|
||||
|
||||
ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key,
|
||||
dir, dir_gen, name);
|
||||
if (ret == -ENOENT)
|
||||
ret = record_deleted_ref_if_needed(num, dir, index, name, sctx);
|
||||
else if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int record_changed_ref(struct send_ctx *sctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = iterate_inode_ref(sctx->send_root, sctx->left_path,
|
||||
sctx->cmp_key, 0, __record_changed_new_ref, sctx);
|
||||
sctx->cmp_key, 0, record_new_ref_if_needed, sctx);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = iterate_inode_ref(sctx->parent_root, sctx->right_path,
|
||||
sctx->cmp_key, 0, __record_changed_deleted_ref, sctx);
|
||||
sctx->cmp_key, 0, record_deleted_ref_if_needed, sctx);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = 0;
|
||||
@ -4736,10 +4562,10 @@ static int process_all_refs(struct send_ctx *sctx,
|
||||
|
||||
if (cmd == BTRFS_COMPARE_TREE_NEW) {
|
||||
root = sctx->send_root;
|
||||
cb = __record_new_ref;
|
||||
cb = record_new_ref_if_needed;
|
||||
} else if (cmd == BTRFS_COMPARE_TREE_DELETED) {
|
||||
root = sctx->parent_root;
|
||||
cb = __record_deleted_ref;
|
||||
cb = record_deleted_ref_if_needed;
|
||||
} else {
|
||||
btrfs_err(sctx->send_root->fs_info,
|
||||
"Wrong command %d in process_all_refs", cmd);
|
||||
@ -6591,8 +6417,13 @@ static int record_parent_ref(int num, u64 dir, int index, struct fs_path *name,
|
||||
{
|
||||
struct parent_paths_ctx *ppctx = ctx;
|
||||
|
||||
return record_ref(ppctx->sctx->parent_root, dir, name, ppctx->sctx,
|
||||
ppctx->refs);
|
||||
/*
|
||||
* Pass 0 as the generation for the directory, we don't care about it
|
||||
* here as we have no new references to add, we just want to delete all
|
||||
* references for an inode.
|
||||
*/
|
||||
return record_ref_in_tree(&ppctx->sctx->rbtree_deleted_refs, ppctx->refs,
|
||||
name, dir, 0, ppctx->sctx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user