Skip to content

Commit

Permalink
btrfs: factor out inode items copy loop from btrfs_log_inode()
Browse files Browse the repository at this point in the history
[ Upstream commit da44700 ]

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: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
fdmanana authored and gregkh committed Sep 3, 2020
1 parent a0cfda9 commit d5f5b15
Showing 1 changed file with 138 additions and 136 deletions.
274 changes: 138 additions & 136 deletions fs/btrfs/tree-log.c
Expand Up @@ -4994,6 +4994,138 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
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.
* At least one parent directory for this inode must exist in the tree
* or be logged already.
Expand Down Expand Up @@ -5023,9 +5155,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *log = root->log_root;
int err = 0;
int ret;
int nritems;
int ins_start_slot = 0;
int ins_nr;
bool fast_search = false;
u64 ino = btrfs_ino(inode);
struct extent_map_tree *em_tree = &inode->extent_tree;
Expand Down Expand Up @@ -5156,139 +5285,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
goto out_unlock;
}

while (1) {
ins_nr = 0;
ret = btrfs_search_forward(root, &min_key,
path, trans->transid);
if (ret < 0) {
err = ret;
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;
}
err = copy_inode_items_to_log(trans, inode, &min_key, &max_key,
path, dst_path, logged_isize,
recursive_logging, inode_only, ctx,
&need_log_inode_item);
if (err)
goto out_unlock;

btrfs_release_path(path);
btrfs_release_path(dst_path);
Expand Down

0 comments on commit d5f5b15

Please sign in to comment.