Commit da447009 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

btrfs: factor out inode items copy loop from btrfs_log_inode()

The function btrfs_log_inode() is quite large and so is its loop which
iterates the inode items from the fs/subvolume tree and copies them into
a log tree. Because this is a large loop inside a very large function
and because an upcoming patch in this series needs to add some more logic
inside that loop, move the loop into a helper function to make it a bit
more manageable.
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a5eeb3d1
...@@ -4941,6 +4941,138 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans, ...@@ -4941,6 +4941,138 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static int copy_inode_items_to_log(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode,
struct btrfs_key *min_key,
const struct btrfs_key *max_key,
struct btrfs_path *path,
struct btrfs_path *dst_path,
const u64 logged_isize,
const bool recursive_logging,
const int inode_only,
struct btrfs_log_ctx *ctx,
bool *need_log_inode_item)
{
struct btrfs_root *root = inode->root;
int ins_start_slot = 0;
int ins_nr = 0;
int ret;
while (1) {
ret = btrfs_search_forward(root, min_key, path, trans->transid);
if (ret < 0)
return ret;
if (ret > 0) {
ret = 0;
break;
}
again:
/* Note, ins_nr might be > 0 here, cleanup outside the loop */
if (min_key->objectid != max_key->objectid)
break;
if (min_key->type > max_key->type)
break;
if (min_key->type == BTRFS_INODE_ITEM_KEY)
*need_log_inode_item = false;
if ((min_key->type == BTRFS_INODE_REF_KEY ||
min_key->type == BTRFS_INODE_EXTREF_KEY) &&
inode->generation == trans->transid &&
!recursive_logging) {
u64 other_ino = 0;
u64 other_parent = 0;
ret = btrfs_check_ref_name_override(path->nodes[0],
path->slots[0], min_key, inode,
&other_ino, &other_parent);
if (ret < 0) {
return ret;
} else if (ret > 0 && ctx &&
other_ino != btrfs_ino(BTRFS_I(ctx->inode))) {
if (ins_nr > 0) {
ins_nr++;
} else {
ins_nr = 1;
ins_start_slot = path->slots[0];
}
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot, ins_nr,
inode_only, logged_isize);
if (ret < 0)
return ret;
ins_nr = 0;
ret = log_conflicting_inodes(trans, root, path,
ctx, other_ino, other_parent);
if (ret)
return ret;
btrfs_release_path(path);
goto next_key;
}
}
/* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
if (min_key->type == BTRFS_XATTR_ITEM_KEY) {
if (ins_nr == 0)
goto next_slot;
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot,
ins_nr, inode_only, logged_isize);
if (ret < 0)
return ret;
ins_nr = 0;
goto next_slot;
}
if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
ins_nr++;
goto next_slot;
} else if (!ins_nr) {
ins_start_slot = path->slots[0];
ins_nr = 1;
goto next_slot;
}
ret = copy_items(trans, inode, dst_path, path, ins_start_slot,
ins_nr, inode_only, logged_isize);
if (ret < 0)
return ret;
ins_nr = 1;
ins_start_slot = path->slots[0];
next_slot:
path->slots[0]++;
if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
btrfs_item_key_to_cpu(path->nodes[0], min_key,
path->slots[0]);
goto again;
}
if (ins_nr) {
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot, ins_nr, inode_only,
logged_isize);
if (ret < 0)
return ret;
ins_nr = 0;
}
btrfs_release_path(path);
next_key:
if (min_key->offset < (u64)-1) {
min_key->offset++;
} else if (min_key->type < max_key->type) {
min_key->type++;
min_key->offset = 0;
} else {
break;
}
}
if (ins_nr)
ret = copy_items(trans, inode, dst_path, path, ins_start_slot,
ins_nr, inode_only, logged_isize);
return ret;
}
/* log a single inode in the tree log. /* log a single inode in the tree log.
* At least one parent directory for this inode must exist in the tree * At least one parent directory for this inode must exist in the tree
* or be logged already. * or be logged already.
...@@ -4970,9 +5102,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -4970,9 +5102,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *log = root->log_root; struct btrfs_root *log = root->log_root;
int err = 0; int err = 0;
int ret; int ret;
int nritems;
int ins_start_slot = 0;
int ins_nr;
bool fast_search = false; bool fast_search = false;
u64 ino = btrfs_ino(inode); u64 ino = btrfs_ino(inode);
struct extent_map_tree *em_tree = &inode->extent_tree; struct extent_map_tree *em_tree = &inode->extent_tree;
...@@ -5103,139 +5232,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -5103,139 +5232,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
goto out_unlock; goto out_unlock;
} }
while (1) { err = copy_inode_items_to_log(trans, inode, &min_key, &max_key,
ins_nr = 0; path, dst_path, logged_isize,
ret = btrfs_search_forward(root, &min_key, recursive_logging, inode_only, ctx,
path, trans->transid); &need_log_inode_item);
if (ret < 0) { if (err)
err = ret; goto out_unlock;
goto out_unlock;
}
if (ret != 0)
break;
again:
/* note, ins_nr might be > 0 here, cleanup outside the loop */
if (min_key.objectid != ino)
break;
if (min_key.type > max_key.type)
break;
if (min_key.type == BTRFS_INODE_ITEM_KEY)
need_log_inode_item = false;
if ((min_key.type == BTRFS_INODE_REF_KEY ||
min_key.type == BTRFS_INODE_EXTREF_KEY) &&
inode->generation == trans->transid &&
!recursive_logging) {
u64 other_ino = 0;
u64 other_parent = 0;
ret = btrfs_check_ref_name_override(path->nodes[0],
path->slots[0], &min_key, inode,
&other_ino, &other_parent);
if (ret < 0) {
err = ret;
goto out_unlock;
} else if (ret > 0 && ctx &&
other_ino != btrfs_ino(BTRFS_I(ctx->inode))) {
if (ins_nr > 0) {
ins_nr++;
} else {
ins_nr = 1;
ins_start_slot = path->slots[0];
}
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot,
ins_nr, inode_only,
logged_isize);
if (ret < 0) {
err = ret;
goto out_unlock;
}
ins_nr = 0;
err = log_conflicting_inodes(trans, root, path,
ctx, other_ino, other_parent);
if (err)
goto out_unlock;
btrfs_release_path(path);
goto next_key;
}
}
/* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
if (min_key.type == BTRFS_XATTR_ITEM_KEY) {
if (ins_nr == 0)
goto next_slot;
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot,
ins_nr, inode_only, logged_isize);
if (ret < 0) {
err = ret;
goto out_unlock;
}
ins_nr = 0;
goto next_slot;
}
if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
ins_nr++;
goto next_slot;
} else if (!ins_nr) {
ins_start_slot = path->slots[0];
ins_nr = 1;
goto next_slot;
}
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot, ins_nr, inode_only,
logged_isize);
if (ret < 0) {
err = ret;
goto out_unlock;
}
ins_nr = 1;
ins_start_slot = path->slots[0];
next_slot:
nritems = btrfs_header_nritems(path->nodes[0]);
path->slots[0]++;
if (path->slots[0] < nritems) {
btrfs_item_key_to_cpu(path->nodes[0], &min_key,
path->slots[0]);
goto again;
}
if (ins_nr) {
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot,
ins_nr, inode_only, logged_isize);
if (ret < 0) {
err = ret;
goto out_unlock;
}
ins_nr = 0;
}
btrfs_release_path(path);
next_key:
if (min_key.offset < (u64)-1) {
min_key.offset++;
} else if (min_key.type < max_key.type) {
min_key.type++;
min_key.offset = 0;
} else {
break;
}
}
if (ins_nr) {
ret = copy_items(trans, inode, dst_path, path,
ins_start_slot, ins_nr, inode_only,
logged_isize);
if (ret < 0) {
err = ret;
goto out_unlock;
}
ins_nr = 0;
}
btrfs_release_path(path); btrfs_release_path(path);
btrfs_release_path(dst_path); btrfs_release_path(dst_path);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment