Skip to content

Commit eb10d85

Browse files
fdmananakdave
authored andcommitted
btrfs: factor out the copying loop of dir items from log_dir_items()
In preparation for the next change, move the loop that processes a leaf and copies its directory items to the log, into a separate helper function. This makes the next change simpler and it also helps making log_dir_items() a bit shorter (specially after the next change). This patch is part of a patchset comprised of the following 5 patches: btrfs: remove root argument from btrfs_log_inode() and its callees btrfs: remove redundant log root assignment from log_dir_items() btrfs: factor out the copying loop of dir items from log_dir_items() btrfs: insert items in batches when logging a directory when possible btrfs: keep track of the last logged keys when logging a directory This is patch 3/5. The change log of the last patch (5/5) has performance results. Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent d46fb84 commit eb10d85

File tree

1 file changed

+75
-60
lines changed

1 file changed

+75
-60
lines changed

fs/btrfs/tree-log.c

Lines changed: 75 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3632,6 +3632,66 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
36323632
return 0;
36333633
}
36343634

3635+
static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
3636+
struct btrfs_inode *inode,
3637+
struct btrfs_path *path,
3638+
struct btrfs_path *dst_path,
3639+
int key_type,
3640+
struct btrfs_log_ctx *ctx)
3641+
{
3642+
struct btrfs_root *log = inode->root->log_root;
3643+
struct extent_buffer *src = path->nodes[0];
3644+
const int nritems = btrfs_header_nritems(src);
3645+
const u64 ino = btrfs_ino(inode);
3646+
int i;
3647+
3648+
for (i = path->slots[0]; i < nritems; i++) {
3649+
struct btrfs_key key;
3650+
struct btrfs_dir_item *di;
3651+
int ret;
3652+
3653+
btrfs_item_key_to_cpu(src, &key, i);
3654+
3655+
if (key.objectid != ino || key.type != key_type)
3656+
return 1;
3657+
3658+
ret = overwrite_item(trans, log, dst_path, src, i, &key);
3659+
if (ret < 0)
3660+
return ret;
3661+
3662+
/*
3663+
* We must make sure that when we log a directory entry, the
3664+
* corresponding inode, after log replay, has a matching link
3665+
* count. For example:
3666+
*
3667+
* touch foo
3668+
* mkdir mydir
3669+
* sync
3670+
* ln foo mydir/bar
3671+
* xfs_io -c "fsync" mydir
3672+
* <crash>
3673+
* <mount fs and log replay>
3674+
*
3675+
* Would result in a fsync log that when replayed, our file inode
3676+
* would have a link count of 1, but we get two directory entries
3677+
* pointing to the same inode. After removing one of the names,
3678+
* it would not be possible to remove the other name, which
3679+
* resulted always in stale file handle errors, and would not be
3680+
* possible to rmdir the parent directory, since its i_size could
3681+
* never be decremented to the value BTRFS_EMPTY_DIR_SIZE,
3682+
* resulting in -ENOTEMPTY errors.
3683+
*/
3684+
di = btrfs_item_ptr(src, i, struct btrfs_dir_item);
3685+
btrfs_dir_item_key_to_cpu(src, di, &key);
3686+
if ((btrfs_dir_transid(src, di) == trans->transid ||
3687+
btrfs_dir_type(src, di) == BTRFS_FT_DIR) &&
3688+
key.type != BTRFS_ROOT_ITEM_KEY)
3689+
ctx->log_new_dentries = true;
3690+
}
3691+
3692+
return 0;
3693+
}
3694+
36353695
/*
36363696
* log all the items included in the current transaction for a given
36373697
* directory. This also creates the range items in the log tree required
@@ -3647,11 +3707,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
36473707
struct btrfs_key min_key;
36483708
struct btrfs_root *root = inode->root;
36493709
struct btrfs_root *log = root->log_root;
3650-
struct extent_buffer *src;
36513710
int err = 0;
36523711
int ret;
3653-
int i;
3654-
int nritems;
36553712
u64 first_offset = min_offset;
36563713
u64 last_offset = (u64)-1;
36573714
u64 ino = btrfs_ino(inode);
@@ -3729,61 +3786,14 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
37293786
* from our directory
37303787
*/
37313788
while (1) {
3732-
struct btrfs_key tmp;
3733-
src = path->nodes[0];
3734-
nritems = btrfs_header_nritems(src);
3735-
for (i = path->slots[0]; i < nritems; i++) {
3736-
struct btrfs_dir_item *di;
3737-
3738-
btrfs_item_key_to_cpu(src, &min_key, i);
3739-
3740-
if (min_key.objectid != ino || min_key.type != key_type)
3741-
goto done;
3742-
3743-
if (need_resched()) {
3744-
btrfs_release_path(path);
3745-
cond_resched();
3746-
goto search;
3747-
}
3748-
3749-
ret = overwrite_item(trans, log, dst_path, src, i,
3750-
&min_key);
3751-
if (ret) {
3789+
ret = process_dir_items_leaf(trans, inode, path, dst_path,
3790+
key_type, ctx);
3791+
if (ret != 0) {
3792+
if (ret < 0)
37523793
err = ret;
3753-
goto done;
3754-
}
3755-
3756-
/*
3757-
* We must make sure that when we log a directory entry,
3758-
* the corresponding inode, after log replay, has a
3759-
* matching link count. For example:
3760-
*
3761-
* touch foo
3762-
* mkdir mydir
3763-
* sync
3764-
* ln foo mydir/bar
3765-
* xfs_io -c "fsync" mydir
3766-
* <crash>
3767-
* <mount fs and log replay>
3768-
*
3769-
* Would result in a fsync log that when replayed, our
3770-
* file inode would have a link count of 1, but we get
3771-
* two directory entries pointing to the same inode.
3772-
* After removing one of the names, it would not be
3773-
* possible to remove the other name, which resulted
3774-
* always in stale file handle errors, and would not
3775-
* be possible to rmdir the parent directory, since
3776-
* its i_size could never decrement to the value
3777-
* BTRFS_EMPTY_DIR_SIZE, resulting in -ENOTEMPTY errors.
3778-
*/
3779-
di = btrfs_item_ptr(src, i, struct btrfs_dir_item);
3780-
btrfs_dir_item_key_to_cpu(src, di, &tmp);
3781-
if ((btrfs_dir_transid(src, di) == trans->transid ||
3782-
btrfs_dir_type(src, di) == BTRFS_FT_DIR) &&
3783-
tmp.type != BTRFS_ROOT_ITEM_KEY)
3784-
ctx->log_new_dentries = true;
3794+
goto done;
37853795
}
3786-
path->slots[0] = nritems;
3796+
path->slots[0] = btrfs_header_nritems(path->nodes[0]);
37873797

37883798
/*
37893799
* look ahead to the next item and see if it is also
@@ -3797,21 +3807,26 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
37973807
err = ret;
37983808
goto done;
37993809
}
3800-
btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
3801-
if (tmp.objectid != ino || tmp.type != key_type) {
3810+
btrfs_item_key_to_cpu(path->nodes[0], &min_key, path->slots[0]);
3811+
if (min_key.objectid != ino || min_key.type != key_type) {
38023812
last_offset = (u64)-1;
38033813
goto done;
38043814
}
38053815
if (btrfs_header_generation(path->nodes[0]) != trans->transid) {
38063816
ret = overwrite_item(trans, log, dst_path,
38073817
path->nodes[0], path->slots[0],
3808-
&tmp);
3818+
&min_key);
38093819
if (ret)
38103820
err = ret;
38113821
else
3812-
last_offset = tmp.offset;
3822+
last_offset = min_key.offset;
38133823
goto done;
38143824
}
3825+
if (need_resched()) {
3826+
btrfs_release_path(path);
3827+
cond_resched();
3828+
goto search;
3829+
}
38153830
}
38163831
done:
38173832
btrfs_release_path(path);

0 commit comments

Comments
 (0)