summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2025-09-02 12:16:17 +0100
committerDavid Sterba <dsterba@suse.com>2025-09-23 08:49:20 +0200
commit1ebeee283a2ac8ea29a705d7f03a15e3aae30f22 (patch)
treea93b791edde3c172ec5a2a40ee4faa887cb49a04
parentf9c02e4b525d766bebfcbeac1b25b03aacfe62f1 (diff)
btrfs: add path for subvolume tree changes to struct walk_control
While replaying log trees we need to do searches and updates to subvolume trees and for that we use a path that we allocate in replay_one_buffer() and then pass it as a parameter to other functions deeper in the log replay call chain. Instead of passing it as parameter, add it to struct walk_control since we pass a pointer to that structure for every log replay function. This reduces the number of arguments passed to the functions and it will be needed and important for an upcoming changes that improves error reporting for log replay. Also name the new filed in struct walk_control to 'subvol_path' - while that is longer to type, the naming makes it clear it's used for subvolume tree operations since many of the log replay functions operate both on subvolume and log trees, and for the log tree searches we have struct walk_control::log_leaf to also make it obvious it's an extent buffer for a log tree extent buffer. Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/tree-log.c323
1 files changed, 156 insertions, 167 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 66500ebdd35c..747daaaaf332 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -162,16 +162,17 @@ struct walk_control {
struct btrfs_key log_key;
/* The slot being processed of the current log leaf. */
int log_slot;
+
+ /* A path used for searches and modifications to subvolume trees. */
+ struct btrfs_path *subvol_path;
};
static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode,
int inode_only,
struct btrfs_log_ctx *ctx);
-static int link_to_fixup_dir(struct walk_control *wc,
- struct btrfs_path *path, u64 objectid);
+static int link_to_fixup_dir(struct walk_control *wc, u64 objectid);
static noinline int replay_dir_deletes(struct walk_control *wc,
- struct btrfs_path *path,
u64 dirid, bool del_all);
static void wait_log_commit(struct btrfs_root *root, int transid);
@@ -422,7 +423,7 @@ static int process_one_buffer(struct extent_buffer *eb,
*
* If the key isn't in the destination yet, a new item is inserted.
*/
-static int overwrite_item(struct walk_control *wc, struct btrfs_path *path)
+static int overwrite_item(struct walk_control *wc)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -449,14 +450,14 @@ static int overwrite_item(struct walk_control *wc, struct btrfs_path *path)
src_ptr = btrfs_item_ptr_offset(wc->log_leaf, wc->log_slot);
/* Look for the key in the destination tree. */
- ret = btrfs_search_slot(NULL, root, &wc->log_key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &wc->log_key, wc->subvol_path, 0, 0);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
return ret;
}
- dst_eb = path->nodes[0];
- dst_slot = path->slots[0];
+ dst_eb = wc->subvol_path->nodes[0];
+ dst_slot = wc->subvol_path->slots[0];
if (ret == 0) {
char *src_copy;
@@ -466,7 +467,7 @@ static int overwrite_item(struct walk_control *wc, struct btrfs_path *path)
goto insert;
if (item_size == 0) {
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return 0;
}
src_copy = kmalloc(item_size, GFP_NOFS);
@@ -487,7 +488,7 @@ static int overwrite_item(struct walk_control *wc, struct btrfs_path *path)
* sync
*/
if (ret == 0) {
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return 0;
}
@@ -537,23 +538,23 @@ static int overwrite_item(struct walk_control *wc, struct btrfs_path *path)
btrfs_set_inode_size(wc->log_leaf, item, 0);
}
insert:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
/* try to insert the key into the destination tree */
- path->skip_release_on_error = 1;
- ret = btrfs_insert_empty_item(trans, root, path, &wc->log_key, item_size);
- path->skip_release_on_error = 0;
+ wc->subvol_path->skip_release_on_error = 1;
+ ret = btrfs_insert_empty_item(trans, root, wc->subvol_path, &wc->log_key, item_size);
+ wc->subvol_path->skip_release_on_error = 0;
- dst_eb = path->nodes[0];
- dst_slot = path->slots[0];
+ dst_eb = wc->subvol_path->nodes[0];
+ dst_slot = wc->subvol_path->slots[0];
/* make sure any existing item is the correct size */
if (ret == -EEXIST || ret == -EOVERFLOW) {
const u32 found_size = btrfs_item_size(dst_eb, dst_slot);
if (found_size > item_size)
- btrfs_truncate_item(trans, path, item_size, 1);
+ btrfs_truncate_item(trans, wc->subvol_path, item_size, 1);
else if (found_size < item_size)
- btrfs_extend_item(trans, path, item_size - found_size);
+ btrfs_extend_item(trans, wc->subvol_path, item_size - found_size);
} else if (ret) {
btrfs_abort_transaction(trans, ret);
return ret;
@@ -618,7 +619,7 @@ insert:
btrfs_set_inode_generation(dst_eb, dst_item, trans->transid);
}
no_copy:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return 0;
}
@@ -649,7 +650,7 @@ static int read_alloc_one_name(struct extent_buffer *eb, void *start, int len,
* The extent is inserted into the file, dropping any existing extents
* from the file that overlap the new one.
*/
-static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path *path)
+static noinline int replay_one_extent(struct walk_control *wc)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -710,16 +711,18 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
* file. This must be done before the btrfs_drop_extents run
* so we don't try to drop this extent.
*/
- ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), start, 0);
+ ret = btrfs_lookup_file_extent(trans, root, wc->subvol_path,
+ btrfs_ino(inode), start, 0);
if (ret == 0 &&
(found_type == BTRFS_FILE_EXTENT_REG ||
found_type == BTRFS_FILE_EXTENT_PREALLOC)) {
+ struct extent_buffer *leaf = wc->subvol_path->nodes[0];
struct btrfs_file_extent_item existing;
unsigned long ptr;
- ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
- read_extent_buffer(path->nodes[0], &existing, ptr, sizeof(existing));
+ ptr = btrfs_item_ptr_offset(leaf, wc->subvol_path->slots[0]);
+ read_extent_buffer(leaf, &existing, ptr, sizeof(existing));
/*
* we already have a pointer to this exact extent,
@@ -727,17 +730,17 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
*/
if (memcmp_extent_buffer(wc->log_leaf, &existing, (unsigned long)item,
sizeof(existing)) == 0) {
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
goto out;
}
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
/* drop any overlapping extents */
drop_args.start = start;
drop_args.end = extent_end;
drop_args.drop_cache = true;
- drop_args.path = path;
+ drop_args.path = wc->subvol_path;
ret = btrfs_drop_extents(trans, root, inode, &drop_args);
if (ret) {
btrfs_abort_transaction(trans, ret);
@@ -746,7 +749,7 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
if (found_type == BTRFS_FILE_EXTENT_INLINE) {
/* inline extents are easy, we just overwrite them */
- ret = overwrite_item(wc, path);
+ ret = overwrite_item(wc);
if (ret)
goto out;
goto update_inode;
@@ -762,13 +765,15 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
btrfs_fs_incompat(fs_info, NO_HOLES))
goto update_inode;
- ret = btrfs_insert_empty_item(trans, root, path, &wc->log_key, sizeof(*item));
+ ret = btrfs_insert_empty_item(trans, root, wc->subvol_path,
+ &wc->log_key, sizeof(*item));
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
}
- dest_offset = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
- copy_extent_buffer(path->nodes[0], wc->log_leaf, dest_offset,
+ dest_offset = btrfs_item_ptr_offset(wc->subvol_path->nodes[0],
+ wc->subvol_path->slots[0]);
+ copy_extent_buffer(wc->subvol_path->nodes[0], wc->log_leaf, dest_offset,
(unsigned long)item, sizeof(*item));
/*
@@ -778,7 +783,7 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
* update the inode item.
*/
if (btrfs_file_extent_disk_bytenr(wc->log_leaf, item) == 0) {
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
goto update_inode;
}
@@ -833,7 +838,7 @@ static noinline int replay_one_extent(struct walk_control *wc, struct btrfs_path
}
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
if (btrfs_file_extent_compression(wc->log_leaf, item)) {
csum_start = ins.objectid;
@@ -967,7 +972,6 @@ static int unlink_inode_for_log_replay(struct walk_control *wc,
* item
*/
static noinline int drop_one_dir_item(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_inode *dir,
struct btrfs_dir_item *di)
{
@@ -975,12 +979,10 @@ static noinline int drop_one_dir_item(struct walk_control *wc,
struct btrfs_root *root = dir->root;
struct btrfs_inode *inode;
struct fscrypt_str name;
- struct extent_buffer *leaf;
+ struct extent_buffer *leaf = wc->subvol_path->nodes[0];
struct btrfs_key location;
int ret;
- leaf = path->nodes[0];
-
btrfs_dir_item_key_to_cpu(leaf, di, &location);
ret = read_alloc_one_name(leaf, di + 1, btrfs_dir_name_len(leaf, di), &name);
if (ret) {
@@ -988,7 +990,7 @@ static noinline int drop_one_dir_item(struct walk_control *wc,
return ret;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
inode = btrfs_iget_logging(location.objectid, root);
if (IS_ERR(inode)) {
@@ -998,7 +1000,7 @@ static noinline int drop_one_dir_item(struct walk_control *wc,
goto out;
}
- ret = link_to_fixup_dir(wc, path, location.objectid);
+ ret = link_to_fixup_dir(wc, location.objectid);
if (ret)
goto out;
@@ -1097,13 +1099,12 @@ out:
}
static int unlink_refs_not_in_log(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_key *search_key,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
u64 parent_objectid)
{
- struct extent_buffer *leaf = path->nodes[0];
+ struct extent_buffer *leaf = wc->subvol_path->nodes[0];
unsigned long ptr;
unsigned long ptr_end;
@@ -1112,8 +1113,8 @@ static int unlink_refs_not_in_log(struct walk_control *wc,
* log. If so, we allow them to stay otherwise they must be unlinked as
* a conflict.
*/
- ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
- ptr_end = ptr + btrfs_item_size(leaf, path->slots[0]);
+ ptr = btrfs_item_ptr_offset(leaf, wc->subvol_path->slots[0]);
+ ptr_end = ptr + btrfs_item_size(leaf, wc->subvol_path->slots[0]);
while (ptr < ptr_end) {
struct btrfs_trans_handle *trans = wc->trans;
struct fscrypt_str victim_name;
@@ -1141,7 +1142,7 @@ static int unlink_refs_not_in_log(struct walk_control *wc,
}
inc_nlink(&inode->vfs_inode);
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
ret = unlink_inode_for_log_replay(wc, dir, inode, &victim_name);
kfree(victim_name.name);
@@ -1154,15 +1155,14 @@ static int unlink_refs_not_in_log(struct walk_control *wc,
}
static int unlink_extrefs_not_in_log(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_key *search_key,
struct btrfs_inode *inode,
u64 inode_objectid,
u64 parent_objectid)
{
- struct extent_buffer *leaf = path->nodes[0];
- const unsigned long base = btrfs_item_ptr_offset(leaf, path->slots[0]);
- const u32 item_size = btrfs_item_size(leaf, path->slots[0]);
+ struct extent_buffer *leaf = wc->subvol_path->nodes[0];
+ const unsigned long base = btrfs_item_ptr_offset(leaf, wc->subvol_path->slots[0]);
+ const u32 item_size = btrfs_item_size(leaf, wc->subvol_path->slots[0]);
u32 cur_offset = 0;
while (cur_offset < item_size) {
@@ -1213,7 +1213,7 @@ next:
}
inc_nlink(&inode->vfs_inode);
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
ret = unlink_inode_for_log_replay(wc, victim_parent, inode,
&victim_name);
@@ -1228,7 +1228,6 @@ next:
}
static inline int __add_inode_ref(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_inode *dir,
struct btrfs_inode *inode,
u64 inode_objectid, u64 parent_objectid,
@@ -1246,7 +1245,7 @@ again:
search_key.objectid = inode_objectid;
search_key.type = BTRFS_INODE_REF_KEY;
search_key.offset = parent_objectid;
- ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &search_key, wc->subvol_path, 0, 0);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
return ret;
@@ -1258,53 +1257,54 @@ again:
if (search_key.objectid == search_key.offset)
return 1;
- ret = unlink_refs_not_in_log(wc, path, &search_key, dir, inode,
+ ret = unlink_refs_not_in_log(wc, &search_key, dir, inode,
parent_objectid);
if (ret == -EAGAIN)
goto again;
else if (ret)
return ret;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
/* Same search but for extended refs */
- extref = btrfs_lookup_inode_extref(root, path, name, inode_objectid, parent_objectid);
+ extref = btrfs_lookup_inode_extref(root, wc->subvol_path, name,
+ inode_objectid, parent_objectid);
if (IS_ERR(extref)) {
return PTR_ERR(extref);
} else if (extref) {
- ret = unlink_extrefs_not_in_log(wc, path, &search_key, inode,
+ ret = unlink_extrefs_not_in_log(wc, &search_key, inode,
inode_objectid, parent_objectid);
if (ret == -EAGAIN)
goto again;
else if (ret)
return ret;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
/* look for a conflicting sequence number */
- di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
+ di = btrfs_lookup_dir_index_item(trans, root, wc->subvol_path, btrfs_ino(dir),
ref_index, name, 0);
if (IS_ERR(di)) {
ret = PTR_ERR(di);
btrfs_abort_transaction(trans, ret);
return ret;
} else if (di) {
- ret = drop_one_dir_item(wc, path, dir, di);
+ ret = drop_one_dir_item(wc, dir, di);
if (ret)
return ret;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
/* look for a conflicting name */
- di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir), name, 0);
+ di = btrfs_lookup_dir_item(trans, root, wc->subvol_path, btrfs_ino(dir), name, 0);
if (IS_ERR(di)) {
return PTR_ERR(di);
} else if (di) {
- ret = drop_one_dir_item(wc, path, dir, di);
+ ret = drop_one_dir_item(wc, dir, di);
if (ret)
return ret;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return 0;
}
@@ -1357,9 +1357,7 @@ static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
* proper unlink of that name (that is, remove its entry from the inode
* reference item and both dir index keys).
*/
-static int unlink_old_inode_refs(struct walk_control *wc,
- struct btrfs_path *path,
- struct btrfs_inode *inode)
+static int unlink_old_inode_refs(struct walk_control *wc, struct btrfs_inode *inode)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -1369,8 +1367,8 @@ static int unlink_old_inode_refs(struct walk_control *wc,
struct extent_buffer *eb;
again:
- btrfs_release_path(path);
- ret = btrfs_search_slot(NULL, root, &wc->log_key, path, 0, 0);
+ btrfs_release_path(wc->subvol_path);
+ ret = btrfs_search_slot(NULL, root, &wc->log_key, wc->subvol_path, 0, 0);
if (ret > 0) {
ret = 0;
goto out;
@@ -1380,9 +1378,9 @@ again:
goto out;
}
- eb = path->nodes[0];
- ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
- ref_end = ref_ptr + btrfs_item_size(eb, path->slots[0]);
+ eb = wc->subvol_path->nodes[0];
+ ref_ptr = btrfs_item_ptr_offset(eb, wc->subvol_path->slots[0]);
+ ref_end = ref_ptr + btrfs_item_size(eb, wc->subvol_path->slots[0]);
while (ref_ptr < ref_end) {
struct fscrypt_str name;
u64 parent_id;
@@ -1413,7 +1411,7 @@ again:
if (!ret) {
struct btrfs_inode *dir;
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
dir = btrfs_iget_logging(parent_id, root);
if (IS_ERR(dir)) {
ret = PTR_ERR(dir);
@@ -1438,7 +1436,7 @@ again:
}
ret = 0;
out:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return ret;
}
@@ -1446,7 +1444,7 @@ again:
* Replay one inode back reference item found in the log tree.
* Path is for temporary use by this function (it should be released on return).
*/
-static noinline int add_inode_ref(struct walk_control *wc, struct btrfs_path *path)
+static noinline int add_inode_ref(struct walk_control *wc)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -1548,8 +1546,8 @@ static noinline int add_inode_ref(struct walk_control *wc, struct btrfs_path *pa
}
}
- ret = inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
- ref_index, &name);
+ ret = inode_in_dir(root, wc->subvol_path, btrfs_ino(dir),
+ btrfs_ino(inode), ref_index, &name);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
goto out;
@@ -1561,7 +1559,7 @@ static noinline int add_inode_ref(struct walk_control *wc, struct btrfs_path *pa
* overwrite any existing back reference, and we don't
* want to create dangling pointers in the directory.
*/
- ret = __add_inode_ref(wc, path, dir, inode, inode_objectid,
+ ret = __add_inode_ref(wc, dir, inode, inode_objectid,
parent_objectid, ref_index, &name);
if (ret) {
if (ret == 1)
@@ -1602,14 +1600,14 @@ next:
* dir index entries exist for a name but there is no inode reference
* item with the same name.
*/
- ret = unlink_old_inode_refs(wc, path, inode);
+ ret = unlink_old_inode_refs(wc, inode);
if (ret)
goto out;
/* finally write the back reference in the inode */
- ret = overwrite_item(wc, path);
+ ret = overwrite_item(wc);
out:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
kfree(name.name);
if (dir)
iput(&dir->vfs_inode);
@@ -1728,7 +1726,6 @@ process_slot:
* will free the inode.
*/
static noinline int fixup_inode_link_count(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_inode *inode)
{
struct btrfs_trans_handle *trans = wc->trans;
@@ -1737,13 +1734,13 @@ static noinline int fixup_inode_link_count(struct walk_control *wc,
u64 nlink = 0;
const u64 ino = btrfs_ino(inode);
- ret = count_inode_refs(inode, path);
+ ret = count_inode_refs(inode, wc->subvol_path);
if (ret < 0)
goto out;
nlink = ret;
- ret = count_inode_extrefs(inode, path);
+ ret = count_inode_extrefs(inode, wc->subvol_path);
if (ret < 0)
goto out;
@@ -1762,7 +1759,7 @@ static noinline int fixup_inode_link_count(struct walk_control *wc,
if (inode->vfs_inode.i_nlink == 0) {
if (S_ISDIR(inode->vfs_inode.i_mode)) {
- ret = replay_dir_deletes(wc, path, ino, true);
+ ret = replay_dir_deletes(wc, ino, true);
if (ret)
goto out;
}
@@ -1772,12 +1769,11 @@ static noinline int fixup_inode_link_count(struct walk_control *wc,
}
out:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return ret;
}
-static noinline int fixup_inode_link_counts(struct walk_control *wc,
- struct btrfs_path *path)
+static noinline int fixup_inode_link_counts(struct walk_control *wc)
{
int ret;
struct btrfs_key key;
@@ -1790,34 +1786,34 @@ static noinline int fixup_inode_link_counts(struct walk_control *wc,
struct btrfs_root *root = wc->root;
struct btrfs_inode *inode;
- ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &key, wc->subvol_path, -1, 1);
if (ret < 0)
break;
if (ret == 1) {
ret = 0;
- if (path->slots[0] == 0)
+ if (wc->subvol_path->slots[0] == 0)
break;
- path->slots[0]--;
+ wc->subvol_path->slots[0]--;
}
- btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ btrfs_item_key_to_cpu(wc->subvol_path->nodes[0], &key, wc->subvol_path->slots[0]);
if (key.objectid != BTRFS_TREE_LOG_FIXUP_OBJECTID ||
key.type != BTRFS_ORPHAN_ITEM_KEY)
break;
- ret = btrfs_del_item(trans, root, path);
+ ret = btrfs_del_item(trans, root, wc->subvol_path);
if (ret)
break;
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
inode = btrfs_iget_logging(key.offset, root);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
break;
}
- ret = fixup_inode_link_count(wc, path, inode);
+ ret = fixup_inode_link_count(wc, inode);
iput(&inode->vfs_inode);
if (ret)
break;
@@ -1829,7 +1825,7 @@ static noinline int fixup_inode_link_counts(struct walk_control *wc,
*/
key.offset = (u64)-1;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return ret;
}
@@ -1839,9 +1835,7 @@ static noinline int fixup_inode_link_counts(struct walk_control *wc,
* count when replay is done. The link count is incremented here
* so the inode won't go away until we check it
*/
-static noinline int link_to_fixup_dir(struct walk_control *wc,
- struct btrfs_path *path,
- u64 objectid)
+static noinline int link_to_fixup_dir(struct walk_control *wc, u64 objectid)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -1862,9 +1856,9 @@ static noinline int link_to_fixup_dir(struct walk_control *wc,
key.type = BTRFS_ORPHAN_ITEM_KEY;
key.offset = objectid;
- ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
+ ret = btrfs_insert_empty_item(trans, root, wc->subvol_path, &key, 0);
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
if (ret == 0) {
if (!vfs_inode->i_nlink)
set_nlink(vfs_inode, 1);
@@ -1917,7 +1911,6 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
static int delete_conflicting_dir_entry(struct walk_control *wc,
struct btrfs_inode *dir,
- struct btrfs_path *path,
struct btrfs_dir_item *dst_di,
const struct btrfs_key *log_key,
u8 log_flags,
@@ -1925,12 +1918,12 @@ static int delete_conflicting_dir_entry(struct walk_control *wc,
{
struct btrfs_key found_key;
- btrfs_dir_item_key_to_cpu(path->nodes[0], dst_di, &found_key);
+ btrfs_dir_item_key_to_cpu(wc->subvol_path->nodes[0], dst_di, &found_key);
/* The existing dentry points to the same inode, don't delete it. */
if (found_key.objectid == log_key->objectid &&
found_key.type == log_key->type &&
found_key.offset == log_key->offset &&
- btrfs_dir_flags(path->nodes[0], dst_di) == log_flags)
+ btrfs_dir_flags(wc->subvol_path->nodes[0], dst_di) == log_flags)
return 1;
/*
@@ -1940,7 +1933,7 @@ static int delete_conflicting_dir_entry(struct walk_control *wc,
if (!exists)
return 0;
- return drop_one_dir_item(wc, path, dir, dst_di);
+ return drop_one_dir_item(wc, dir, dst_di);
}
/*
@@ -1959,9 +1952,7 @@ static int delete_conflicting_dir_entry(struct walk_control *wc,
* Returns < 0 on error, 0 if the name wasn't replayed (dentry points to a
* non-existing inode) and 1 if the name was replayed.
*/
-static noinline int replay_one_name(struct walk_control *wc,
- struct btrfs_path *path,
- struct btrfs_dir_item *di)
+static noinline int replay_one_name(struct walk_control *wc, struct btrfs_dir_item *di)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -1995,8 +1986,8 @@ static noinline int replay_one_name(struct walk_control *wc,
log_flags = btrfs_dir_flags(wc->log_leaf, di);
btrfs_dir_item_key_to_cpu(wc->log_leaf, di, &log_key);
- ret = btrfs_lookup_inode(trans, root, path, &log_key, 0);
- btrfs_release_path(path);
+ ret = btrfs_lookup_inode(trans, root, wc->subvol_path, &log_key, 0);
+ btrfs_release_path(wc->subvol_path);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
goto out;
@@ -2004,14 +1995,14 @@ static noinline int replay_one_name(struct walk_control *wc,
exists = (ret == 0);
ret = 0;
- dir_dst_di = btrfs_lookup_dir_item(trans, root, path, wc->log_key.objectid,
- &name, 1);
+ dir_dst_di = btrfs_lookup_dir_item(trans, root, wc->subvol_path,
+ wc->log_key.objectid, &name, 1);
if (IS_ERR(dir_dst_di)) {
ret = PTR_ERR(dir_dst_di);
btrfs_abort_transaction(trans, ret);
goto out;
} else if (dir_dst_di) {
- ret = delete_conflicting_dir_entry(wc, dir, path, dir_dst_di,
+ ret = delete_conflicting_dir_entry(wc, dir, dir_dst_di,
&log_key, log_flags, exists);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
@@ -2020,9 +2011,9 @@ static noinline int replay_one_name(struct walk_control *wc,
dir_dst_matches = (ret == 1);
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
- index_dst_di = btrfs_lookup_dir_index_item(trans, root, path,
+ index_dst_di = btrfs_lookup_dir_index_item(trans, root, wc->subvol_path,
wc->log_key.objectid,
wc->log_key.offset, &name, 1);
if (IS_ERR(index_dst_di)) {
@@ -2030,7 +2021,7 @@ static noinline int replay_one_name(struct walk_control *wc,
btrfs_abort_transaction(trans, ret);
goto out;
} else if (index_dst_di) {
- ret = delete_conflicting_dir_entry(wc, dir, path, index_dst_di,
+ ret = delete_conflicting_dir_entry(wc, dir, index_dst_di,
&log_key, log_flags, exists);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
@@ -2039,7 +2030,7 @@ static noinline int replay_one_name(struct walk_control *wc,
index_dst_matches = (ret == 1);
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
if (dir_dst_matches && index_dst_matches) {
ret = 0;
@@ -2104,8 +2095,7 @@ out:
}
/* Replay one dir item from a BTRFS_DIR_INDEX_KEY key. */
-static noinline int replay_one_dir_item(struct walk_control *wc,
- struct btrfs_path *path)
+static noinline int replay_one_dir_item(struct walk_control *wc)
{
int ret;
struct btrfs_dir_item *di;
@@ -2114,7 +2104,7 @@ static noinline int replay_one_dir_item(struct walk_control *wc,
ASSERT(wc->log_key.type == BTRFS_DIR_INDEX_KEY);
di = btrfs_item_ptr(wc->log_leaf, wc->log_slot, struct btrfs_dir_item);
- ret = replay_one_name(wc, path, di);
+ ret = replay_one_name(wc, di);
if (ret < 0)
return ret;
@@ -2148,7 +2138,7 @@ static noinline int replay_one_dir_item(struct walk_control *wc,
struct btrfs_key di_key;
btrfs_dir_item_key_to_cpu(wc->log_leaf, di, &di_key);
- ret = link_to_fixup_dir(wc, path, di_key.objectid);
+ ret = link_to_fixup_dir(wc, di_key.objectid);
}
return ret;
@@ -2242,7 +2232,6 @@ out:
* to is unlinked
*/
static noinline int check_item_in_log(struct walk_control *wc,
- struct btrfs_path *path,
struct btrfs_path *log_path,
struct btrfs_inode *dir,
struct btrfs_key *dir_key,
@@ -2266,8 +2255,8 @@ static noinline int check_item_in_log(struct walk_control *wc,
*/
ASSERT(dir_key->type == BTRFS_DIR_INDEX_KEY);
- eb = path->nodes[0];
- slot = path->slots[0];
+ eb = wc->subvol_path->nodes[0];
+ slot = wc->subvol_path->slots[0];
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name);
if (ret) {
@@ -2293,7 +2282,7 @@ static noinline int check_item_in_log(struct walk_control *wc,
}
btrfs_dir_item_key_to_cpu(eb, di, &location);
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
btrfs_release_path(log_path);
inode = btrfs_iget_logging(location.objectid, root);
if (IS_ERR(inode)) {
@@ -2303,7 +2292,7 @@ static noinline int check_item_in_log(struct walk_control *wc,
goto out;
}
- ret = link_to_fixup_dir(wc, path, location.objectid);
+ ret = link_to_fixup_dir(wc, location.objectid);
if (ret)
goto out;
@@ -2315,7 +2304,7 @@ static noinline int check_item_in_log(struct walk_control *wc,
* (an index number), so we're done.
*/
out:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
btrfs_release_path(log_path);
kfree(name.name);
if (inode)
@@ -2323,7 +2312,7 @@ out:
return ret;
}
-static int replay_xattr_deletes(struct walk_control *wc, struct btrfs_path *path)
+static int replay_xattr_deletes(struct walk_control *wc)
{
struct btrfs_trans_handle *trans = wc->trans;
struct btrfs_root *root = wc->root;
@@ -2331,7 +2320,6 @@ static int replay_xattr_deletes(struct walk_control *wc, struct btrfs_path *path
struct btrfs_key search_key;
struct btrfs_path *log_path;
const u64 ino = wc->log_key.objectid;
- int i;
int nritems;
int ret;
@@ -2345,32 +2333,32 @@ static int replay_xattr_deletes(struct walk_control *wc, struct btrfs_path *path
search_key.type = BTRFS_XATTR_ITEM_KEY;
search_key.offset = 0;
again:
- ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &search_key, wc->subvol_path, 0, 0);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
goto out;
}
process_leaf:
- nritems = btrfs_header_nritems(path->nodes[0]);
- for (i = path->slots[0]; i < nritems; i++) {
+ nritems = btrfs_header_nritems(wc->subvol_path->nodes[0]);
+ for (int i = wc->subvol_path->slots[0]; i < nritems; i++) {
struct btrfs_key key;
struct btrfs_dir_item *di;
struct btrfs_dir_item *log_di;
u32 total_size;
u32 cur;
- btrfs_item_key_to_cpu(path->nodes[0], &key, i);
+ btrfs_item_key_to_cpu(wc->subvol_path->nodes[0], &key, i);
if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY) {
ret = 0;
goto out;
}
- di = btrfs_item_ptr(path->nodes[0], i, struct btrfs_dir_item);
- total_size = btrfs_item_size(path->nodes[0], i);
+ di = btrfs_item_ptr(wc->subvol_path->nodes[0], i, struct btrfs_dir_item);
+ total_size = btrfs_item_size(wc->subvol_path->nodes[0], i);
cur = 0;
while (cur < total_size) {
- u16 name_len = btrfs_dir_name_len(path->nodes[0], di);
- u16 data_len = btrfs_dir_data_len(path->nodes[0], di);
+ u16 name_len = btrfs_dir_name_len(wc->subvol_path->nodes[0], di);
+ u16 data_len = btrfs_dir_data_len(wc->subvol_path->nodes[0], di);
u32 this_len = sizeof(*di) + name_len + data_len;
char *name;
@@ -2380,7 +2368,7 @@ process_leaf:
btrfs_abort_transaction(trans, ret);
goto out;
}
- read_extent_buffer(path->nodes[0], name,
+ read_extent_buffer(wc->subvol_path->nodes[0], name,
(unsigned long)(di + 1), name_len);
log_di = btrfs_lookup_xattr(NULL, log, log_path, ino,
@@ -2388,8 +2376,8 @@ process_leaf:
btrfs_release_path(log_path);
if (!log_di) {
/* Doesn't exist in log tree, so delete it. */
- btrfs_release_path(path);
- di = btrfs_lookup_xattr(trans, root, path, ino,
+ btrfs_release_path(wc->subvol_path);
+ di = btrfs_lookup_xattr(trans, root, wc->subvol_path, ino,
name, name_len, -1);
kfree(name);
if (IS_ERR(di)) {
@@ -2399,12 +2387,12 @@ process_leaf:
}
ASSERT(di);
ret = btrfs_delete_one_dir_name(trans, root,
- path, di);
+ wc->subvol_path, di);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto out;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
search_key = key;
goto again;
}
@@ -2418,7 +2406,7 @@ process_leaf:
di = (struct btrfs_dir_item *)((char *)di + this_len);
}
}
- ret = btrfs_next_leaf(root, path);
+ ret = btrfs_next_leaf(root, wc->subvol_path);
if (ret > 0)
ret = 0;
else if (ret == 0)
@@ -2427,7 +2415,7 @@ process_leaf:
btrfs_abort_transaction(trans, ret);
out:
btrfs_free_path(log_path);
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
return ret;
}
@@ -2443,7 +2431,6 @@ out:
* directory.
*/
static noinline int replay_dir_deletes(struct walk_control *wc,
- struct btrfs_path *path,
u64 dirid, bool del_all)
{
struct btrfs_trans_handle *trans = wc->trans;
@@ -2486,7 +2473,7 @@ static noinline int replay_dir_deletes(struct walk_control *wc,
if (del_all)
range_end = (u64)-1;
else {
- ret = find_dir_range(log, path, dirid,
+ ret = find_dir_range(log, wc->subvol_path, dirid,
&range_start, &range_end);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
@@ -2499,16 +2486,16 @@ static noinline int replay_dir_deletes(struct walk_control *wc,
dir_key.offset = range_start;
while (1) {
int nritems;
- ret = btrfs_search_slot(NULL, root, &dir_key, path,
- 0, 0);
+ ret = btrfs_search_slot(NULL, root, &dir_key,
+ wc->subvol_path, 0, 0);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
goto out;
}
- nritems = btrfs_header_nritems(path->nodes[0]);
- if (path->slots[0] >= nritems) {
- ret = btrfs_next_leaf(root, path);
+ nritems = btrfs_header_nritems(wc->subvol_path->nodes[0]);
+ if (wc->subvol_path->slots[0] >= nritems) {
+ ret = btrfs_next_leaf(root, wc->subvol_path);
if (ret == 1) {
break;
} else if (ret < 0) {
@@ -2516,8 +2503,8 @@ static noinline int replay_dir_deletes(struct walk_control *wc,
goto out;
}
}
- btrfs_item_key_to_cpu(path->nodes[0], &found_key,
- path->slots[0]);
+ btrfs_item_key_to_cpu(wc->subvol_path->nodes[0], &found_key,
+ wc->subvol_path->slots[0]);
if (found_key.objectid != dirid ||
found_key.type != dir_key.type) {
ret = 0;
@@ -2527,22 +2514,21 @@ static noinline int replay_dir_deletes(struct walk_control *wc,
if (found_key.offset > range_end)
break;
- ret = check_item_in_log(wc, path, log_path, dir,
- &found_key, del_all);
+ ret = check_item_in_log(wc, log_path, dir, &found_key, del_all);
if (ret)
goto out;
if (found_key.offset == (u64)-1)
break;
dir_key.offset = found_key.offset + 1;
}
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
if (range_end == (u64)-1)
break;
range_start = range_end + 1;
}
ret = 0;
out:
- btrfs_release_path(path);
+ btrfs_release_path(wc->subvol_path);
btrfs_free_path(log_path);
iput(&dir->vfs_inode);
return ret;
@@ -2567,7 +2553,6 @@ static int replay_one_buffer(struct extent_buffer *eb,
.transid = gen,
.level = level
};
- struct btrfs_path *path;
struct btrfs_root *root = wc->root;
struct btrfs_trans_handle *trans = wc->trans;
int ret;
@@ -2581,8 +2566,9 @@ static int replay_one_buffer(struct extent_buffer *eb,
return ret;
}
- path = btrfs_alloc_path();
- if (!path) {
+ ASSERT(wc->subvol_path == NULL);
+ wc->subvol_path = btrfs_alloc_path();
+ if (!wc->subvol_path) {
btrfs_abort_transaction(trans, -ENOMEM);
return -ENOMEM;
}
@@ -2630,16 +2616,16 @@ static int replay_one_buffer(struct extent_buffer *eb,
wc->stage == LOG_WALK_REPLAY_INODES) {
u32 mode;
- ret = replay_xattr_deletes(wc, path);
+ ret = replay_xattr_deletes(wc);
if (ret)
break;
mode = btrfs_inode_mode(eb, inode_item);
if (S_ISDIR(mode)) {
- ret = replay_dir_deletes(wc, path, wc->log_key.objectid, false);
+ ret = replay_dir_deletes(wc, wc->log_key.objectid, false);
if (ret)
break;
}
- ret = overwrite_item(wc, path);
+ ret = overwrite_item(wc);
if (ret)
break;
@@ -2667,7 +2653,7 @@ static int replay_one_buffer(struct extent_buffer *eb,
drop_args.start = from;
drop_args.end = (u64)-1;
drop_args.drop_cache = true;
- drop_args.path = path;
+ drop_args.path = wc->subvol_path;
ret = btrfs_drop_extents(trans, root, inode, &drop_args);
if (ret) {
btrfs_abort_transaction(trans, ret);
@@ -2684,7 +2670,7 @@ static int replay_one_buffer(struct extent_buffer *eb,
break;
}
- ret = link_to_fixup_dir(wc, path, wc->log_key.objectid);
+ ret = link_to_fixup_dir(wc, wc->log_key.objectid);
if (ret)
break;
}
@@ -2694,7 +2680,7 @@ static int replay_one_buffer(struct extent_buffer *eb,
if (wc->log_key.type == BTRFS_DIR_INDEX_KEY &&
wc->stage == LOG_WALK_REPLAY_DIR_INDEX) {
- ret = replay_one_dir_item(wc, path);
+ ret = replay_one_dir_item(wc);
if (ret)
break;
}
@@ -2704,16 +2690,16 @@ static int replay_one_buffer(struct extent_buffer *eb,
/* these keys are simply copied */
if (wc->log_key.type == BTRFS_XATTR_ITEM_KEY) {
- ret = overwrite_item(wc, path);
+ ret = overwrite_item(wc);
if (ret)
break;
} else if (wc->log_key.type == BTRFS_INODE_REF_KEY ||
wc->log_key.type == BTRFS_INODE_EXTREF_KEY) {
- ret = add_inode_ref(wc, path);
+ ret = add_inode_ref(wc);
if (ret)
break;
} else if (wc->log_key.type == BTRFS_EXTENT_DATA_KEY) {
- ret = replay_one_extent(wc, path);
+ ret = replay_one_extent(wc);
if (ret)
break;
}
@@ -2724,7 +2710,8 @@ static int replay_one_buffer(struct extent_buffer *eb,
* older kernel with such keys, ignore them.
*/
}
- btrfs_free_path(path);
+ btrfs_free_path(wc->subvol_path);
+ wc->subvol_path = NULL;
return ret;
}
@@ -7515,7 +7502,9 @@ again:
if (wc.stage == LOG_WALK_REPLAY_ALL) {
struct btrfs_root *root = wc.root;
- ret = fixup_inode_link_counts(&wc, path);
+ wc.subvol_path = path;
+ ret = fixup_inode_link_counts(&wc);
+ wc.subvol_path = NULL;
if (ret) {
btrfs_abort_transaction(trans, ret);
goto next;