Skip to content

Commit

Permalink
btrfs: add and use helper for unlinking inode during log replay
Browse files Browse the repository at this point in the history
During log replay there is this pattern of running delayed items after
every inode unlink. To avoid repeating this several times, move the
logic into an helper function and use it instead of calling
btrfs_unlink_inode() followed by btrfs_run_delayed_items().

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
Filipe Manana authored and David Sterba committed Mar 14, 2022
1 parent 06bae87 commit 313ab75
Showing 1 changed file with 29 additions and 48 deletions.
77 changes: 29 additions & 48 deletions fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,26 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
return ret;
}

static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
const char *name,
int name_len)
{
int ret;

ret = btrfs_unlink_inode(trans, dir, inode, name, name_len);
if (ret)
return ret;
/*
* Whenever we need to check if a name exists or not, we check the
* fs/subvolume tree. So after an unlink we must run delayed items, so
* that future checks for a name during log replay see that the name
* does not exists anymore.
*/
return btrfs_run_delayed_items(trans);
}

/*
* when cleaning up conflicts between the directory names in the
* subvolume, directory names in the log and directory names in the
Expand Down Expand Up @@ -941,12 +961,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
if (ret)
goto out;

ret = btrfs_unlink_inode(trans, dir, BTRFS_I(inode), name,
ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), name,
name_len);
if (ret)
goto out;
else
ret = btrfs_run_delayed_items(trans);
out:
kfree(name);
iput(inode);
Expand Down Expand Up @@ -1106,12 +1122,9 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
inc_nlink(&inode->vfs_inode);
btrfs_release_path(path);

ret = btrfs_unlink_inode(trans, dir, inode,
ret = unlink_inode_for_log_replay(trans, dir, inode,
victim_name, victim_name_len);
kfree(victim_name);
if (ret)
return ret;
ret = btrfs_run_delayed_items(trans);
if (ret)
return ret;
*search_done = 1;
Expand Down Expand Up @@ -1178,14 +1191,11 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
inc_nlink(&inode->vfs_inode);
btrfs_release_path(path);

ret = btrfs_unlink_inode(trans,
ret = unlink_inode_for_log_replay(trans,
BTRFS_I(victim_parent),
inode,
victim_name,
victim_name_len);
if (!ret)
ret = btrfs_run_delayed_items(
trans);
}
iput(victim_parent);
kfree(victim_name);
Expand Down Expand Up @@ -1340,19 +1350,10 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
kfree(name);
goto out;
}
ret = btrfs_unlink_inode(trans, BTRFS_I(dir),
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir),
inode, name, namelen);
kfree(name);
iput(dir);
/*
* Whenever we need to check if a name exists or not, we
* check the subvolume tree. So after an unlink we must
* run delayed items, so that future checks for a name
* during log replay see that the name does not exists
* anymore.
*/
if (!ret)
ret = btrfs_run_delayed_items(trans);
if (ret)
goto out;
goto again;
Expand Down Expand Up @@ -1448,8 +1449,8 @@ static int add_link(struct btrfs_trans_handle *trans,
ret = -ENOENT;
goto out;
}
ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(other_inode),
name, namelen);
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(other_inode),
name, namelen);
if (ret)
goto out;
/*
Expand All @@ -1458,10 +1459,6 @@ static int add_link(struct btrfs_trans_handle *trans,
*/
if (other_inode->i_nlink == 0)
inc_nlink(other_inode);

ret = btrfs_run_delayed_items(trans);
if (ret)
goto out;
add_link:
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
name, namelen, 0, ref_index);
Expand Down Expand Up @@ -1594,7 +1591,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ret = btrfs_inode_ref_exists(inode, dir, key->type,
name, namelen);
if (ret > 0) {
ret = btrfs_unlink_inode(trans,
ret = unlink_inode_for_log_replay(trans,
BTRFS_I(dir),
BTRFS_I(inode),
name, namelen);
Expand All @@ -1605,15 +1602,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
*/
if (!ret && inode->i_nlink == 0)
inc_nlink(inode);
/*
* Whenever we need to check if a name exists or
* not, we check the subvolume tree. So after an
* unlink we must run delayed items, so that future
* checks for a name during log replay see that the
* name does not exists anymore.
*/
if (!ret)
ret = btrfs_run_delayed_items(trans);
}
if (ret < 0)
goto out;
Expand Down Expand Up @@ -2350,15 +2338,8 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
goto out;

inc_nlink(inode);
ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(inode), name,
name_len);
if (ret)
goto out;

ret = btrfs_run_delayed_items(trans);
if (ret)
goto out;

ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode),
name, name_len);
/*
* Unlike dir item keys, dir index keys can only have one name (entry) in
* them, as there are no key collisions since each key has a unique offset
Expand Down

0 comments on commit 313ab75

Please sign in to comment.