* [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs
@ 2023-04-29 20:19 Josef Bacik
2023-04-29 20:19 ` [PATCH 01/26] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
` (26 more replies)
0 siblings, 27 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
Hello,
This is a long series, and it depends on the following series
btrfs-progs: prep work for syncing files into kernel-shared
btrfs-progs: sync basic code from the kernel
btrfs-progs: prep work for syncing ctree.c
btrfs-progs: more prep work for syncing ctree.c
This is even more more prep work for syncing ctree.c, and the last patch is the
actual sync. A lot of these prep patches are updating the callers to match the
current calling conventions in the kernel to make the syncing straightforward.
This entire series passes our tests. Thanks,
Josef
Josef Bacik (26):
btrfs-progs: stop using add_root_to_dirty_list in check
btrfs-progs: remove useless add_root_to_dirty_list call in mkfs
btrfs-progs: remove add_root_to_dirty_list call when creating free
space tree
btrfs-progs: make add_root_to_dirty_list static and unexport it
btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty
btrfs-progs: update read_node_slot to match the kernel definition
btrfs-progs: update btrfs_bin_search to match the kernel definition
btrfs-progs: update btrfs_set_item_key_safe to match kernel definition
btrfs-progs: update btrfs_print_leaf to match the kernel definition
btrfs-progs: update btrfs_truncate_item to match the kernel definition
btrfs-progs: update btrfs_extend_item to match the kernel definition
btrfs-progs: sync memcpy_extent_buffer from the kernel
btrfs-progs: change how we check supported csum type
btrfs-progs: drop btrfs_init_path
btrfs-progs: move btrfs_set_item_key_unsafe to check/
btrfs-progs: move btrfs_record_file_extent and code into a new file
btrfs-progs: make a local copy of btrfs_next_sibling_block in
print-tree.c
btrfs-progs: don't set the ->commit_root in btrfs_create_tree
btrfs-progs: remove btrfs_create_root
btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c
btrfs-progs: make btrfs_del_ptr a void
btrfs-progs: replace blocksize with parent argument for
btrfs_alloc_tree_block
btrfs-progs: use path->search_for_extension
btrfs-progs: add write_extent_buffer_chunk_tree_uuid helper
btrfs-progs: init new tree blocks in btrfs_alloc_tree_block
btrfs-progs: sync ctree.c from the kernel
Makefile | 1 +
btrfs-corrupt-block.c | 1 +
btrfs-map-logical.c | 1 +
check/clear-cache.c | 10 +-
check/main.c | 114 +-
check/mode-common.c | 35 +-
check/mode-lowmem.c | 84 +-
check/qgroup-verify.c | 14 +-
check/repair.c | 50 +-
check/repair.h | 5 +
cmds/inspect-dump-tree.c | 5 +-
cmds/inspect-tree-stats.c | 3 +-
cmds/rescue-chunk-recover.c | 16 +-
cmds/rescue.c | 2 +-
cmds/restore.c | 26 +-
common/extent-tree-utils.c | 282 ++
common/extent-tree-utils.h | 28 +
convert/main.c | 10 +-
convert/source-fs.c | 5 +-
image/main.c | 13 +-
include/kerncompat.h | 80 +
kernel-lib/trace.h | 8 +
kernel-shared/ctree.c | 4848 ++++++++++++++++++++----------
kernel-shared/ctree.h | 138 +-
kernel-shared/dir-item.c | 4 +-
kernel-shared/disk-io.c | 36 +-
kernel-shared/extent-tree.c | 281 +-
kernel-shared/extent_io.c | 16 +-
kernel-shared/extent_io.h | 9 +-
kernel-shared/file-item.c | 15 +-
kernel-shared/file.c | 3 +-
kernel-shared/free-space-cache.c | 4 +-
kernel-shared/free-space-tree.c | 1 -
kernel-shared/inode-item.c | 5 +-
kernel-shared/inode.c | 5 +-
kernel-shared/locking.c | 6 +-
kernel-shared/print-tree.c | 62 +-
kernel-shared/print-tree.h | 7 +-
kernel-shared/transaction.c | 9 +-
kernel-shared/volumes.c | 6 +-
mkfs/main.c | 89 +-
mkfs/rootdir.c | 11 +-
quick-test.c | 6 +-
tune/change-csum.c | 23 +-
tune/change-uuid.c | 6 +-
tune/convert-bgt.c | 13 +-
46 files changed, 4245 insertions(+), 2151 deletions(-)
create mode 100644 common/extent-tree-utils.c
create mode 100644 common/extent-tree-utils.h
--
2.40.0
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 01/26] btrfs-progs: stop using add_root_to_dirty_list in check
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 02/26] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
` (25 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This is used to make sure the root is updated in the tree_root when we
re-init the root, however this function is static in the kernel and
doesn't need to be exported for any reason. Simply update the root item
and then update it in the tree_root instead of adding it to the dirty
list.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/check/main.c b/check/main.c
index 8714c213..d9c54deb 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9163,8 +9163,12 @@ static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
free_extent_buffer(root->node);
root->node = c;
- add_root_to_dirty_list(root);
- return 0;
+
+ btrfs_set_root_bytenr(&root->root_item, c->start);
+ btrfs_set_root_generation(&root->root_item, trans->transid);
+
+ return btrfs_update_root(trans, gfs_info->tree_root, &root->root_key,
+ &root->root_item);
}
static int reset_block_groups(void)
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 02/26] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
2023-04-29 20:19 ` [PATCH 01/26] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 03/26] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
` (24 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
We are calling this when creating the UUID tree, however when we create
the tree it inserts the root item into the tree_root, so this call is
superfluous.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
mkfs/main.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/mkfs/main.c b/mkfs/main.c
index 4856cf96..418c721c 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -789,7 +789,6 @@ static int create_uuid_tree(struct btrfs_trans_handle *trans)
goto out;
}
- add_root_to_dirty_list(root);
fs_info->uuid_root = root;
ret = btrfs_uuid_tree_add(trans, fs_info->fs_root->root_item.uuid,
BTRFS_UUID_KEY_SUBVOL,
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 03/26] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
2023-04-29 20:19 ` [PATCH 01/26] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
2023-04-29 20:19 ` [PATCH 02/26] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 04/26] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
` (23 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
Since we insert the free space tree item into the tree_root when we
create the tree we don't need to call add_root_to_dirty_list.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/free-space-tree.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/kernel-shared/free-space-tree.c b/kernel-shared/free-space-tree.c
index 4064b7cb..a8a0a6ec 100644
--- a/kernel-shared/free-space-tree.c
+++ b/kernel-shared/free-space-tree.c
@@ -1522,7 +1522,6 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
ret = btrfs_global_root_insert(fs_info, free_space_root);
if (ret)
goto abort;
- add_root_to_dirty_list(free_space_root);
do {
block_group = btrfs_lookup_first_block_group(fs_info, start);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 04/26] btrfs-progs: make add_root_to_dirty_list static and unexport it
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (2 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 03/26] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 05/26] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
` (22 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
Now that there are no users of this helper outside of ctree.c, unexport
it and make it static.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 2 +-
kernel-shared/ctree.h | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index d5a1f90b..3cb3378e 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -119,7 +119,7 @@ void btrfs_release_path(struct btrfs_path *p)
memset(p, 0, sizeof(*p));
}
-void add_root_to_dirty_list(struct btrfs_root *root)
+static void add_root_to_dirty_list(struct btrfs_root *root)
{
if (test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state) &&
list_empty(&root->dirty_list)) {
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 5eba9c14..ce050cec 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -988,7 +988,6 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key);
void btrfs_release_path(struct btrfs_path *p);
-void add_root_to_dirty_list(struct btrfs_root *root);
struct btrfs_path *btrfs_alloc_path(void);
void btrfs_free_path(struct btrfs_path *p);
void btrfs_init_path(struct btrfs_path *p);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 05/26] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (3 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 04/26] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 06/26] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
` (21 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This is the calling convention in the kernel because we track dirty
blocks per transaction instead of globally in the fs_info. Simply
mirror what we do in the kernel to make it easier to sync ctree.c
locally.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
cmds/rescue.c | 2 +-
kernel-shared/ctree.c | 12 ++++++------
kernel-shared/disk-io.c | 2 +-
kernel-shared/extent-tree.c | 2 +-
kernel-shared/extent_io.c | 3 ++-
kernel-shared/extent_io.h | 4 +++-
kernel-shared/transaction.c | 4 ++--
7 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/cmds/rescue.c b/cmds/rescue.c
index 5551374d..75a4192f 100644
--- a/cmds/rescue.c
+++ b/cmds/rescue.c
@@ -340,7 +340,7 @@ static int clear_uuid_tree(struct btrfs_fs_info *fs_info)
if (ret < 0)
goto out;
list_del(&uuid_root->dirty_list);
- ret = btrfs_clear_buffer_dirty(uuid_root->node);
+ ret = btrfs_clear_buffer_dirty(trans, uuid_root->node);
if (ret < 0)
goto out;
ret = btrfs_free_tree_block(trans, btrfs_root_id(uuid_root),
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 3cb3378e..b127dcf9 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -434,7 +434,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_dec_ref(trans, root, buf, 1);
BUG_ON(ret);
}
- btrfs_clear_buffer_dirty(buf);
+ btrfs_clear_buffer_dirty(trans, buf);
}
return 0;
}
@@ -760,7 +760,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
root->node = child;
add_root_to_dirty_list(root);
path->nodes[level] = NULL;
- btrfs_clear_buffer_dirty(mid);
+ btrfs_clear_buffer_dirty(trans, mid);
/* once for the path */
free_extent_buffer(mid);
@@ -814,7 +814,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
u64 bytenr = right->start;
u32 blocksize = right->len;
- btrfs_clear_buffer_dirty(right);
+ btrfs_clear_buffer_dirty(trans, right);
free_extent_buffer(right);
right = NULL;
wret = btrfs_del_ptr(root, path, level + 1, pslot + 1);
@@ -861,7 +861,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* we've managed to empty the middle node, drop it */
u64 bytenr = mid->start;
u32 blocksize = mid->len;
- btrfs_clear_buffer_dirty(mid);
+ btrfs_clear_buffer_dirty(trans, mid);
free_extent_buffer(mid);
mid = NULL;
wret = btrfs_del_ptr(root, path, level + 1, pslot);
@@ -2834,7 +2834,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
if (leaf == root->node) {
btrfs_set_header_level(leaf, 0);
} else {
- btrfs_clear_buffer_dirty(leaf);
+ btrfs_clear_buffer_dirty(trans, leaf);
wret = btrfs_del_leaf(trans, root, path, leaf);
BUG_ON(ret);
if (wret)
@@ -2870,7 +2870,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
if (btrfs_header_nritems(leaf) == 0) {
- btrfs_clear_buffer_dirty(leaf);
+ btrfs_clear_buffer_dirty(trans, leaf);
path->slots[1] = slot;
ret = btrfs_del_leaf(trans, root, path, leaf);
BUG_ON(ret);
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index 536b7119..3e0c3534 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2318,7 +2318,7 @@ int btrfs_delete_and_free_root(struct btrfs_trans_handle *trans,
return ret;
list_del(&root->dirty_list);
- ret = btrfs_clear_buffer_dirty(root->node);
+ ret = btrfs_clear_buffer_dirty(trans, root->node);
if (ret)
return ret;
ret = btrfs_free_tree_block(trans, btrfs_root_id(root), root->node, 0, 1);
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 062ff4a7..bbce9587 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1899,7 +1899,7 @@ static int pin_down_bytes(struct btrfs_trans_handle *trans, u64 bytenr,
if (header_owner != BTRFS_TREE_LOG_OBJECTID &&
header_transid == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
- btrfs_clear_buffer_dirty(buf);
+ btrfs_clear_buffer_dirty(trans, buf);
free_extent_buffer(buf);
return 1;
}
diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c
index 105b5ec8..e38bb1ed 100644
--- a/kernel-shared/extent_io.c
+++ b/kernel-shared/extent_io.c
@@ -585,7 +585,8 @@ int set_extent_buffer_dirty(struct extent_buffer *eb)
return 0;
}
-int btrfs_clear_buffer_dirty(struct extent_buffer *eb)
+int btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
+ struct extent_buffer *eb)
{
struct extent_io_tree *tree = &eb->fs_info->dirty_buffers;
if (eb->flags & EXTENT_BUFFER_DIRTY) {
diff --git a/kernel-shared/extent_io.h b/kernel-shared/extent_io.h
index a1cda3a5..f573a4e2 100644
--- a/kernel-shared/extent_io.h
+++ b/kernel-shared/extent_io.h
@@ -54,6 +54,7 @@ static inline int le_test_bit(int nr, const u8 *addr)
}
struct btrfs_fs_info;
+struct btrfs_trans_handle;
struct extent_buffer {
struct cache_extent cache_node;
@@ -125,7 +126,8 @@ void memset_extent_buffer(const struct extent_buffer *eb, char c,
int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
unsigned long nr);
int set_extent_buffer_dirty(struct extent_buffer *eb);
-int btrfs_clear_buffer_dirty(struct extent_buffer *eb);
+int btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
+ struct extent_buffer *eb);
int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 logical,
u64 *len, int mirror);
int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
diff --git a/kernel-shared/transaction.c b/kernel-shared/transaction.c
index f99bc684..1e1ec85b 100644
--- a/kernel-shared/transaction.c
+++ b/kernel-shared/transaction.c
@@ -161,7 +161,7 @@ again:
goto cleanup;
}
start += eb->len;
- btrfs_clear_buffer_dirty(eb);
+ btrfs_clear_buffer_dirty(trans, eb);
free_extent_buffer(eb);
}
}
@@ -184,7 +184,7 @@ cleanup:
eb = find_first_extent_buffer(fs_info, start);
BUG_ON(!eb || eb->start != start);
start += eb->len;
- btrfs_clear_buffer_dirty(eb);
+ btrfs_clear_buffer_dirty(trans, eb);
free_extent_buffer(eb);
}
}
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 06/26] btrfs-progs: update read_node_slot to match the kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (4 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 05/26] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 07/26] btrfs-progs: update btrfs_bin_search " Josef Bacik
` (20 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In the kernel this is called btrfs_read_node_slot, and it doesn't take a
btrfs_fs_info. Update the btrfs-progs version to match the kernel and
update all of the callers.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
cmds/restore.c | 5 ++---
kernel-shared/ctree.c | 32 +++++++++++++++-----------------
kernel-shared/ctree.h | 4 ++--
kernel-shared/print-tree.c | 2 +-
4 files changed, 20 insertions(+), 23 deletions(-)
diff --git a/cmds/restore.c b/cmds/restore.c
index 9fe7b4d2..31cad31f 100644
--- a/cmds/restore.c
+++ b/cmds/restore.c
@@ -240,7 +240,6 @@ static int next_leaf(struct btrfs_root *root, struct btrfs_path *path)
int offset = 1;
struct extent_buffer *c;
struct extent_buffer *next = NULL;
- struct btrfs_fs_info *fs_info = root->fs_info;
again:
for (; level < BTRFS_MAX_LEVEL; level++) {
@@ -267,7 +266,7 @@ again:
continue;
}
- next = read_node_slot(fs_info, c, slot);
+ next = btrfs_read_node_slot(c, slot);
if (extent_buffer_uptodate(next))
break;
offset++;
@@ -281,7 +280,7 @@ again:
path->slots[level] = 0;
if (!level)
break;
- next = read_node_slot(fs_info, next, 0);
+ next = btrfs_read_node_slot(next, 0);
if (!extent_buffer_uptodate(next))
goto again;
}
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index b127dcf9..cbf735de 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -681,9 +681,10 @@ int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,
slot);
}
-struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
- struct extent_buffer *parent, int slot)
+struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
+ int slot)
{
+ struct btrfs_fs_info *fs_info = parent->fs_info;
struct extent_buffer *ret;
int level = btrfs_header_level(parent);
@@ -752,7 +753,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
return 0;
/* promote the child to a root */
- child = read_node_slot(fs_info, mid, 0);
+ child = btrfs_read_node_slot(mid, 0);
BUG_ON(!extent_buffer_uptodate(child));
ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
BUG_ON(ret);
@@ -776,7 +777,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)
return 0;
- left = read_node_slot(fs_info, parent, pslot - 1);
+ left = btrfs_read_node_slot(parent, pslot - 1);
if (extent_buffer_uptodate(left)) {
wret = btrfs_cow_block(trans, root, left,
parent, pslot - 1, &left);
@@ -785,7 +786,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
goto enospc;
}
}
- right = read_node_slot(fs_info, parent, pslot + 1);
+ right = btrfs_read_node_slot(parent, pslot + 1);
if (extent_buffer_uptodate(right)) {
wret = btrfs_cow_block(trans, root, right,
parent, pslot + 1, &right);
@@ -937,7 +938,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
if (!parent)
return 1;
- left = read_node_slot(fs_info, parent, pslot - 1);
+ left = btrfs_read_node_slot(parent, pslot - 1);
/* first, try to make some room in the middle buffer */
if (extent_buffer_uptodate(left)) {
@@ -978,7 +979,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
}
free_extent_buffer(left);
}
- right= read_node_slot(fs_info, parent, pslot + 1);
+ right= btrfs_read_node_slot(parent, pslot + 1);
/*
* then try to empty the right most buffer into the middle
@@ -1230,7 +1231,7 @@ again:
reada_for_search(fs_info, p, level, slot,
key->objectid);
- b = read_node_slot(fs_info, b, slot);
+ b = btrfs_read_node_slot(b, slot);
if (!extent_buffer_uptodate(b))
return -EIO;
} else {
@@ -1789,7 +1790,6 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
struct extent_buffer *right;
struct extent_buffer *upper;
struct btrfs_disk_key disk_key;
- struct btrfs_fs_info *fs_info = root->fs_info;
int slot;
u32 i;
int free_space;
@@ -1810,7 +1810,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
if (slot >= btrfs_header_nritems(upper) - 1)
return 1;
- right = read_node_slot(fs_info, upper, slot + 1);
+ right = btrfs_read_node_slot(upper, slot + 1);
if (!extent_buffer_uptodate(right)) {
if (IS_ERR(right))
return PTR_ERR(right);
@@ -1938,7 +1938,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
struct btrfs_disk_key disk_key;
struct extent_buffer *right = path->nodes[0];
struct extent_buffer *left;
- struct btrfs_fs_info *fs_info = root->fs_info;
int slot;
int i;
int free_space;
@@ -1962,7 +1961,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
return 1;
}
- left = read_node_slot(fs_info, path->nodes[1], slot - 1);
+ left = btrfs_read_node_slot(path->nodes[1], slot - 1);
free_space = btrfs_leaf_free_space(left);
if (free_space < data_size) {
free_extent_buffer(left);
@@ -2898,7 +2897,6 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
int level = 1;
struct extent_buffer *c;
struct extent_buffer *next = NULL;
- struct btrfs_fs_info *fs_info = root->fs_info;
while(level < BTRFS_MAX_LEVEL) {
if (!path->nodes[level])
@@ -2914,7 +2912,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
}
slot--;
- next = read_node_slot(fs_info, c, slot);
+ next = btrfs_read_node_slot(c, slot);
if (!extent_buffer_uptodate(next)) {
if (IS_ERR(next))
return PTR_ERR(next);
@@ -2934,7 +2932,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
path->slots[level] = slot;
if (!level)
break;
- next = read_node_slot(fs_info, next, slot);
+ next = btrfs_read_node_slot(next, slot);
if (!extent_buffer_uptodate(next)) {
if (IS_ERR(next))
return PTR_ERR(next);
@@ -2977,7 +2975,7 @@ int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
if (path->reada)
reada_for_search(fs_info, path, level, slot, 0);
- next = read_node_slot(fs_info, c, slot);
+ next = btrfs_read_node_slot(c, slot);
if (!extent_buffer_uptodate(next))
return -EIO;
break;
@@ -3000,7 +2998,7 @@ int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
break;
if (path->reada)
reada_for_search(fs_info, path, level, 0, 0);
- next = read_node_slot(fs_info, next, 0);
+ next = btrfs_read_node_slot(next, 0);
if (!extent_buffer_uptodate(next))
return -EIO;
}
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index ce050cec..edf74fcc 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -948,8 +948,8 @@ int btrfs_convert_one_bg(struct btrfs_trans_handle *trans, u64 bytenr);
int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot);
-struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
- struct extent_buffer *parent, int slot);
+struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
+ int slot);
int btrfs_previous_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid,
int type);
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 6cdfdef7..594c524f 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1487,7 +1487,7 @@ static int search_leftmost_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb;
path->slots[i] = 0;
- eb = read_node_slot(fs_info, path->nodes[i], 0);
+ eb = btrfs_read_node_slot(path->nodes[i], 0);
if (!extent_buffer_uptodate(eb)) {
ret = -EIO;
goto out;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 07/26] btrfs-progs: update btrfs_bin_search to match the kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (5 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 06/26] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 08/26] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
` (19 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This was updated to include a first_slot argument, update it to match
the kernel definition to make it easier to sync ctree.c.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/main.c | 2 +-
kernel-shared/ctree.c | 6 +++---
kernel-shared/ctree.h | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/check/main.c b/check/main.c
index d9c54deb..a6485db5 100644
--- a/check/main.c
+++ b/check/main.c
@@ -6524,7 +6524,7 @@ static int run_next_block(struct btrfs_root *root,
* technically unreferenced and don't need to be worried about.
*/
if (ri != NULL && ri->drop_level && level > ri->drop_level) {
- ret = btrfs_bin_search(buf, &ri->drop_key, &i);
+ ret = btrfs_bin_search(buf, 0, &ri->drop_key, &i);
if (ret && i > 0)
i--;
}
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index cbf735de..2e7b6c9a 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -664,8 +664,8 @@ static int generic_bin_search(struct extent_buffer *eb, unsigned long p,
* simple bin_search frontend that does the right thing for
* leaves vs nodes
*/
-int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,
- int *slot)
+int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
+ const struct btrfs_key *key, int *slot)
{
if (btrfs_header_level(eb) == 0)
return generic_bin_search(eb,
@@ -1196,7 +1196,7 @@ again:
ret = check_block(fs_info, p, level);
if (ret)
return -1;
- ret = btrfs_bin_search(b, key, &slot);
+ ret = btrfs_bin_search(b, 0, key, &slot);
if (level != 0) {
if (ret && slot > 0)
slot -= 1;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index edf74fcc..d5797d09 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -982,8 +982,8 @@ int btrfs_search_slot_for_read(struct btrfs_root *root,
const struct btrfs_key *key,
struct btrfs_path *p, int find_higher,
int return_any);
-int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,
- int *slot);
+int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
+ const struct btrfs_key *key, int *slot);
int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 08/26] btrfs-progs: update btrfs_set_item_key_safe to match kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (6 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 07/26] btrfs-progs: update btrfs_bin_search " Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 09/26] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
` (18 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In the kernel we just pass the btrfs_fs_info, and we const'ify the
new_key. Update the btrfs-progs definition to make syncing ctree.c
easier.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 12 +++++-------
kernel-shared/ctree.h | 5 +++--
kernel-shared/file-item.c | 3 +--
3 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 2e7b6c9a..94aa45a3 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1355,8 +1355,9 @@ void btrfs_fixup_low_keys( struct btrfs_path *path, struct btrfs_disk_key *key,
* This function isn't completely safe. It's the caller's responsibility
* that the new key won't break the order
*/
-int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
- struct btrfs_key *new_key)
+void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
+ struct btrfs_path *path,
+ const struct btrfs_key *new_key)
{
struct btrfs_disk_key disk_key;
struct extent_buffer *eb;
@@ -1366,13 +1367,11 @@ int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
slot = path->slots[0];
if (slot > 0) {
btrfs_item_key(eb, &disk_key, slot - 1);
- if (btrfs_comp_keys(&disk_key, new_key) >= 0)
- return -1;
+ BUG_ON(btrfs_comp_keys(&disk_key, new_key) >= 0);
}
if (slot < btrfs_header_nritems(eb) - 1) {
btrfs_item_key(eb, &disk_key, slot + 1);
- if (btrfs_comp_keys(&disk_key, new_key) <= 0)
- return -1;
+ BUG_ON(btrfs_comp_keys(&disk_key, new_key) <= 0);
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -1380,7 +1379,6 @@ int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
btrfs_mark_buffer_dirty(eb);
if (slot == 0)
btrfs_fixup_low_keys(path, &disk_key, 1);
- return 0;
}
/*
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index d5797d09..e54d3bc3 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1055,8 +1055,9 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct extent_buffer *leaf);
void btrfs_fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
int level);
-int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
- struct btrfs_key *new_key);
+void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
+ struct btrfs_path *path,
+ const struct btrfs_key *new_key);
void btrfs_set_item_key_unsafe(struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key);
diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c
index 9f8a3296..87f80bfe 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -389,8 +389,7 @@ static noinline int truncate_one_csum(struct btrfs_root *root,
BUG_ON(ret);
key->offset = end_byte;
- ret = btrfs_set_item_key_safe(root, path, key);
- BUG_ON(ret);
+ btrfs_set_item_key_safe(root->fs_info, path, key);
} else {
BUG();
}
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 09/26] btrfs-progs: update btrfs_print_leaf to match the kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (7 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 08/26] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 10/26] btrfs-progs: update btrfs_truncate_item " Josef Bacik
` (17 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In the kernel we have btrfs_print_leaf(eb) instead of
btrfs_print_leaf(eb, mode). In fact in all of the kernel-shared sources
we're just using the default mode. Fix this to have a
__btrfs_print_leaf() which handles the mode for the user space utilities
that want the different behavior, and then change btrfs_print_leaf() to
just be the normal default style.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
cmds/inspect-dump-tree.c | 2 +-
kernel-shared/ctree.c | 16 ++++++++--------
kernel-shared/extent-tree.c | 8 ++++----
kernel-shared/print-tree.c | 4 ++--
kernel-shared/print-tree.h | 7 ++++++-
5 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/cmds/inspect-dump-tree.c b/cmds/inspect-dump-tree.c
index 7c524b04..5385208d 100644
--- a/cmds/inspect-dump-tree.c
+++ b/cmds/inspect-dump-tree.c
@@ -52,7 +52,7 @@ static void print_extents(struct extent_buffer *eb)
return;
if (btrfs_is_leaf(eb)) {
- btrfs_print_leaf(eb, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(eb);
return;
}
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 94aa45a3..a23128ee 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2418,7 +2418,7 @@ split:
ret = 0;
if (btrfs_leaf_free_space(leaf) < 0) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
BUG();
}
kfree(buf);
@@ -2510,7 +2510,7 @@ int btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
ret = 0;
if (btrfs_leaf_free_space(leaf) < 0) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
BUG();
}
return ret;
@@ -2534,7 +2534,7 @@ int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
data_end = leaf_data_end(leaf);
if (btrfs_leaf_free_space(leaf) < data_size) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
BUG();
}
slot = path->slots[0];
@@ -2542,7 +2542,7 @@ int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
BUG_ON(slot < 0);
if (slot >= nritems) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
printk("slot %d too large, nritems %u\n", slot, nritems);
BUG_ON(1);
}
@@ -2569,7 +2569,7 @@ int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
ret = 0;
if (btrfs_leaf_free_space(leaf) < 0) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
BUG();
}
return ret;
@@ -2617,7 +2617,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
data_end = leaf_data_end(leaf);
if (btrfs_leaf_free_space(leaf) < total_size) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
printk("not enough freespace need %u have %d\n",
total_size, btrfs_leaf_free_space(leaf));
BUG();
@@ -2630,7 +2630,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
unsigned int old_data = btrfs_item_data_end(leaf, slot);
if (old_data < data_end) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
printk("slot %d old_data %u data_end %u\n",
slot, old_data, data_end);
BUG_ON(1);
@@ -2676,7 +2676,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
}
if (btrfs_leaf_free_space(leaf) < 0) {
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
BUG();
}
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index bbce9587..fa83d152 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -937,7 +937,7 @@ again:
printf("Size is %u, needs to be %u, slot %d\n",
(unsigned)item_size,
(unsigned)sizeof(*ei), path->slots[0]);
- btrfs_print_leaf(leaf, BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(leaf);
return -EINVAL;
}
@@ -1428,7 +1428,7 @@ again:
}
if (ret != 0) {
- btrfs_print_leaf(path->nodes[0], BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(path->nodes[0]);
printk("failed to find block number %llu\n",
(unsigned long long)bytenr);
BUG();
@@ -2034,7 +2034,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
printk(KERN_ERR "umm, got %d back from search"
", was looking for %llu\n", ret,
(unsigned long long)bytenr);
- btrfs_print_leaf(path->nodes[0], BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(path->nodes[0]);
}
BUG_ON(ret);
extent_slot = path->slots[0];
@@ -2048,7 +2048,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
(unsigned long long)owner_objectid,
(unsigned long long)owner_offset);
printf("path->slots[0]: %d path->nodes[0]:\n", path->slots[0]);
- btrfs_print_leaf(path->nodes[0], BTRFS_PRINT_TREE_DEFAULT);
+ btrfs_print_leaf(path->nodes[0]);
ret = -EIO;
goto fail;
}
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 594c524f..ff2a8097 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1294,7 +1294,7 @@ static void print_header_info(struct extent_buffer *eb, unsigned int mode)
fflush(stdout);
}
-void btrfs_print_leaf(struct extent_buffer *eb, unsigned int mode)
+void __btrfs_print_leaf(struct extent_buffer *eb, unsigned int mode)
{
struct btrfs_disk_key disk_key;
u32 leaf_data_size = BTRFS_LEAF_DATA_SIZE(eb->fs_info);
@@ -1607,7 +1607,7 @@ void btrfs_print_tree(struct extent_buffer *eb, unsigned int mode)
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
- btrfs_print_leaf(eb, mode);
+ __btrfs_print_leaf(eb, mode);
return;
}
/* We are crossing eb boundary, this node must be corrupted */
diff --git a/kernel-shared/print-tree.h b/kernel-shared/print-tree.h
index 80fb6ef7..c1e75d1e 100644
--- a/kernel-shared/print-tree.h
+++ b/kernel-shared/print-tree.h
@@ -34,7 +34,12 @@ enum {
};
void btrfs_print_tree(struct extent_buffer *eb, unsigned int mode);
-void btrfs_print_leaf(struct extent_buffer *eb, unsigned int mode);
+void __btrfs_print_leaf(struct extent_buffer *eb, unsigned int mode);
+
+static inline void btrfs_print_leaf(struct extent_buffer *eb)
+{
+ __btrfs_print_leaf(eb, BTRFS_PRINT_TREE_DEFAULT);
+}
void btrfs_print_key(struct btrfs_disk_key *disk_key);
void print_chunk_item(struct extent_buffer *eb, struct btrfs_chunk *chunk);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 10/26] btrfs-progs: update btrfs_truncate_item to match the kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (8 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 09/26] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 11/26] btrfs-progs: update btrfs_extend_item " Josef Bacik
` (16 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This is void in the kernel, and this makes sense in btrfs-progs as it
stands currently as it doesn't actually return an error if there's a
problem, it simply BUG()'s. Update this to be a void and update the
callers to make it easier to sync ctree.c.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 7 ++-----
kernel-shared/ctree.h | 2 +-
kernel-shared/extent-tree.c | 4 +---
kernel-shared/file-item.c | 7 ++-----
4 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index a23128ee..d78a3258 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2425,9 +2425,8 @@ split:
return ret;
}
-int btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
+void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
{
- int ret = 0;
int slot;
struct extent_buffer *leaf;
u32 nritems;
@@ -2442,7 +2441,7 @@ int btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
old_size = btrfs_item_size(leaf, slot);
if (old_size == new_size)
- return 0;
+ return;
nritems = btrfs_header_nritems(leaf);
data_end = leaf_data_end(leaf);
@@ -2508,12 +2507,10 @@ int btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
btrfs_set_item_size(leaf, slot, new_size);
btrfs_mark_buffer_dirty(leaf);
- ret = 0;
if (btrfs_leaf_free_space(leaf) < 0) {
btrfs_print_leaf(leaf);
BUG();
}
- return ret;
}
int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index e54d3bc3..18562f3b 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -969,7 +969,7 @@ int btrfs_create_root(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 objectid);
int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
u32 data_size);
-int btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end);
+void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index fa83d152..718a4fc9 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1129,7 +1129,6 @@ static int update_inline_extent_backref(struct btrfs_trans_handle *trans,
u32 item_size;
int size;
int type;
- int ret;
u64 refs;
leaf = path->nodes[0];
@@ -1169,8 +1168,7 @@ static int update_inline_extent_backref(struct btrfs_trans_handle *trans,
memmove_extent_buffer(leaf, ptr, ptr + size,
end - ptr - size);
item_size -= size;
- ret = btrfs_truncate_item(path, item_size, 1);
- BUG_ON(ret);
+ btrfs_truncate_item(path, item_size, 1);
}
btrfs_mark_buffer_dirty(leaf);
return 0;
diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c
index 87f80bfe..6e0f7381 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -356,7 +356,6 @@ static noinline int truncate_one_csum(struct btrfs_root *root,
u64 csum_end;
u64 end_byte = bytenr + len;
u32 blocksize = root->fs_info->sectorsize;
- int ret;
leaf = path->nodes[0];
csum_end = btrfs_item_size(leaf, path->slots[0]) / csum_size;
@@ -372,8 +371,7 @@ static noinline int truncate_one_csum(struct btrfs_root *root,
*/
u32 new_size = (bytenr - key->offset) / blocksize;
new_size *= csum_size;
- ret = btrfs_truncate_item(path, new_size, 1);
- BUG_ON(ret);
+ btrfs_truncate_item(path, new_size, 1);
} else if (key->offset >= bytenr && csum_end > end_byte &&
end_byte > key->offset) {
/*
@@ -385,8 +383,7 @@ static noinline int truncate_one_csum(struct btrfs_root *root,
u32 new_size = (csum_end - end_byte) / blocksize;
new_size *= csum_size;
- ret = btrfs_truncate_item(path, new_size, 0);
- BUG_ON(ret);
+ btrfs_truncate_item(path, new_size, 0);
key->offset = end_byte;
btrfs_set_item_key_safe(root->fs_info, path, key);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 11/26] btrfs-progs: update btrfs_extend_item to match the kernel definition
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (9 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 10/26] btrfs-progs: update btrfs_truncate_item " Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 12/26] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
` (15 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
Similar to btrfs_truncate_item(), this is void in the kernel as the
failure case is simply BUG_ON(). Additionally there is no root
parameter as it's not used in the function at all. Make these changes
and update the callers.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 8 ++------
kernel-shared/ctree.h | 3 +--
kernel-shared/dir-item.c | 4 ++--
kernel-shared/extent-tree.c | 4 +---
kernel-shared/file-item.c | 3 +--
kernel-shared/inode-item.c | 5 ++---
tune/change-csum.c | 3 +--
7 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index d78a3258..97164cb8 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2513,10 +2513,8 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
}
}
-int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
- u32 data_size)
+void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
{
- int ret = 0;
int slot;
struct extent_buffer *leaf;
u32 nritems;
@@ -2564,12 +2562,10 @@ int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
btrfs_set_item_size(leaf, slot, old_size + data_size);
btrfs_mark_buffer_dirty(leaf);
- ret = 0;
if (btrfs_leaf_free_space(leaf) < 0) {
btrfs_print_leaf(leaf);
BUG();
}
- return ret;
}
/*
@@ -3218,7 +3214,7 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
* ret == -EEXIST case, An item with that type already exists.
* Extend the item and store the new subvol_id at the end.
*/
- btrfs_extend_item(uuid_root, path, sizeof(subvol_id_le));
+ btrfs_extend_item(path, sizeof(subvol_id_le));
eb = path->nodes[0];
slot = path->slots[0];
offset = btrfs_item_ptr_offset(eb, slot);
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 18562f3b..b3e73e35 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -967,8 +967,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct extent_buffer **cow_ret, u64 new_root_objectid);
int btrfs_create_root(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 objectid);
-int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
- u32 data_size);
+void btrfs_extend_item(struct btrfs_path *path, u32 data_size);
void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
diff --git a/kernel-shared/dir-item.c b/kernel-shared/dir-item.c
index ef49441c..def7ea81 100644
--- a/kernel-shared/dir-item.c
+++ b/kernel-shared/dir-item.c
@@ -40,8 +40,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
di = btrfs_match_dir_item_name(root, path, name, name_len);
if (di)
return ERR_PTR(-EEXIST);
- ret = btrfs_extend_item(root, path, data_size);
- WARN_ON(ret > 0);
+ btrfs_extend_item(path, data_size);
+ ret = 0;
}
if (ret < 0)
return ERR_PTR(ret);
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 718a4fc9..ba853110 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1040,7 +1040,6 @@ static int setup_inline_extent_backref(struct btrfs_root *root,
u64 refs;
int size;
int type;
- int ret;
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
@@ -1049,8 +1048,7 @@ static int setup_inline_extent_backref(struct btrfs_root *root,
type = extent_ref_type(parent, owner);
size = btrfs_extent_inline_ref_size(type);
- ret = btrfs_extend_item(root, path, size);
- BUG_ON(ret);
+ btrfs_extend_item(path, size);
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
refs = btrfs_extent_refs(leaf, ei);
diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c
index 6e0f7381..fd6756e9 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -293,8 +293,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
diff = diff - btrfs_item_size(leaf, path->slots[0]);
if (diff != csum_size)
goto insert;
- ret = btrfs_extend_item(root, path, diff);
- BUG_ON(ret);
+ btrfs_extend_item(path, diff);
goto csum;
}
diff --git a/kernel-shared/inode-item.c b/kernel-shared/inode-item.c
index 891ae40a..d0705267 100644
--- a/kernel-shared/inode-item.c
+++ b/kernel-shared/inode-item.c
@@ -78,8 +78,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
goto out;
old_size = btrfs_item_size(path->nodes[0], path->slots[0]);
- ret = btrfs_extend_item(root, path, ins_len);
- BUG_ON(ret);
+ btrfs_extend_item(path, ins_len);
ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_ref);
ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
@@ -352,7 +351,7 @@ int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
name, name_len, NULL))
goto out;
- btrfs_extend_item(root, path, ins_len);
+ btrfs_extend_item(path, ins_len);
ret = 0;
}
diff --git a/tune/change-csum.c b/tune/change-csum.c
index a1131686..49624c6f 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -232,8 +232,7 @@ static int csum_file_block(struct btrfs_trans_handle *trans,
diff = diff - btrfs_item_size(leaf, path->slots[0]);
if (diff != csum_size)
goto insert;
- ret = btrfs_extend_item(csum_root, path, diff);
- BUG_ON(ret);
+ btrfs_extend_item(path, diff);
goto csum;
}
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 12/26] btrfs-progs: sync memcpy_extent_buffer from the kernel
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (10 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 11/26] btrfs-progs: update btrfs_extend_item " Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 13/26] btrfs-progs: change how we check supported csum type Josef Bacik
` (14 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
We use this in ctree.c in the kernel, so sync this helper into
btrfs-progs to make sync'ing ctree.c easier.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/extent_io.c | 6 ++++++
kernel-shared/extent_io.h | 3 +++
2 files changed, 9 insertions(+)
diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c
index e38bb1ed..fbf45e9d 100644
--- a/kernel-shared/extent_io.c
+++ b/kernel-shared/extent_io.c
@@ -630,6 +630,12 @@ void copy_extent_buffer_full(const struct extent_buffer *dst,
copy_extent_buffer(dst, src, 0, 0, src->len);
}
+void memcpy_extent_buffer(const struct extent_buffer *dst, unsigned long dst_offset,
+ unsigned long src_offset, unsigned long len)
+{
+ memcpy((void *)dst->data + dst_offset, dst->data + src_offset, len);
+}
+
void memmove_extent_buffer(const struct extent_buffer *dst, unsigned long dst_offset,
unsigned long src_offset, unsigned long len)
{
diff --git a/kernel-shared/extent_io.h b/kernel-shared/extent_io.h
index f573a4e2..544d5710 100644
--- a/kernel-shared/extent_io.h
+++ b/kernel-shared/extent_io.h
@@ -118,6 +118,9 @@ void copy_extent_buffer(const struct extent_buffer *dst,
unsigned long len);
void copy_extent_buffer_full(const struct extent_buffer *dst,
const struct extent_buffer *src);
+void memcpy_extent_buffer(const struct extent_buffer *dst,
+ unsigned long dst_offset, unsigned long src_offset,
+ unsigned long len);
void memmove_extent_buffer(const struct extent_buffer *dst,
const unsigned long dst_offset,
unsigned long src_offset, unsigned long len);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 13/26] btrfs-progs: change how we check supported csum type
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (11 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 12/26] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 14/26] btrfs-progs: drop btrfs_init_path Josef Bacik
` (13 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In the kernel we have a basic btrfs_supported_super_csum() helper in
disk-io.c to validate the csum type. Update progs to do the same thing
that the kernel does and then drop the btrfs_super_num_csums() helper as
it doesn't exist upstream and is no longer used.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 5 -----
kernel-shared/ctree.h | 1 -
kernel-shared/disk-io.c | 15 ++++++++++++++-
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 97164cb8..0bd24646 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -65,11 +65,6 @@ const char *btrfs_super_csum_name(u16 csum_type)
return btrfs_csums[csum_type].name;
}
-size_t btrfs_super_num_csums(void)
-{
- return ARRAY_SIZE(btrfs_csums);
-}
-
u16 btrfs_csum_type_size(u16 csum_type)
{
return btrfs_csums[csum_type].size;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index b3e73e35..cab8f71b 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1064,7 +1064,6 @@ void btrfs_set_item_key_unsafe(struct btrfs_root *root,
u16 btrfs_super_csum_size(const struct btrfs_super_block *s);
const char *btrfs_super_csum_name(u16 csum_type);
u16 btrfs_csum_type_size(u16 csum_type);
-size_t btrfs_super_num_csums(void);
/* root-item.c */
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index 3e0c3534..b7a98c4c 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -1713,6 +1713,19 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
return info->fs_root;
}
+static bool btrfs_supported_super_csum(u16 csum_type)
+{
+ switch (csum_type) {
+ case BTRFS_CSUM_TYPE_CRC32:
+ case BTRFS_CSUM_TYPE_XXHASH:
+ case BTRFS_CSUM_TYPE_SHA256:
+ case BTRFS_CSUM_TYPE_BLAKE2:
+ return true;
+ default:
+ return false;
+ }
+}
+
/*
* Check if the super is valid:
* - nodesize/sectorsize - minimum, maximum, alignment
@@ -1737,7 +1750,7 @@ int btrfs_check_super(struct btrfs_super_block *sb, unsigned sbflags)
}
csum_type = btrfs_super_csum_type(sb);
- if (csum_type >= btrfs_super_num_csums()) {
+ if (!btrfs_supported_super_csum(csum_type)) {
error("unsupported checksum algorithm %u", csum_type);
return -EIO;
}
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 14/26] btrfs-progs: drop btrfs_init_path
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (12 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 13/26] btrfs-progs: change how we check supported csum type Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 15/26] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
` (12 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This simply zero's out the path, and this is used everywhere we use a
stack path. Drop this usage and simply init the path's to empty instead
of using a function to do the memset.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/clear-cache.c | 10 +---
check/main.c | 94 ++++++++++----------------------
check/mode-common.c | 35 ++++--------
check/mode-lowmem.c | 84 +++++++++-------------------
check/qgroup-verify.c | 14 ++---
check/repair.c | 3 +-
cmds/inspect-dump-tree.c | 3 +-
cmds/inspect-tree-stats.c | 3 +-
cmds/rescue-chunk-recover.c | 13 ++---
cmds/restore.c | 21 +++----
convert/main.c | 9 +--
convert/source-fs.c | 4 +-
image/main.c | 13 ++---
kernel-shared/ctree.c | 5 --
kernel-shared/ctree.h | 1 -
kernel-shared/extent-tree.c | 3 +-
kernel-shared/file.c | 3 +-
kernel-shared/free-space-cache.c | 4 +-
kernel-shared/inode.c | 5 +-
kernel-shared/print-tree.c | 3 +-
kernel-shared/volumes.c | 6 +-
mkfs/main.c | 15 ++---
mkfs/rootdir.c | 10 +---
quick-test.c | 6 +-
tune/change-csum.c | 9 +--
tune/change-uuid.c | 6 +-
26 files changed, 116 insertions(+), 266 deletions(-)
diff --git a/check/clear-cache.c b/check/clear-cache.c
index 031379ce..17b9c93b 100644
--- a/check/clear-cache.c
+++ b/check/clear-cache.c
@@ -129,11 +129,9 @@ close_out:
static int check_free_space_tree(struct btrfs_root *root)
{
struct btrfs_key key = { 0 };
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
- btrfs_init_path(&path);
-
while (1) {
struct btrfs_block_group *bg;
u64 cur_start = key.objectid;
@@ -447,7 +445,6 @@ out:
int truncate_free_ino_items(struct btrfs_root *root)
{
- struct btrfs_path path;
struct btrfs_key key = { .objectid = BTRFS_FREE_INO_OBJECTID,
.type = (u8)-1,
.offset = (u64)-1 };
@@ -465,9 +462,9 @@ int truncate_free_ino_items(struct btrfs_root *root)
struct btrfs_file_extent_item *fi;
struct btrfs_root *csum_root;
struct btrfs_key found_key;
+ struct btrfs_path path = {};
u8 found_type;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
@@ -548,14 +545,13 @@ out:
int clear_ino_cache_items(void)
{
int ret;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, gfs_info->tree_root, &key, &path, 0, 0);
if (ret < 0)
return ret;
diff --git a/check/main.c b/check/main.c
index a6485db5..5e4f5827 100644
--- a/check/main.c
+++ b/check/main.c
@@ -889,7 +889,7 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache,
static int check_orphan_item(struct btrfs_root *root, u64 ino)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
@@ -897,7 +897,6 @@ static int check_orphan_item(struct btrfs_root *root, u64 ino)
key.type = BTRFS_ORPHAN_ITEM_KEY;
key.offset = ino;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
btrfs_release_path(&path);
if (ret > 0)
@@ -1325,14 +1324,12 @@ static int leave_shared_node(struct btrfs_root *root,
static int is_child_root(struct btrfs_root *root, u64 parent_root_id,
u64 child_root_id)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct extent_buffer *leaf;
int has_parent = 0;
int ret;
- btrfs_init_path(&path);
-
key.objectid = parent_root_id;
key.type = BTRFS_ROOT_REF_KEY;
key.offset = child_root_id;
@@ -2107,7 +2104,7 @@ static int add_missing_dir_index(struct btrfs_root *root,
struct inode_record *rec,
struct inode_backref *backref)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_trans_handle *trans;
struct btrfs_dir_item *dir_item;
struct extent_buffer *leaf;
@@ -2125,7 +2122,6 @@ static int add_missing_dir_index(struct btrfs_root *root,
fprintf(stderr, "repairing missing dir index item for inode %llu\n",
(unsigned long long)rec->ino);
- btrfs_init_path(&path);
key.objectid = backref->dir;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = backref->index;
@@ -2169,7 +2165,7 @@ static int delete_dir_index(struct btrfs_root *root,
{
struct btrfs_trans_handle *trans;
struct btrfs_dir_item *di;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
trans = btrfs_start_transaction(root, 1);
@@ -2181,7 +2177,6 @@ static int delete_dir_index(struct btrfs_root *root,
BTRFS_DIR_INDEX_KEY, (unsigned long long)backref->index,
(unsigned long long)root->objectid);
- btrfs_init_path(&path);
di = btrfs_lookup_dir_index_item(trans, root, &path, backref->dir,
backref->index, backref->name,
backref->namelen, -1);
@@ -2535,14 +2530,13 @@ out:
*/
static int find_normal_file_extent(struct btrfs_root *root, u64 ino)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_file_extent_item *fi;
u8 type;
int ret = 0;
- btrfs_init_path(&path);
key.objectid = ino;
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = 0;
@@ -2755,11 +2749,9 @@ static int repair_mismatch_dir_hash(struct btrfs_trans_handle *trans,
static int btrfs_delete_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_key *key)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
- btrfs_init_path(&path);
-
ret = btrfs_search_slot(trans, root, key, &path, -1, 1);
if (ret) {
if (ret > 0)
@@ -2779,7 +2771,7 @@ static int find_file_extent_offset_by_bytenr(struct btrfs_root *root,
u64 owner, u64 bytenr, u64 *offset_ret)
{
int ret = 0;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_file_extent_item *fi;
@@ -2787,8 +2779,6 @@ static int find_file_extent_offset_by_bytenr(struct btrfs_root *root,
u64 disk_bytenr;
int slot;
- btrfs_init_path(&path);
-
key.objectid = owner;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
@@ -2960,7 +2950,7 @@ static int repair_inode_gen_original(struct btrfs_trans_handle *trans,
static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
{
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
/* unaligned extent recs always lead to csum missing error, clean it */
@@ -2993,7 +2983,6 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
if (!ret && rec->errors & I_ERR_MISMATCH_DIR_HASH)
ret = repair_mismatch_dir_hash(trans, root, rec);
if (!ret && rec->errors & I_ERR_INVALID_IMODE)
@@ -3539,7 +3528,7 @@ static int repair_btree(struct btrfs_root *root,
struct cache_tree *corrupt_blocks)
{
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_corrupt_block *corrupt;
struct cache_extent *cache;
struct btrfs_key key;
@@ -3557,7 +3546,6 @@ static int repair_btree(struct btrfs_root *root,
fprintf(stderr, "Error starting transaction: %m\n");
return ret;
}
- btrfs_init_path(&path);
cache = first_cache_extent(corrupt_blocks);
while (cache) {
corrupt = container_of(cache, struct btrfs_corrupt_block,
@@ -3625,7 +3613,7 @@ static int check_fs_root(struct btrfs_root *root,
int wret;
int level;
u64 super_generation;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct shared_node root_node;
struct root_record *rec;
struct btrfs_root_item *root_item = &root->root_item;
@@ -3668,7 +3656,6 @@ static int check_fs_root(struct btrfs_root *root,
rec->found_root_item = 1;
}
- btrfs_init_path(&path);
memset(&root_node, 0, sizeof(root_node));
cache_tree_init(&root_node.root_cache);
cache_tree_init(&root_node.inode_cache);
@@ -3804,7 +3791,7 @@ skip_walking:
static int check_fs_roots(struct cache_tree *root_cache)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct walk_control wc;
struct extent_buffer *leaf, *tree_node;
@@ -3822,7 +3809,6 @@ static int check_fs_roots(struct cache_tree *root_cache)
reset_cached_block_groups();
memset(&wc, 0, sizeof(wc));
cache_tree_init(&wc.shared);
- btrfs_init_path(&path);
again:
key.offset = 0;
@@ -4212,7 +4198,7 @@ static int check_owner_ref(struct btrfs_root *root,
struct tree_backref *back;
struct btrfs_root *ref_root;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *parent;
int level;
int found = 0;
@@ -4252,7 +4238,6 @@ static int check_owner_ref(struct btrfs_root *root,
else
btrfs_node_key_to_cpu(buf, &key, 0);
- btrfs_init_path(&path);
path.lowest_level = level + 1;
ret = btrfs_search_slot(NULL, ref_root, &key, &path, 0, 0);
if (ret < 0)
@@ -4510,7 +4495,7 @@ static int try_to_fix_bad_block(struct btrfs_root *root,
struct ulist *roots;
struct ulist_node *node;
struct btrfs_root *search_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct ulist_iterator iter;
struct btrfs_key root_key, key;
int ret;
@@ -4523,7 +4508,6 @@ static int try_to_fix_bad_block(struct btrfs_root *root,
if (ret)
return -EIO;
- btrfs_init_path(&path);
ULIST_ITER_INIT(&iter);
/*
* If we found no roots referencing to this tree block, there is no
@@ -5768,12 +5752,11 @@ static int check_extent_exists(struct btrfs_root *root, u64 bytenr,
u64 num_bytes)
{
struct btrfs_root *extent_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_key key;
int ret;
- btrfs_init_path(&path);
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = (u64)-1;
@@ -5909,7 +5892,7 @@ out:
static int check_csum_root(struct btrfs_root *root)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_key key;
u64 last_data_end = 0;
@@ -5930,7 +5913,6 @@ static int check_csum_root(struct btrfs_root *root)
return -ENOENT;
}
- btrfs_init_path(&path);
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
key.type = BTRFS_EXTENT_CSUM_KEY;
key.offset = 0;
@@ -7376,14 +7358,12 @@ static int delete_duplicate_records(struct btrfs_root *root,
{
struct btrfs_trans_handle *trans;
LIST_HEAD(delete_list);
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_record *tmp, *good, *n;
int nr_del = 0;
int ret = 0, err;
struct btrfs_key key;
- btrfs_init_path(&path);
-
good = rec;
/* Find the record that covers all of the duplicates. */
list_for_each_entry(tmp, &rec->dups, list) {
@@ -7479,7 +7459,7 @@ static int __find_possible_backrefs(struct btrfs_root *root,
u64 *bytes_ret)
{
int ret = 0;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_file_extent_item *fi;
@@ -7487,8 +7467,6 @@ static int __find_possible_backrefs(struct btrfs_root *root,
u64 backref_offset, disk_bytenr;
int slot;
- btrfs_init_path(&path);
-
key.objectid = owner;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
@@ -7642,7 +7620,7 @@ static int fixup_extent_refs(struct cache_tree *extent_cache,
{
struct btrfs_trans_handle *trans = NULL;
int ret;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct cache_extent *cache;
struct extent_backref *back, *tmp;
int allocated = 0;
@@ -7651,7 +7629,6 @@ static int fixup_extent_refs(struct cache_tree *extent_cache,
if (rec->flag_block_full_backref)
flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
- btrfs_init_path(&path);
if (rec->refs != rec->extent_item_refs && !rec->metadata) {
/*
* Sometimes the backrefs themselves are so broken they don't
@@ -7727,7 +7704,7 @@ static int fixup_extent_flags(struct extent_record *rec)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root = btrfs_extent_root(gfs_info, rec->start);
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_extent_item *ei;
struct btrfs_key key;
u64 flags;
@@ -7750,7 +7727,6 @@ retry:
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
if (ret < 0) {
btrfs_release_path(&path);
@@ -7797,14 +7773,13 @@ static int prune_one_block(struct btrfs_trans_handle *trans,
{
struct btrfs_root *extent_root;
int ret;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *eb;
u64 found;
int slot;
int nritems;
int level = corrupt->level + 1;
- btrfs_init_path(&path);
again:
extent_root = btrfs_extent_root(gfs_info, corrupt->key.objectid);
/* we want to stop at the parent to our busted block */
@@ -7983,7 +7958,7 @@ static int record_unaligned_extent_rec(struct extent_record *rec)
static int repair_extent_item_generation(struct extent_record *rec)
{
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_extent_item *ei;
struct btrfs_root *extent_root = btrfs_extent_root(gfs_info,
@@ -8003,7 +7978,6 @@ static int repair_extent_item_generation(struct extent_record *rec)
error_msg(ERROR_MSG_START_TRANS, "%m");
return ret;
}
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, extent_root, &key, &path, 0, 1);
/* Not possible */
if (ret == 0)
@@ -8728,7 +8702,7 @@ static int check_block_groups(struct block_group_tree *bg_cache)
static int parse_tree_roots(struct list_head *normal_trees,
struct list_head *dropping_trees)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_root_item ri;
@@ -8736,7 +8710,6 @@ static int parse_tree_roots(struct list_head *normal_trees,
int slot;
int ret = 0;
- btrfs_init_path(&path);
key.offset = 0;
key.objectid = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
@@ -8801,15 +8774,13 @@ out:
*/
static int check_dev_extents(void)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_root *dev_root = gfs_info->dev_root;
int ret;
u64 prev_devid = 0;
u64 prev_dev_ext_end = 0;
- btrfs_init_path(&path);
-
key.objectid = 1;
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = 0;
@@ -9174,14 +9145,13 @@ static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
static int reset_block_groups(void)
{
struct btrfs_block_group *cache;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_chunk *chunk;
struct btrfs_key key;
int ret;
u64 start;
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_CHUNK_ITEM_KEY;
key.offset = 0;
@@ -9245,14 +9215,13 @@ static int reset_block_groups(void)
static int reset_balance(struct btrfs_trans_handle *trans)
{
struct btrfs_root *root = gfs_info->tree_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_key key;
int del_slot, del_nr = 0;
int ret;
int found = 0;
- btrfs_init_path(&path);
key.objectid = BTRFS_BALANCE_OBJECTID;
key.type = BTRFS_BALANCE_ITEM_KEY;
key.offset = 0;
@@ -9351,12 +9320,11 @@ static int reinit_global_roots(struct btrfs_trans_handle *trans, u64 objectid)
.type = BTRFS_ROOT_ITEM_KEY,
.offset = 0,
};
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *tree_root = gfs_info->tree_root;
struct btrfs_root *root;
int ret;
- btrfs_init_path(&path);
while (1) {
ret = btrfs_search_slot(NULL, tree_root, &key, &path, 0, 0);
if (ret) {
@@ -9509,7 +9477,7 @@ again:
static int delete_bad_item(struct btrfs_root *root, struct bad_item *bad)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_trans_handle *trans;
struct btrfs_key key;
int ret;
@@ -9531,7 +9499,6 @@ static int delete_bad_item(struct btrfs_root *root, struct bad_item *bad)
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &bad->key, &path, -1, 1);
if (ret) {
if (ret > 0)
@@ -9583,7 +9550,7 @@ static int build_roots_info_cache(void)
int ret = 0;
struct btrfs_key key;
struct extent_buffer *leaf;
- struct btrfs_path path;
+ struct btrfs_path path = {};
if (!roots_info_cache) {
roots_info_cache = malloc(sizeof(*roots_info_cache));
@@ -9592,7 +9559,6 @@ static int build_roots_info_cache(void)
cache_tree_init(roots_info_cache);
}
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
@@ -9799,7 +9765,7 @@ static int maybe_repair_root_item(struct btrfs_path *path,
*/
static int repair_root_items(void)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct extent_buffer *leaf;
struct btrfs_trans_handle *trans = NULL;
@@ -9810,8 +9776,6 @@ static int repair_root_items(void)
if (btrfs_fs_incompat(gfs_info, EXTENT_TREE_V2))
return 0;
- btrfs_init_path(&path);
-
ret = build_roots_info_cache();
if (ret)
goto out;
diff --git a/check/mode-common.c b/check/mode-common.c
index a38d2afc..a4644d63 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -52,10 +52,9 @@ static int check_prealloc_data_ref(u64 disk_bytenr,
u64 offset = btrfs_extent_data_ref_offset(eb, dref);
struct btrfs_root *root;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret;
- btrfs_init_path(&path);
key.objectid = rootid;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
@@ -190,7 +189,7 @@ int check_prealloc_extent_written(u64 disk_bytenr, u64 num_bytes)
{
struct btrfs_root *extent_root = btrfs_extent_root(gfs_info,
disk_bytenr);
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
struct btrfs_extent_item *ei;
@@ -202,7 +201,6 @@ int check_prealloc_extent_written(u64 disk_bytenr, u64 num_bytes)
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
if (ret > 0) {
fprintf(stderr,
@@ -303,7 +301,7 @@ int count_csum_range(u64 start, u64 len, u64 *found)
{
struct btrfs_root *csum_root = btrfs_csum_root(gfs_info, start);
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
int ret;
size_t size;
@@ -311,8 +309,6 @@ int count_csum_range(u64 start, u64 len, u64 *found)
u64 csum_end;
u16 csum_size = gfs_info->csum_size;
- btrfs_init_path(&path);
-
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
key.offset = start;
key.type = BTRFS_EXTENT_CSUM_KEY;
@@ -416,7 +412,6 @@ static int get_highest_inode(struct btrfs_trans_handle *trans,
struct btrfs_key key, found_key;
int ret;
- btrfs_init_path(path);
key.objectid = BTRFS_LAST_FREE_OBJECTID;
key.offset = -1;
key.type = BTRFS_INODE_ITEM_KEY;
@@ -654,10 +649,9 @@ int delete_corrupted_dir_item(struct btrfs_trans_handle *trans,
u32 namelen)
{
struct btrfs_dir_item *di_item;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, di_key, &path, 0, 1);
if (ret > 0) {
error("key (%llu %u %llu) doesn't exist in root %llu",
@@ -736,7 +730,7 @@ static int find_file_type_dir_index(struct btrfs_root *root, u64 ino, u64 dirid,
u64 index, const char *name, u32 name_len,
u32 *imode_ret)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key location;
struct btrfs_dir_item *di;
@@ -746,7 +740,6 @@ static int find_file_type_dir_index(struct btrfs_root *root, u64 ino, u64 dirid,
u32 len;
int ret;
- btrfs_init_path(&path);
key.objectid = dirid;
key.offset = index;
key.type = BTRFS_DIR_INDEX_KEY;
@@ -788,7 +781,7 @@ static int find_file_type_dir_item(struct btrfs_root *root, u64 ino, u64 dirid,
const char *name, u32 name_len,
u32 *imode_ret)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key location;
struct btrfs_dir_item *di;
@@ -800,7 +793,6 @@ static int find_file_type_dir_item(struct btrfs_root *root, u64 ino, u64 dirid,
u32 len;
int ret;
- btrfs_init_path(&path);
key.objectid = dirid;
key.offset = btrfs_name_hash(name, name_len);
key.type = BTRFS_DIR_INDEX_KEY;
@@ -1056,7 +1048,7 @@ int check_repair_free_space_inode(struct btrfs_path *path)
int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_trans_handle *trans;
struct btrfs_key key;
int ret;
@@ -1077,7 +1069,6 @@ int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
path.lowest_level = btrfs_header_level(eb);
if (path.lowest_level)
btrfs_node_key_to_cpu(eb, &key, 0);
@@ -1100,7 +1091,7 @@ int get_extent_item_generation(u64 bytenr, u64 *gen_ret)
{
struct btrfs_root *root = btrfs_extent_root(gfs_info, bytenr);
struct btrfs_extent_item *ei;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
@@ -1108,7 +1099,6 @@ int get_extent_item_generation(u64 bytenr, u64 *gen_ret)
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
/* Not possible */
if (ret == 0)
@@ -1232,7 +1222,7 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
struct btrfs_root *cur_root)
{
struct btrfs_root *csum_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct extent_buffer *node;
struct btrfs_file_extent_item *fi;
@@ -1247,7 +1237,6 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
if (!buf)
return -ENOMEM;
- btrfs_init_path(&path);
key.objectid = 0;
key.offset = 0;
key.type = 0;
@@ -1339,7 +1328,7 @@ out:
static int fill_csum_tree_from_fs(struct btrfs_trans_handle *trans)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *tree_root = gfs_info->tree_root;
struct btrfs_root *cur_root;
struct extent_buffer *node;
@@ -1347,7 +1336,6 @@ static int fill_csum_tree_from_fs(struct btrfs_trans_handle *trans)
int slot = 0;
int ret = 0;
- btrfs_init_path(&path);
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.offset = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
@@ -1486,14 +1474,13 @@ static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root)
{
struct btrfs_root *csum_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_extent_item *ei;
struct extent_buffer *leaf;
char *buf;
struct btrfs_key key;
int ret;
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
index 1614c065..a5116631 100644
--- a/check/mode-lowmem.c
+++ b/check/mode-lowmem.c
@@ -281,7 +281,7 @@ static int modify_block_groups_cache(u64 flags, int cache)
{
struct btrfs_root *root = btrfs_block_group_root(gfs_info);
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_block_group *bg_cache;
struct btrfs_block_group_item *bi;
struct btrfs_block_group_item bg_item;
@@ -293,7 +293,6 @@ static int modify_block_groups_cache(u64 flags, int cache)
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
errno = -ret;
@@ -430,7 +429,7 @@ err:
*/
static int is_chunk_almost_full(u64 start)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_root *root = btrfs_block_group_root(gfs_info);
struct btrfs_block_group_item *bi;
@@ -446,7 +445,6 @@ static int is_chunk_almost_full(u64 start)
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (!ret)
ret = -EIO;
@@ -637,7 +635,7 @@ static int repair_tree_block_ref(struct btrfs_root *root,
{
struct btrfs_trans_handle *trans = NULL;
struct btrfs_root *extent_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_extent_item *ei;
struct btrfs_tree_block_info *bi;
struct btrfs_key key;
@@ -660,7 +658,6 @@ static int repair_tree_block_ref(struct btrfs_root *root,
WARN_ON(level > BTRFS_MAX_LEVEL);
WARN_ON(level < 0);
- btrfs_init_path(&path);
bytenr = btrfs_header_bytenr(node);
owner = btrfs_header_owner(node);
generation = btrfs_header_generation(node);
@@ -820,7 +817,7 @@ static int find_dir_index(struct btrfs_root *root, u64 dirid, u64 location_id,
u64 *index_ret, char *namebuf, u32 name_len,
u8 file_type)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *node;
struct btrfs_dir_item *di;
struct btrfs_key key;
@@ -842,7 +839,6 @@ static int find_dir_index(struct btrfs_root *root, u64 dirid, u64 location_id,
key.offset = (u64)-1;
key.type = BTRFS_DIR_INDEX_KEY;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0)
return ret;
@@ -919,7 +915,7 @@ static int find_dir_item(struct btrfs_root *root, struct btrfs_key *key,
struct btrfs_key *location_key, char *name,
u32 namelen, u8 file_type)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *node;
struct btrfs_dir_item *di;
struct btrfs_key location;
@@ -942,7 +938,6 @@ static int find_dir_item(struct btrfs_root *root, struct btrfs_key *key,
return ret;
}
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
if (ret) {
ret = key->type == BTRFS_DIR_ITEM_KEY ? DIR_ITEM_MISSING :
@@ -1338,7 +1333,7 @@ static int find_inode_ref(struct btrfs_root *root, struct btrfs_key *key,
char *name, int namelen, u64 *index_ret)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_inode_ref *ref;
struct btrfs_inode_extref *extref;
struct extent_buffer *node;
@@ -1355,7 +1350,6 @@ static int find_inode_ref(struct btrfs_root *root, struct btrfs_key *key,
UASSERT(index_ret);
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
if (ret) {
ret = INODE_REF_MISSING;
@@ -1415,7 +1409,6 @@ extref:
goto out;
btrfs_release_path(&path);
- btrfs_init_path(&path);
dir_id = key->offset;
key->type = BTRFS_INODE_EXTREF_KEY;
@@ -1498,14 +1491,13 @@ static int repair_inode_item_missing(struct btrfs_root *root, u64 ino,
{
struct btrfs_key key;
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret;
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
ret = -EIO;
@@ -1564,14 +1556,13 @@ static int lowmem_delete_corrupted_dir_item(struct btrfs_root *root,
static int try_repair_imode(struct btrfs_root *root, u64 ino)
{
struct btrfs_inode_item *iitem;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret > 0)
@@ -2188,7 +2179,7 @@ static int __count_dir_isize(struct btrfs_root *root, u64 ino, int type,
u64 *size_ret)
{
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
u32 len;
struct btrfs_dir_item *di;
int ret;
@@ -2202,7 +2193,6 @@ static int __count_dir_isize(struct btrfs_root *root, u64 ino, int type,
key.type = type;
key.offset = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
ret = -EIO;
@@ -2518,11 +2508,10 @@ out:
static bool has_orphan_item(struct btrfs_root *root, u64 ino)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
- btrfs_init_path(&path);
key.objectid = BTRFS_ORPHAN_OBJECTID;
key.type = BTRFS_ORPHAN_ITEM_KEY;
key.offset = ino;
@@ -3019,7 +3008,7 @@ static int check_tree_block_ref(struct btrfs_root *root,
{
struct btrfs_key key;
struct btrfs_root *extent_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_extent_item *ei;
struct btrfs_extent_inline_ref *iref;
struct extent_buffer *leaf;
@@ -3038,7 +3027,6 @@ static int check_tree_block_ref(struct btrfs_root *root,
int strict = 1;
int parent = 0;
- btrfs_init_path(&path);
key.objectid = bytenr;
if (btrfs_fs_incompat(gfs_info, SKINNY_METADATA))
key.type = BTRFS_METADATA_ITEM_KEY;
@@ -3239,7 +3227,7 @@ static int repair_extent_data_item(struct btrfs_root *root,
struct btrfs_key fi_key;
struct btrfs_key key;
struct btrfs_extent_item *ei;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *extent_root;
struct extent_buffer *eb;
u64 size;
@@ -3291,7 +3279,6 @@ static int repair_extent_data_item(struct btrfs_root *root,
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
- btrfs_init_path(&path);
extent_root = btrfs_extent_root(gfs_info, key.objectid);
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
if (ret < 0) {
@@ -3374,7 +3361,7 @@ static int check_extent_data_item(struct btrfs_root *root,
{
struct btrfs_file_extent_item *fi;
struct extent_buffer *eb = pathp->nodes[0];
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *extent_root;
struct btrfs_key fi_key;
struct btrfs_key dbref_key;
@@ -3440,7 +3427,6 @@ static int check_extent_data_item(struct btrfs_root *root,
owner = btrfs_header_owner(eb);
/* Check the extent item of the file extent in extent tree */
- btrfs_init_path(&path);
dbref_key.objectid = btrfs_file_extent_disk_bytenr(eb, fi);
dbref_key.type = BTRFS_EXTENT_ITEM_KEY;
dbref_key.offset = btrfs_file_extent_disk_num_bytes(eb, fi);
@@ -3567,7 +3553,7 @@ static int check_block_group_item(struct extent_buffer *eb, int slot)
struct btrfs_root *chunk_root = gfs_info->chunk_root;
struct btrfs_block_group_item *bi;
struct btrfs_block_group_item bg_item;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key bg_key;
struct btrfs_key chunk_key;
struct btrfs_key extent_key;
@@ -3592,7 +3578,6 @@ static int check_block_group_item(struct extent_buffer *eb, int slot)
chunk_key.type = BTRFS_CHUNK_ITEM_KEY;
chunk_key.offset = bg_key.objectid;
- btrfs_init_path(&path);
/* Search for the referencer chunk */
ret = btrfs_search_slot(NULL, chunk_root, &chunk_key, &path, 0, 0);
if (ret) {
@@ -3618,7 +3603,6 @@ static int check_block_group_item(struct extent_buffer *eb, int slot)
extent_key.type = 0;
extent_key.offset = 0;
- btrfs_init_path(&path);
extent_root = btrfs_extent_root(gfs_info, extent_key.objectid);
ret = btrfs_search_slot(NULL, extent_root, &extent_key, &path, 0, 0);
if (ret < 0)
@@ -3697,7 +3681,7 @@ static int query_tree_block_level(u64 bytenr)
{
struct btrfs_root *extent_root;
struct extent_buffer *eb;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_extent_item *ei;
u64 flags;
@@ -3711,8 +3695,6 @@ static int query_tree_block_level(u64 bytenr)
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
-
extent_root = btrfs_extent_root(gfs_info, bytenr);
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
if (ret < 0)
@@ -3775,7 +3757,7 @@ static int check_tree_block_backref(u64 root_id, u64 bytenr, int level)
{
struct btrfs_root *root;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *eb;
struct extent_buffer *node;
u32 nodesize = btrfs_super_nodesize(gfs_info->super_copy);
@@ -3821,7 +3803,6 @@ static int check_tree_block_backref(u64 root_id, u64 bytenr, int level)
free_extent_buffer(eb);
- btrfs_init_path(&path);
path.lowest_level = level;
/* Search with the first key, to ensure we can reach it */
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
@@ -3947,7 +3928,7 @@ static int check_extent_data_backref(u64 root_id, u64 objectid, u64 offset,
struct btrfs_root *root;
struct btrfs_root *extent_root;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi;
u32 found_count = 0;
@@ -3959,7 +3940,6 @@ static int check_extent_data_backref(u64 root_id, u64 objectid, u64 offset,
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
extent_root = btrfs_extent_root(gfs_info, bytenr);
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
if (ret < 0)
@@ -3977,7 +3957,6 @@ static int check_extent_data_backref(u64 root_id, u64 objectid, u64 offset,
key.objectid = root_id;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
root = btrfs_read_fs_root(gfs_info, &key);
if (IS_ERR(root))
@@ -4445,7 +4424,7 @@ static int check_dev_extent_item(struct extent_buffer *eb, int slot)
{
struct btrfs_root *chunk_root = gfs_info->chunk_root;
struct btrfs_dev_extent *ptr;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key chunk_key;
struct btrfs_key devext_key;
struct btrfs_chunk *chunk;
@@ -4464,7 +4443,6 @@ static int check_dev_extent_item(struct extent_buffer *eb, int slot)
chunk_key.type = BTRFS_CHUNK_ITEM_KEY;
chunk_key.offset = btrfs_dev_extent_chunk_offset(eb, ptr);
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, chunk_root, &chunk_key, &path, 0, 0);
if (ret)
goto out;
@@ -4508,7 +4486,7 @@ static int check_dev_item(struct extent_buffer *eb, int slot,
{
struct btrfs_root *dev_root = gfs_info->dev_root;
struct btrfs_dev_item *dev_item;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_dev_extent *ptr;
struct btrfs_device *dev;
@@ -4537,7 +4515,6 @@ static int check_dev_item(struct extent_buffer *eb, int slot,
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, dev_root, &key, &path, 0, 0);
if (ret < 0) {
btrfs_item_key_to_cpu(eb, &key, slot);
@@ -4681,7 +4658,7 @@ out:
static int check_chunk_item(struct extent_buffer *eb, int slot)
{
struct btrfs_root *dev_root = gfs_info->dev_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key chunk_key;
struct btrfs_key devext_key;
struct btrfs_chunk *chunk;
@@ -4711,7 +4688,6 @@ static int check_chunk_item(struct extent_buffer *eb, int slot)
}
type = btrfs_chunk_type(eb, chunk);
- btrfs_init_path(&path);
ret = find_block_group_item(&path, chunk_key.offset, length, type);
if (ret < 0)
err |= REFERENCER_MISSING;
@@ -4720,7 +4696,6 @@ static int check_chunk_item(struct extent_buffer *eb, int slot)
stripe_len = btrfs_stripe_length(gfs_info, eb, chunk);
for (i = 0; i < num_stripes; i++) {
btrfs_release_path(&path);
- btrfs_init_path(&path);
devext_key.objectid = btrfs_stripe_devid_nr(eb, chunk, i);
devext_key.type = BTRFS_DEV_EXTENT_KEY;
devext_key.offset = btrfs_stripe_offset_nr(eb, chunk, i);
@@ -5117,12 +5092,10 @@ static int repair_fs_first_inode(struct btrfs_root *root, int err)
{
struct btrfs_trans_handle *trans;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int filetype = BTRFS_FT_DIR;
int ret = 0;
- btrfs_init_path(&path);
-
if (err & INODE_REF_MISSING) {
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
key.type = BTRFS_INODE_REF_KEY;
@@ -5178,7 +5151,7 @@ out:
*/
static int check_fs_first_inode(struct btrfs_root *root)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_inode_item *ii;
u64 index;
@@ -5196,7 +5169,6 @@ static int check_fs_first_inode(struct btrfs_root *root)
BTRFS_FIRST_FREE_OBJECTID)
return 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0)
goto out;
@@ -5250,7 +5222,7 @@ out:
*/
static int check_btrfs_root(struct btrfs_root *root, int check_all)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct node_refs nrefs;
struct btrfs_root_item *root_item = &root->root_item;
u64 super_generation = btrfs_super_generation(gfs_info->super_copy);
@@ -5273,7 +5245,6 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
level = btrfs_header_level(root->node);
- btrfs_init_path(&path);
if (btrfs_root_generation(root_item) > super_generation + 1) {
error(
@@ -5358,7 +5329,7 @@ static int check_fs_root(struct btrfs_root *root)
static int check_root_ref(struct btrfs_root *root, struct btrfs_key *ref_key,
struct extent_buffer *node, int slot)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_root_ref *ref;
struct btrfs_root_ref *backref;
@@ -5395,7 +5366,6 @@ static int check_root_ref(struct btrfs_root *root, struct btrfs_key *ref_key,
key.type = BTRFS_ROOT_BACKREF_KEY + BTRFS_ROOT_REF_KEY - ref_key->type;
key.offset = ref_key->objectid;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret) {
err |= ROOT_REF_MISSING;
@@ -5450,14 +5420,13 @@ int check_fs_roots_lowmem(void)
{
struct btrfs_root *tree_root = gfs_info->tree_root;
struct btrfs_root *cur_root = NULL;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct extent_buffer *node;
int slot;
int ret;
int err = 0;
- btrfs_init_path(&path);
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.offset = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
@@ -5556,7 +5525,7 @@ out:
*/
int check_chunks_and_extents_lowmem(void)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key old_key;
struct btrfs_key key;
struct btrfs_root *root;
@@ -5572,7 +5541,6 @@ int check_chunks_and_extents_lowmem(void)
ret = check_btrfs_root(root, 1);
err |= ret;
- btrfs_init_path(&path);
key.objectid = BTRFS_EXTENT_TREE_OBJECTID;
key.offset = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
diff --git a/check/qgroup-verify.c b/check/qgroup-verify.c
index 1a62009b..0c08eae8 100644
--- a/check/qgroup-verify.c
+++ b/check/qgroup-verify.c
@@ -938,7 +938,7 @@ static int load_quota_info(struct btrfs_fs_info *info)
int ret;
struct btrfs_root *root = info->quota_root;
struct btrfs_root *tmproot;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_key root_key;
struct btrfs_disk_key disk_key;
@@ -954,8 +954,6 @@ loop:
* items. The 2nd pass picks up relation items and glues them to their
* respective count structures.
*/
- btrfs_init_path(&path);
-
key.offset = 0;
key.objectid = search_relations ? 0 : BTRFS_QGROUP_RELATION_KEY;
key.type = 0;
@@ -1164,13 +1162,11 @@ static int scan_extents(struct btrfs_fs_info *info,
int ret, i, nr, level;
struct btrfs_root *root = btrfs_extent_root(info, start);
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_disk_key disk_key;
struct extent_buffer *leaf;
u64 bytenr = 0, num_bytes = 0;
- btrfs_init_path(&path);
-
key.objectid = start;
key.type = 0;
key.offset = 0;
@@ -1562,7 +1558,7 @@ static int repair_qgroup_info(struct btrfs_fs_info *info,
int ret;
struct btrfs_root *root = info->quota_root;
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_qgroup_info_item *info_item;
struct btrfs_key key;
@@ -1575,7 +1571,6 @@ static int repair_qgroup_info(struct btrfs_fs_info *info,
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_QGROUP_INFO_KEY;
key.offset = count->qgroupid;
@@ -1619,7 +1614,7 @@ static int repair_qgroup_status(struct btrfs_fs_info *info, bool silent)
int ret;
struct btrfs_root *root = info->quota_root;
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_qgroup_status_item *status_item;
@@ -1630,7 +1625,6 @@ static int repair_qgroup_status(struct btrfs_fs_info *info, bool silent)
if (IS_ERR(trans))
return PTR_ERR(trans);
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_QGROUP_STATUS_KEY;
key.offset = 0;
diff --git a/check/repair.c b/check/repair.c
index b73f9518..c5afbaa1 100644
--- a/check/repair.c
+++ b/check/repair.c
@@ -172,12 +172,11 @@ static int populate_used_from_extent_root(struct btrfs_root *root,
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *leaf;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int slot;
int ret;
- btrfs_init_path(&path);
key.offset = 0;
key.objectid = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
diff --git a/cmds/inspect-dump-tree.c b/cmds/inspect-dump-tree.c
index 5385208d..f5f344c3 100644
--- a/cmds/inspect-dump-tree.c
+++ b/cmds/inspect-dump-tree.c
@@ -310,7 +310,7 @@ static int cmd_inspect_dump_tree(const struct cmd_struct *cmd,
{
struct btrfs_root *root;
struct btrfs_fs_info *info;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_root_item ri;
struct extent_buffer *leaf;
@@ -545,7 +545,6 @@ static int cmd_inspect_dump_tree(const struct cmd_struct *cmd,
}
tree_root_scan = info->tree_root;
- btrfs_init_path(&path);
again:
if (!extent_buffer_uptodate(tree_root_scan->node))
goto no_node;
diff --git a/cmds/inspect-tree-stats.c b/cmds/inspect-tree-stats.c
index 716aa008..080547c1 100644
--- a/cmds/inspect-tree-stats.c
+++ b/cmds/inspect-tree-stats.c
@@ -314,7 +314,7 @@ static int calc_root_size(struct btrfs_root *tree_root, struct btrfs_key *key,
int find_inline)
{
struct btrfs_root *root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct rb_node *n;
struct timeval start, end, diff = {0};
struct root_stats stat;
@@ -329,7 +329,6 @@ static int calc_root_size(struct btrfs_root *tree_root, struct btrfs_key *key,
return 1;
}
- btrfs_init_path(&path);
memset(&stat, 0, sizeof(stat));
level = btrfs_header_level(root->node);
stat.lowest_bytenr = btrfs_header_bytenr(root->node);
diff --git a/cmds/rescue-chunk-recover.c b/cmds/rescue-chunk-recover.c
index 52119d98..f30612d1 100644
--- a/cmds/rescue-chunk-recover.c
+++ b/cmds/rescue-chunk-recover.c
@@ -556,7 +556,7 @@ static int check_chunk_by_metadata(struct recover_control *rc,
int ret;
int i;
int slot;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_root *dev_root;
struct stripe *stripe;
@@ -564,8 +564,6 @@ static int check_chunk_by_metadata(struct recover_control *rc,
struct btrfs_block_group_item *bg_ptr;
struct extent_buffer *l;
- btrfs_init_path(&path);
-
if (bg_only)
goto bg_check;
@@ -985,7 +983,7 @@ static int block_group_remove_all_extent_items(struct btrfs_trans_handle *trans,
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
u64 start = bg->objectid;
u64 end = bg->objectid + bg->offset;
@@ -995,7 +993,6 @@ static int block_group_remove_all_extent_items(struct btrfs_trans_handle *trans,
int i;
int del_s, del_nr;
- btrfs_init_path(&path);
root = btrfs_extent_root(fs_info, start);
key.objectid = start;
@@ -1384,14 +1381,13 @@ static int rebuild_block_group(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info = root->fs_info;
struct chunk_record *chunk_rec;
struct btrfs_key search_key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
u64 used = 0;
int ret = 0;
if (list_empty(&rc->rebuild_chunks))
return 0;
- btrfs_init_path(&path);
list_for_each_entry(chunk_rec, &rc->rebuild_chunks, list) {
search_key.objectid = chunk_rec->offset;
search_key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -1968,7 +1964,7 @@ static int rebuild_raid_data_chunk_stripes(struct recover_control *rc,
int i;
int ret = 0;
int slot;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key prev_key;
struct btrfs_key key;
struct btrfs_root *csum_root;
@@ -1988,7 +1984,6 @@ static int rebuild_raid_data_chunk_stripes(struct recover_control *rc,
LIST_HEAD(unordered);
LIST_HEAD(candidates);
- btrfs_init_path(&path);
list_splice_init(&chunk->dextents, &candidates);
again:
if (list_is_last(candidates.next, &candidates))
diff --git a/cmds/restore.c b/cmds/restore.c
index 31cad31f..6490eb9c 100644
--- a/cmds/restore.c
+++ b/cmds/restore.c
@@ -474,7 +474,7 @@ static int set_file_xattrs(struct btrfs_root *root, u64 inode,
int fd, const char *file_name)
{
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_dir_item *di;
u32 name_len = 0;
@@ -485,7 +485,6 @@ static int set_file_xattrs(struct btrfs_root *root, u64 inode,
char *data = NULL;
int ret = 0;
- btrfs_init_path(&path);
key.objectid = inode;
key.type = BTRFS_XATTR_ITEM_KEY;
key.offset = 0;
@@ -571,11 +570,10 @@ out:
static int copy_metadata(struct btrfs_root *root, int fd,
struct btrfs_key *key)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_inode_item *inode_item;
int ret;
- btrfs_init_path(&path);
ret = btrfs_lookup_inode(NULL, root, &path, key, 0);
if (ret == 0) {
struct btrfs_timespec *bts;
@@ -620,7 +618,7 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
const char *file)
{
struct extent_buffer *leaf;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_file_extent_item *fi;
struct btrfs_inode_item *inode_item;
struct btrfs_timespec *bts;
@@ -632,7 +630,6 @@ static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
struct timespec times[2];
bool times_ok = false;
- btrfs_init_path(&path);
ret = btrfs_lookup_inode(NULL, root, &path, key, 0);
if (ret == 0) {
inode_item = btrfs_item_ptr(path.nodes[0], path.slots[0],
@@ -798,7 +795,7 @@ static int overwrite_ok(const char * path)
static int copy_symlink(struct btrfs_root *root, struct btrfs_key *key,
const char *file)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_file_extent_item *extent_item;
struct btrfs_inode_item *inode_item;
@@ -821,7 +818,6 @@ static int copy_symlink(struct btrfs_root *root, struct btrfs_key *key,
}
}
- btrfs_init_path(&path);
key->type = BTRFS_EXTENT_DATA_KEY;
key->offset = 0;
ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
@@ -913,7 +909,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
const char *output_rootdir, const char *in_dir,
const regex_t *mreg)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_dir_item *dir_item;
struct btrfs_key found_key, location;
@@ -924,7 +920,6 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key,
int fd;
u8 type;
- btrfs_init_path(&path);
key->offset = 0;
key->type = BTRFS_DIR_INDEX_KEY;
ret = btrfs_search_slot(NULL, root, key, &path, 0, 0);
@@ -1159,7 +1154,7 @@ static int do_list_roots(struct btrfs_root *root)
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_disk_key disk_key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_root_item ri;
unsigned long offset;
@@ -1168,7 +1163,6 @@ static int do_list_roots(struct btrfs_root *root)
root = root->fs_info->tree_root;
- btrfs_init_path(&path);
key.offset = 0;
key.objectid = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
@@ -1287,13 +1281,12 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
static int find_first_dir(struct btrfs_root *root, u64 *objectid)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key found_key;
struct btrfs_key key;
int ret = -1;
int i;
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = 0;
diff --git a/convert/main.c b/convert/main.c
index 941b5ce3..78c8d76e 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -790,7 +790,7 @@ static int create_image(struct btrfs_root *root,
{
struct btrfs_inode_item buf;
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct cache_extent *cache;
struct cache_tree used_tmp;
@@ -807,7 +807,6 @@ static int create_image(struct btrfs_root *root,
return PTR_ERR(trans);
cache_tree_init(&used_tmp);
- btrfs_init_path(&path);
ret = btrfs_find_free_objectid(trans, root, BTRFS_FIRST_FREE_OBJECTID,
&ino);
@@ -1448,7 +1447,7 @@ static int check_convert_image(struct btrfs_root *image_root, u64 ino,
u64 total_size, char *reserved_ranges[])
{
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_fs_info *fs_info = image_root->fs_info;
u64 checked_bytes = 0;
int ret;
@@ -1457,7 +1456,6 @@ static int check_convert_image(struct btrfs_root *image_root, u64 ino,
key.offset = 0;
key.type = BTRFS_EXTENT_DATA_KEY;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, image_root, &key, &path, 0, 0);
/*
* It's possible that some fs doesn't store any (including sb)
@@ -1613,7 +1611,7 @@ static int do_rollback(const char *devname)
struct btrfs_root *image_root;
struct btrfs_fs_info *fs_info;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_dir_item *dir;
struct btrfs_inode_item *inode_item;
struct btrfs_root_ref *root_ref_item;
@@ -1673,7 +1671,6 @@ static int do_rollback(const char *devname)
key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
key.type = BTRFS_ROOT_BACKREF_KEY;
key.offset = BTRFS_FS_TREE_OBJECTID;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0);
if (ret > 0) {
error("unable to find source fs image subvolume, is it deleted?");
diff --git a/convert/source-fs.c b/convert/source-fs.c
index f600b2c3..d206fab6 100644
--- a/convert/source-fs.c
+++ b/convert/source-fs.c
@@ -228,7 +228,7 @@ int record_file_blocks(struct blk_iterate_data *data,
int ret = 0;
struct btrfs_root *root = data->root;
struct btrfs_root *convert_root = data->convert_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
u32 sectorsize = root->fs_info->sectorsize;
u64 file_pos = file_block * sectorsize;
u64 old_disk_bytenr = disk_block * sectorsize;
@@ -241,8 +241,6 @@ int record_file_blocks(struct blk_iterate_data *data,
data->objectid, data->inode, file_pos, 0,
num_bytes);
- btrfs_init_path(&path);
-
/*
* Search real disk bytenr from convert root
*/
diff --git a/image/main.c b/image/main.c
index 856e313f..32f82705 100644
--- a/image/main.c
+++ b/image/main.c
@@ -1020,7 +1020,7 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
int walk_trees, bool dump_data)
{
struct btrfs_root *root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct metadump_struct metadump;
int ret;
int err = 0;
@@ -1048,8 +1048,6 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
goto out;
}
- btrfs_init_path(&path);
-
if (walk_trees) {
ret = copy_tree_blocks(root, root->fs_info->chunk_root->node,
&metadump, 1);
@@ -2392,7 +2390,7 @@ static int fixup_device_size(struct btrfs_trans_handle *trans,
struct btrfs_dev_item *dev_item;
struct btrfs_dev_extent *dev_ext;
struct btrfs_device *dev;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_root *root = fs_info->chunk_root;
struct btrfs_key key;
@@ -2403,7 +2401,6 @@ static int fixup_device_size(struct btrfs_trans_handle *trans,
dev_item = &fs_info->super_copy->dev_item;
- btrfs_init_path(&path);
devid = btrfs_stack_device_id(dev_item);
key.objectid = devid;
@@ -2568,7 +2565,7 @@ static int remove_all_dev_extents(struct btrfs_trans_handle *trans)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root = fs_info->dev_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct extent_buffer *leaf;
int slot;
@@ -2577,7 +2574,6 @@ static int remove_all_dev_extents(struct btrfs_trans_handle *trans)
key.objectid = 1;
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0) {
@@ -2944,7 +2940,7 @@ static int update_disk_super_on_device(struct btrfs_fs_info *info,
{
struct btrfs_key key;
struct extent_buffer *leaf;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_dev_item *dev_item;
struct btrfs_super_block disk_super;
char dev_uuid[BTRFS_UUID_SIZE];
@@ -2958,7 +2954,6 @@ static int update_disk_super_on_device(struct btrfs_fs_info *info,
key.type = BTRFS_DEV_ITEM_KEY;
key.offset = cur_devid;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, info->chunk_root, &key, &path, 0, 0);
if (ret) {
error("search key failed: %d", ret);
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 0bd24646..9ade5fca 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -83,11 +83,6 @@ u64 btrfs_extref_hash(u64 parent_objectid, const char *name, int len)
return (u64)crc32c(parent_objectid, name, len);
}
-inline void btrfs_init_path(struct btrfs_path *p)
-{
- memset(p, 0, sizeof(*p));
-}
-
struct btrfs_path *btrfs_alloc_path(void)
{
struct btrfs_path *path;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index cab8f71b..3ff11dd0 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -989,7 +989,6 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
void btrfs_release_path(struct btrfs_path *p);
struct btrfs_path *btrfs_alloc_path(void);
void btrfs_free_path(struct btrfs_path *p);
-void btrfs_init_path(struct btrfs_path *p);
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int slot, int nr);
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index ba853110..c2ff94f5 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -3463,7 +3463,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_block_group *block_group;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
block_group = btrfs_lookup_block_group(fs_info, bytenr);
@@ -3485,7 +3485,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
*/
btrfs_pin_extent(fs_info, bytenr, len);
- btrfs_init_path(&path);
/* delete block group item and chunk item */
ret = remove_block_group_item(trans, &path, block_group);
btrfs_release_path(&path);
diff --git a/kernel-shared/file.c b/kernel-shared/file.c
index 100ea31c..de5ecfea 100644
--- a/kernel-shared/file.c
+++ b/kernel-shared/file.c
@@ -187,7 +187,7 @@ int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, int len,
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_inode_item *ii;
u64 isize;
@@ -203,7 +203,6 @@ int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, int len,
return -EINVAL;
}
- btrfs_init_path(&path);
key.objectid = ino;
key.offset = start;
key.type = BTRFS_EXTENT_DATA_KEY;
diff --git a/kernel-shared/free-space-cache.c b/kernel-shared/free-space-cache.c
index 7bd76e39..e27c1b62 100644
--- a/kernel-shared/free-space-cache.c
+++ b/kernel-shared/free-space-cache.c
@@ -910,7 +910,7 @@ int btrfs_clear_free_space_cache(struct btrfs_trans_handle *trans,
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
struct btrfs_disk_key location;
struct btrfs_free_space_header *sc_header;
@@ -919,8 +919,6 @@ int btrfs_clear_free_space_cache(struct btrfs_trans_handle *trans,
int slot;
int ret;
- btrfs_init_path(&path);
-
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
key.type = 0;
key.offset = bg->start;
diff --git a/kernel-shared/inode.c b/kernel-shared/inode.c
index 1430cf33..d4018406 100644
--- a/kernel-shared/inode.c
+++ b/kernel-shared/inode.c
@@ -585,7 +585,7 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *new_root = NULL;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf;
struct btrfs_key key;
@@ -600,7 +600,6 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
if (len == 0 || len > BTRFS_NAME_LEN)
return NULL;
- btrfs_init_path(&path);
key.objectid = dirid;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = (u64)-1;
@@ -705,7 +704,6 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
new_root = NULL;
}
fail:
- btrfs_init_path(&path);
return new_root;
}
@@ -737,7 +735,6 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
search_key.offset = 0;
search_key.type = 0;
- btrfs_init_path(path);
start_found = 0;
ret = btrfs_search_slot(trans, root, &search_key, path, 0, 0);
if (ret < 0)
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index ff2a8097..9e9eb43a 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1501,7 +1501,7 @@ out:
static void bfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
{
struct btrfs_fs_info *fs_info = root_eb->fs_info;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int root_level = btrfs_header_level(root_eb);
int cur_level;
int ret;
@@ -1513,7 +1513,6 @@ static void bfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
mode |= BTRFS_PRINT_TREE_BFS;
mode &= ~(BTRFS_PRINT_TREE_DFS);
- btrfs_init_path(&path);
/* For path */
extent_buffer_get(root_eb);
path.nodes[root_level] = root_eb;
diff --git a/kernel-shared/volumes.c b/kernel-shared/volumes.c
index fff49a06..2ae4cc27 100644
--- a/kernel-shared/volumes.c
+++ b/kernel-shared/volumes.c
@@ -2664,7 +2664,7 @@ static int check_dev_extent_beyond_bytenr(struct btrfs_fs_info *fs_info,
u64 physical)
{
struct btrfs_root *root = fs_info->dev_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_dev_extent *dext;
struct btrfs_key key;
u64 dext_len;
@@ -2675,7 +2675,6 @@ static int check_dev_extent_beyond_bytenr(struct btrfs_fs_info *fs_info,
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0)
return ret;
@@ -2714,7 +2713,7 @@ static int reset_device_item_total_bytes(struct btrfs_fs_info *fs_info,
{
struct btrfs_trans_handle *trans;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *chunk_root = fs_info->chunk_root;
struct btrfs_dev_item *di;
u64 old_bytes = device->total_bytes;
@@ -2737,7 +2736,6 @@ static int reset_device_item_total_bytes(struct btrfs_fs_info *fs_info,
return ret;
}
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, chunk_root, &key, &path, 0, 1);
if (ret > 0) {
error("failed to find DEV_ITEM for devid %llu", device->devid);
diff --git a/mkfs/main.c b/mkfs/main.c
index 418c721c..e0b589cd 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -235,11 +235,10 @@ err:
static int __recow_root(struct btrfs_trans_handle *trans, struct btrfs_root *root)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
- btrfs_init_path(&path);
key.objectid = 0;
key.type = 0;
key.offset = 0;
@@ -590,10 +589,9 @@ static int cleanup_temp_chunks(struct btrfs_fs_info *fs_info,
struct btrfs_root *root = btrfs_block_group_root(fs_info);
struct btrfs_key key;
struct btrfs_key found_key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
int ret = 0;
- btrfs_init_path(&path);
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
@@ -707,7 +705,7 @@ static int create_data_reloc_tree(struct btrfs_trans_handle *trans)
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_inode_item *inode;
struct btrfs_root *root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key = {
.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID,
.type = BTRFS_ROOT_ITEM_KEY,
@@ -749,7 +747,6 @@ static int create_data_reloc_tree(struct btrfs_trans_handle *trans)
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
if (ret > 0) {
@@ -851,7 +848,7 @@ static int insert_qgroup_items(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
u64 qgroupid)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *quota_root = fs_info->quota_root;
struct btrfs_key key;
int ret;
@@ -865,7 +862,6 @@ static int insert_qgroup_items(struct btrfs_trans_handle *trans,
key.type = BTRFS_QGROUP_INFO_KEY;
key.offset = qgroupid;
- btrfs_init_path(&path);
ret = btrfs_insert_empty_item(trans, quota_root, &path, &key,
sizeof(struct btrfs_qgroup_info_item));
btrfs_release_path(&path);
@@ -886,7 +882,7 @@ static int setup_quota_root(struct btrfs_fs_info *fs_info)
struct btrfs_trans_handle *trans;
struct btrfs_qgroup_status_item *qsi;
struct btrfs_root *quota_root;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int qgroup_repaired = 0;
int ret;
@@ -910,7 +906,6 @@ static int setup_quota_root(struct btrfs_fs_info *fs_info)
key.type = BTRFS_QGROUP_STATUS_KEY;
key.offset = 0;
- btrfs_init_path(&path);
ret = btrfs_insert_empty_item(trans, quota_root, &path, &key,
sizeof(*qsi));
if (ret < 0) {
diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index aa2577ad..d6de3eba 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -455,7 +455,7 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
ino_t parent_inum, cur_inum;
ino_t highest_inum = 0;
const char *parent_dir_name;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct extent_buffer *leaf;
struct btrfs_key root_dir_key;
u64 root_dir_inode_size = 0;
@@ -476,8 +476,6 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
dir_entry->inum = parent_inum;
list_add_tail(&dir_entry->list, &dir_head->list);
- btrfs_init_path(&path);
-
root_dir_key.objectid = btrfs_root_dirid(&root->root_item);
root_dir_key.offset = 0;
root_dir_key.type = BTRFS_INODE_ITEM_KEY;
@@ -810,7 +808,7 @@ static int get_device_extent_end(struct btrfs_fs_info *fs_info,
{
struct btrfs_root *dev_root = fs_info->dev_root;
struct btrfs_key key;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_dev_extent *de;
int ret;
@@ -818,7 +816,6 @@ static int get_device_extent_end(struct btrfs_fs_info *fs_info,
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, dev_root, &key, &path, 0, 0);
if (ret == 0) {
error("DEV_EXTENT for devid %llu not found", devid);
@@ -862,7 +859,7 @@ static int set_device_size(struct btrfs_fs_info *fs_info,
struct btrfs_root *chunk_root = fs_info->chunk_root;
struct btrfs_trans_handle *trans;
struct btrfs_dev_item *di;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
int ret;
@@ -871,7 +868,6 @@ static int set_device_size(struct btrfs_fs_info *fs_info,
* super->dev_item will also get updated
*/
device->total_bytes = new_size;
- btrfs_init_path(&path);
/* Update device item in chunk tree */
trans = btrfs_start_transaction(chunk_root, 1);
diff --git a/quick-test.c b/quick-test.c
index 480e78bb..3f3c1cb3 100644
--- a/quick-test.c
+++ b/quick-test.c
@@ -41,7 +41,7 @@ int main(int ac, char **av) {
int run_size = 300000;
int max_key = 100000000;
int tree_size = 2;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_root *root;
struct btrfs_trans_handle *trans;
@@ -86,7 +86,6 @@ int main(int ac, char **av) {
for (i = 0; i < run_size; i++) {
num = next_key(i, max_key);
ins.objectid = num;
- btrfs_init_path(&path);
if (i % 10000 == 0)
fprintf(stderr, "search %d:%d\n", num, i);
ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
@@ -117,7 +116,6 @@ int main(int ac, char **av) {
for (i = 0 ; i < run_size/4; i++) {
num = next_key(i, max_key);
ins.objectid = num;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
if (!ret) {
if (i % 10000 == 0)
@@ -163,7 +161,6 @@ int main(int ac, char **av) {
for (i = 0; i < run_size; i++) {
num = next_key(i, max_key);
ins.objectid = num;
- btrfs_init_path(&path);
if (i % 10000 == 0)
fprintf(stderr, "search %d:%d\n", num, i);
ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
@@ -181,7 +178,6 @@ int main(int ac, char **av) {
struct extent_buffer *leaf;
int slot;
ins.objectid = (u64)-1;
- btrfs_init_path(&path);
ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
if (ret == 0)
BUG();
diff --git a/tune/change-csum.c b/tune/change-csum.c
index 49624c6f..f7917f0b 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -29,12 +29,11 @@ static int change_tree_csum(struct btrfs_trans_handle *trans, struct btrfs_root
int csum_type)
{
struct btrfs_fs_info *fs_info = root->fs_info;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key = {0, 0, 0};
int ret = 0;
int level;
- btrfs_init_path(&path);
/* No transaction, all in-place */
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0)
@@ -298,7 +297,7 @@ static int fill_csum_tree_from_extent(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *extent_root = btrfs_extent_root(fs_info, 0);
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_extent_item *ei;
struct extent_buffer *leaf;
char *buf;
@@ -313,7 +312,6 @@ static int fill_csum_tree_from_extent(struct btrfs_fs_info *fs_info)
return -EINVAL;
}
- btrfs_init_path(&path);
key.objectid = 0;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
@@ -373,7 +371,7 @@ int rewrite_checksums(struct btrfs_fs_info *fs_info, int csum_type)
struct btrfs_root *root;
struct btrfs_super_block *disk_super;
struct btrfs_trans_handle *trans;
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key;
u64 super_flags;
int ret;
@@ -404,7 +402,6 @@ int rewrite_checksums(struct btrfs_fs_info *fs_info, int csum_type)
return ret;
}
- btrfs_init_path(&path);
key.objectid = BTRFS_CSUM_TREE_TMP_OBJECTID;
key.type = BTRFS_TEMPORARY_ITEM_KEY;
key.offset = 0;
diff --git a/tune/change-uuid.c b/tune/change-uuid.c
index dae41056..41118416 100644
--- a/tune/change-uuid.c
+++ b/tune/change-uuid.c
@@ -81,11 +81,10 @@ static int change_buffer_header_uuid(struct extent_buffer *eb, uuid_t new_fsid)
static int change_extent_tree_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsid)
{
struct btrfs_root *root = btrfs_extent_root(fs_info, 0);
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key = {0, 0, 0};
int ret = 0;
- btrfs_init_path(&path);
/*
* Here we don't use transaction as it will takes a lot of reserve
* space, and that will make a near-full btrfs unable to change uuid
@@ -161,11 +160,10 @@ static int change_device_uuid(struct extent_buffer *eb, int slot,
static int change_chunk_tree_uuid(struct btrfs_root *root, uuid_t new_fsid)
{
- struct btrfs_path path;
+ struct btrfs_path path = {};
struct btrfs_key key = {0, 0, 0};
int ret = 0;
- btrfs_init_path(&path);
/* No transaction again */
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0)
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 15/26] btrfs-progs: move btrfs_set_item_key_unsafe to check/
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (13 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 14/26] btrfs-progs: drop btrfs_init_path Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 16/26] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
` (11 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This helper exists for check and for btrfs-corrupt-block. Move the
helper and the btrfs_fixup_low_keys helper into check/repair.[ch] so we
can keep the kernel-shared sources close to the upstream kernel.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
btrfs-corrupt-block.c | 1 +
check/repair.c | 47 +++++++++++++++++++++++++++++++++++++++++++
check/repair.h | 5 +++++
kernel-shared/ctree.c | 40 +++++++++---------------------------
kernel-shared/ctree.h | 5 -----
5 files changed, 62 insertions(+), 36 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 98cfe598..a97c3b90 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -35,6 +35,7 @@
#include "common/messages.h"
#include "common/string-utils.h"
#include "cmds/commands.h"
+#include "check/repair.h"
#define FIELD_BUF_LEN 80
diff --git a/check/repair.c b/check/repair.c
index c5afbaa1..d1407947 100644
--- a/check/repair.c
+++ b/check/repair.c
@@ -33,6 +33,53 @@
int opt_check_repair = 0;
+/*
+ * adjust the pointers going up the tree, starting at level
+ * making sure the right key of each node is points to 'key'.
+ * This is used after shifting pointers to the left, so it stops
+ * fixing up pointers when a given leaf/node is not in slot 0 of the
+ * higher levels
+ */
+void btrfs_fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
+ int level)
+{
+ int i;
+ struct extent_buffer *t;
+
+ for (i = level; i < BTRFS_MAX_LEVEL; i++) {
+ int tslot = path->slots[i];
+ if (!path->nodes[i])
+ break;
+ t = path->nodes[i];
+ btrfs_set_node_key(t, key, tslot);
+ btrfs_mark_buffer_dirty(path->nodes[i]);
+ if (tslot != 0)
+ break;
+ }
+}
+
+/*
+ * update an item key without the safety checks. This is meant to be called by
+ * fsck only.
+ */
+void btrfs_set_item_key_unsafe(struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct btrfs_key *new_key)
+{
+ struct btrfs_disk_key disk_key;
+ struct extent_buffer *eb;
+ int slot;
+
+ eb = path->nodes[0];
+ slot = path->slots[0];
+
+ btrfs_cpu_key_to_disk(&disk_key, new_key);
+ btrfs_set_item_key(eb, &disk_key, slot);
+ btrfs_mark_buffer_dirty(eb);
+ if (slot == 0)
+ btrfs_fixup_low_keys(path, &disk_key, 1);
+}
+
int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info,
struct btrfs_key *first_key,
u64 start, u64 len, int level)
diff --git a/check/repair.h b/check/repair.h
index d4222600..010cd391 100644
--- a/check/repair.h
+++ b/check/repair.h
@@ -45,4 +45,9 @@ int btrfs_mark_used_blocks(struct btrfs_fs_info *fs_info,
struct extent_io_tree *tree);
enum btrfs_tree_block_status btrfs_check_block_for_repair(struct extent_buffer *eb,
struct btrfs_key *first_key);
+void btrfs_set_item_key_unsafe(struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct btrfs_key *new_key);
+void btrfs_fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
+ int level);
#endif
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 9ade5fca..68c270ee 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1321,8 +1321,8 @@ again:
* fixing up pointers when a given leaf/node is not in slot 0 of the
* higher levels
*/
-void btrfs_fixup_low_keys( struct btrfs_path *path, struct btrfs_disk_key *key,
- int level)
+static void fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
+ int level)
{
int i;
struct extent_buffer *t;
@@ -1368,29 +1368,7 @@ void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
btrfs_set_item_key(eb, &disk_key, slot);
btrfs_mark_buffer_dirty(eb);
if (slot == 0)
- btrfs_fixup_low_keys(path, &disk_key, 1);
-}
-
-/*
- * update an item key without the safety checks. This is meant to be called by
- * fsck only.
- */
-void btrfs_set_item_key_unsafe(struct btrfs_root *root,
- struct btrfs_path *path,
- struct btrfs_key *new_key)
-{
- struct btrfs_disk_key disk_key;
- struct extent_buffer *eb;
- int slot;
-
- eb = path->nodes[0];
- slot = path->slots[0];
-
- btrfs_cpu_key_to_disk(&disk_key, new_key);
- btrfs_set_item_key(eb, &disk_key, slot);
- btrfs_mark_buffer_dirty(eb);
- if (slot == 0)
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
}
/*
@@ -2056,7 +2034,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_mark_buffer_dirty(right);
btrfs_item_key(right, &disk_key, 0);
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
/* then fixup the leaf pointer in the path */
if (path->slots[0] < push_items) {
@@ -2286,7 +2264,7 @@ again:
path->nodes[0] = right;
path->slots[0] = 0;
if (path->slots[1] == 0)
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
}
btrfs_mark_buffer_dirty(right);
return ret;
@@ -2491,7 +2469,7 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
btrfs_set_item_key(leaf, &disk_key, slot);
if (slot == 0)
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
}
btrfs_set_item_size(leaf, slot, new_size);
@@ -2655,7 +2633,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
ret = 0;
if (slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, cpu_key);
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
}
if (btrfs_leaf_free_space(leaf) < 0) {
@@ -2728,7 +2706,7 @@ int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_disk_key disk_key;
btrfs_node_key(parent, &disk_key, 0);
- btrfs_fixup_low_keys(path, &disk_key, level + 1);
+ fixup_low_keys(path, &disk_key, level + 1);
}
btrfs_mark_buffer_dirty(parent);
return ret;
@@ -2826,7 +2804,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_disk_key disk_key;
btrfs_item_key(leaf, &disk_key, 0);
- btrfs_fixup_low_keys(path, &disk_key, 1);
+ fixup_low_keys(path, &disk_key, 1);
}
/* delete the leaf if it is mostly empty */
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 3ff11dd0..d7b386db 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1051,14 +1051,9 @@ static inline int btrfs_next_item(struct btrfs_root *root,
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct extent_buffer *leaf);
-void btrfs_fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
- int level);
void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
const struct btrfs_key *new_key);
-void btrfs_set_item_key_unsafe(struct btrfs_root *root,
- struct btrfs_path *path,
- struct btrfs_key *new_key);
u16 btrfs_super_csum_size(const struct btrfs_super_block *s);
const char *btrfs_super_csum_name(u16 csum_type);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 16/26] btrfs-progs: move btrfs_record_file_extent and code into a new file
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (14 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 15/26] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 17/26] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
` (10 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This function and it's related functions only exist for the utilities
that populate existing file systems, and do not exist in the upstream
kernel. Move this function and the related function into it's own
common source file and out of the kernel-shared sources, and then update
all of the users to include the new location of this code.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
Makefile | 1 +
btrfs-map-logical.c | 1 +
common/extent-tree-utils.c | 282 ++++++++++++++++++++++++++++++++++++
common/extent-tree-utils.h | 28 ++++
convert/main.c | 1 +
convert/source-fs.c | 1 +
kernel-shared/ctree.c | 24 ---
kernel-shared/ctree.h | 7 -
kernel-shared/extent-tree.c | 234 ------------------------------
mkfs/rootdir.c | 1 +
10 files changed, 315 insertions(+), 265 deletions(-)
create mode 100644 common/extent-tree-utils.c
create mode 100644 common/extent-tree-utils.h
diff --git a/Makefile b/Makefile
index 6806d347..09e12d06 100644
--- a/Makefile
+++ b/Makefile
@@ -196,6 +196,7 @@ objects = \
common/device-scan.o \
common/device-utils.o \
common/extent-cache.o \
+ common/extent-tree-utils.o \
common/filesystem-utils.o \
common/format-output.o \
common/fsfeatures.o \
diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
index 19514e40..8631774c 100644
--- a/btrfs-map-logical.c
+++ b/btrfs-map-logical.c
@@ -33,6 +33,7 @@
#include "common/utils.h"
#include "common/help.h"
#include "common/extent-cache.h"
+#include "common/extent-tree-utils.h"
#include "common/string-utils.h"
#include "cmds/commands.h"
diff --git a/common/extent-tree-utils.c b/common/extent-tree-utils.c
new file mode 100644
index 00000000..06d5436f
--- /dev/null
+++ b/common/extent-tree-utils.c
@@ -0,0 +1,282 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include "kerncompat.h"
+#include "kernel-shared/ctree.h"
+#include "kernel-shared/disk-io.h"
+#include "kernel-shared/file-item.h"
+#include "kernel-shared/transaction.h"
+#include "kernel-shared/free-space-tree.h"
+#include "common/internal.h"
+#include "common/extent-tree-utils.h"
+#include "common/messages.h"
+
+/*
+ * Search in extent tree to found next meta/data extent
+ * Caller needs to check for no-hole or skinny metadata features.
+ */
+int btrfs_next_extent_item(struct btrfs_root *root, struct btrfs_path *path,
+ u64 max_objectid)
+{
+ struct btrfs_key found_key;
+ int ret;
+
+ while (1) {
+ ret = btrfs_next_item(root, path);
+ if (ret)
+ return ret;
+ btrfs_item_key_to_cpu(path->nodes[0], &found_key,
+ path->slots[0]);
+ if (found_key.objectid > max_objectid)
+ return 1;
+ if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
+ found_key.type == BTRFS_METADATA_ITEM_KEY)
+ return 0;
+ }
+}
+
+static void __get_extent_size(struct btrfs_root *root, struct btrfs_path *path,
+ u64 *start, u64 *len)
+{
+ struct btrfs_key key;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ BUG_ON(!(key.type == BTRFS_EXTENT_ITEM_KEY ||
+ key.type == BTRFS_METADATA_ITEM_KEY));
+ *start = key.objectid;
+ if (key.type == BTRFS_EXTENT_ITEM_KEY)
+ *len = key.offset;
+ else
+ *len = root->fs_info->nodesize;
+}
+
+/*
+ * Find first overlap extent for range [bytenr, bytenr + len)
+ * Return 0 for found and point path to it.
+ * Return >0 for not found.
+ * Return <0 for err
+ */
+static int btrfs_search_overlap_extent(struct btrfs_root *root,
+ struct btrfs_path *path, u64 bytenr, u64 len)
+{
+ struct btrfs_key key;
+ u64 cur_start;
+ u64 cur_len;
+ int ret;
+
+ key.objectid = bytenr;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+ BUG_ON(ret == 0);
+
+ ret = btrfs_previous_extent_item(root, path, 0);
+ if (ret < 0)
+ return ret;
+ /* no previous, check next extent */
+ if (ret > 0)
+ goto next;
+ __get_extent_size(root, path, &cur_start, &cur_len);
+ /* Tail overlap */
+ if (cur_start + cur_len > bytenr)
+ return 1;
+
+next:
+ ret = btrfs_next_extent_item(root, path, bytenr + len);
+ if (ret < 0)
+ return ret;
+ /* No next, prev already checked, no overlap */
+ if (ret > 0)
+ return 0;
+ __get_extent_size(root, path, &cur_start, &cur_len);
+ /* head overlap*/
+ if (cur_start < bytenr + len)
+ return 1;
+ return 0;
+}
+
+static int __btrfs_record_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid,
+ struct btrfs_inode_item *inode,
+ u64 file_pos, u64 disk_bytenr,
+ u64 *ret_num_bytes)
+{
+ int ret;
+ struct btrfs_fs_info *info = root->fs_info;
+ struct btrfs_root *extent_root = btrfs_extent_root(info, disk_bytenr);
+ struct extent_buffer *leaf;
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_key ins_key;
+ struct btrfs_path *path;
+ struct btrfs_extent_item *ei;
+ u64 nbytes;
+ u64 extent_num_bytes;
+ u64 extent_bytenr;
+ u64 extent_offset;
+ u64 num_bytes = *ret_num_bytes;
+
+ /*
+ * @objectid should be an inode number, thus it must not be smaller
+ * than BTRFS_FIRST_FREE_OBJECTID.
+ */
+ UASSERT(objectid >= BTRFS_FIRST_FREE_OBJECTID);
+
+ /*
+ * All supported file system should not use its 0 extent.
+ * As it's for hole
+ *
+ * And hole extent has no size limit, no need to loop.
+ */
+ if (disk_bytenr == 0) {
+ ret = btrfs_insert_file_extent(trans, root, objectid,
+ file_pos, disk_bytenr,
+ num_bytes, num_bytes);
+ return ret;
+ }
+ num_bytes = min_t(u64, num_bytes, BTRFS_MAX_EXTENT_SIZE);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ /* First to check extent overlap */
+ ret = btrfs_search_overlap_extent(extent_root, path, disk_bytenr,
+ num_bytes);
+ if (ret < 0)
+ goto fail;
+ if (ret > 0) {
+ /* Found overlap */
+ u64 cur_start;
+ u64 cur_len;
+
+ __get_extent_size(extent_root, path, &cur_start, &cur_len);
+ /*
+ * For convert case, this extent should be a subset of
+ * existing one.
+ */
+ BUG_ON(disk_bytenr < cur_start);
+
+ extent_bytenr = cur_start;
+ extent_num_bytes = cur_len;
+ extent_offset = disk_bytenr - extent_bytenr;
+ } else {
+ /* No overlap, create new extent */
+ btrfs_release_path(path);
+ ins_key.objectid = disk_bytenr;
+ ins_key.offset = num_bytes;
+ ins_key.type = BTRFS_EXTENT_ITEM_KEY;
+
+ ret = btrfs_insert_empty_item(trans, extent_root, path,
+ &ins_key, sizeof(*ei));
+ if (ret == 0) {
+ leaf = path->nodes[0];
+ ei = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_extent_item);
+
+ btrfs_set_extent_refs(leaf, ei, 0);
+ btrfs_set_extent_generation(leaf, ei, trans->transid);
+ btrfs_set_extent_flags(leaf, ei,
+ BTRFS_EXTENT_FLAG_DATA);
+ btrfs_mark_buffer_dirty(leaf);
+
+ ret = btrfs_update_block_group(trans, disk_bytenr,
+ num_bytes, 1, 0);
+ if (ret)
+ goto fail;
+ } else if (ret != -EEXIST) {
+ goto fail;
+ }
+
+ ret = remove_from_free_space_tree(trans, disk_bytenr, num_bytes);
+ if (ret)
+ goto fail;
+
+ btrfs_run_delayed_refs(trans, -1);
+ extent_bytenr = disk_bytenr;
+ extent_num_bytes = num_bytes;
+ extent_offset = 0;
+ }
+ btrfs_release_path(path);
+ ins_key.objectid = objectid;
+ ins_key.offset = file_pos;
+ ins_key.type = BTRFS_EXTENT_DATA_KEY;
+ ret = btrfs_insert_empty_item(trans, root, path, &ins_key,
+ sizeof(*fi));
+ if (ret)
+ goto fail;
+ leaf = path->nodes[0];
+ fi = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
+ btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
+ btrfs_set_file_extent_disk_bytenr(leaf, fi, extent_bytenr);
+ btrfs_set_file_extent_disk_num_bytes(leaf, fi, extent_num_bytes);
+ btrfs_set_file_extent_offset(leaf, fi, extent_offset);
+ btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_ram_bytes(leaf, fi, extent_num_bytes);
+ btrfs_set_file_extent_compression(leaf, fi, 0);
+ btrfs_set_file_extent_encryption(leaf, fi, 0);
+ btrfs_set_file_extent_other_encoding(leaf, fi, 0);
+ btrfs_mark_buffer_dirty(leaf);
+
+ nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
+ btrfs_set_stack_inode_nbytes(inode, nbytes);
+ btrfs_release_path(path);
+
+ ret = btrfs_inc_extent_ref(trans, extent_bytenr, extent_num_bytes,
+ 0, root->root_key.objectid, objectid,
+ file_pos - extent_offset);
+ if (ret)
+ goto fail;
+ ret = 0;
+ *ret_num_bytes = min(extent_num_bytes - extent_offset, num_bytes);
+fail:
+ btrfs_free_path(path);
+ return ret;
+}
+
+/*
+ * Record a file extent. Do all the required works, such as inserting
+ * file extent item, inserting extent item and backref item into extent
+ * tree and updating block accounting.
+ */
+int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid,
+ struct btrfs_inode_item *inode,
+ u64 file_pos, u64 disk_bytenr,
+ u64 num_bytes)
+{
+ u64 cur_disk_bytenr = disk_bytenr;
+ u64 cur_file_pos = file_pos;
+ u64 cur_num_bytes = num_bytes;
+ int ret = 0;
+
+ while (num_bytes > 0) {
+ ret = __btrfs_record_file_extent(trans, root, objectid,
+ inode, cur_file_pos,
+ cur_disk_bytenr,
+ &cur_num_bytes);
+ if (ret < 0)
+ break;
+ cur_disk_bytenr += cur_num_bytes;
+ cur_file_pos += cur_num_bytes;
+ num_bytes -= cur_num_bytes;
+ }
+ return ret;
+}
diff --git a/common/extent-tree-utils.h b/common/extent-tree-utils.h
new file mode 100644
index 00000000..4a774dc2
--- /dev/null
+++ b/common/extent-tree-utils.h
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef _EXTENT_TREE_UTILS_H_
+#define _EXTENT_TREE_UTILS_H_
+
+int btrfs_next_extent_item(struct btrfs_root *root, struct btrfs_path *path,
+ u64 max_objectid);
+int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 objectid,
+ struct btrfs_inode_item *inode,
+ u64 file_pos, u64 disk_bytenr,
+ u64 num_bytes);
+
+#endif /* _EXTENT_TREE_UTILS_H_ */
diff --git a/convert/main.c b/convert/main.c
index 78c8d76e..a8b74dfa 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -114,6 +114,7 @@
#include "common/device-scan.h"
#include "common/box.h"
#include "common/open-utils.h"
+#include "common/extent-tree-utils.h"
#include "cmds/commands.h"
#include "check/repair.h"
#include "mkfs/common.h"
diff --git a/convert/source-fs.c b/convert/source-fs.c
index d206fab6..cc82fdb6 100644
--- a/convert/source-fs.c
+++ b/convert/source-fs.c
@@ -24,6 +24,7 @@
#include "common/internal.h"
#include "common/messages.h"
#include "common/extent-cache.h"
+#include "common/extent-tree-utils.h"
#include "convert/common.h"
#include "convert/source-fs.h"
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 68c270ee..96d25953 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -3042,30 +3042,6 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
return 1;
}
-/*
- * Search in extent tree to found next meta/data extent
- * Caller needs to check for no-hole or skinny metadata features.
- */
-int btrfs_next_extent_item(struct btrfs_root *root,
- struct btrfs_path *path, u64 max_objectid)
-{
- struct btrfs_key found_key;
- int ret;
-
- while (1) {
- ret = btrfs_next_item(root, path);
- if (ret)
- return ret;
- btrfs_item_key_to_cpu(path->nodes[0], &found_key,
- path->slots[0]);
- if (found_key.objectid > max_objectid)
- return 1;
- if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
- found_key.type == BTRFS_METADATA_ITEM_KEY)
- return 0;
- }
-}
-
/*
* Search uuid tree - unmounted
*
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index d7b386db..cc71e2a5 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -928,11 +928,6 @@ int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_update_block_group(struct btrfs_trans_handle *trans, u64 bytenr,
u64 num, int alloc, int mark_free);
-int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode,
- u64 file_pos, u64 disk_bytenr,
- u64 num_bytes);
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
u64 bytenr, u64 len);
void free_excluded_extents(struct btrfs_fs_info *fs_info,
@@ -955,8 +950,6 @@ int btrfs_previous_item(struct btrfs_root *root,
int type);
int btrfs_previous_extent_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid);
-int btrfs_next_extent_item(struct btrfs_root *root,
- struct btrfs_path *path, u64 max_objectid);
int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index c2ff94f5..98c0b297 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -3520,240 +3520,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
return ret;
}
-static void __get_extent_size(struct btrfs_root *root, struct btrfs_path *path,
- u64 *start, u64 *len)
-{
- struct btrfs_key key;
-
- btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
- BUG_ON(!(key.type == BTRFS_EXTENT_ITEM_KEY ||
- key.type == BTRFS_METADATA_ITEM_KEY));
- *start = key.objectid;
- if (key.type == BTRFS_EXTENT_ITEM_KEY)
- *len = key.offset;
- else
- *len = root->fs_info->nodesize;
-}
-
-/*
- * Find first overlap extent for range [bytenr, bytenr + len)
- * Return 0 for found and point path to it.
- * Return >0 for not found.
- * Return <0 for err
- */
-static int btrfs_search_overlap_extent(struct btrfs_root *root,
- struct btrfs_path *path, u64 bytenr, u64 len)
-{
- struct btrfs_key key;
- u64 cur_start;
- u64 cur_len;
- int ret;
-
- key.objectid = bytenr;
- key.type = BTRFS_EXTENT_DATA_KEY;
- key.offset = (u64)-1;
-
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
- if (ret < 0)
- return ret;
- BUG_ON(ret == 0);
-
- ret = btrfs_previous_extent_item(root, path, 0);
- if (ret < 0)
- return ret;
- /* no previous, check next extent */
- if (ret > 0)
- goto next;
- __get_extent_size(root, path, &cur_start, &cur_len);
- /* Tail overlap */
- if (cur_start + cur_len > bytenr)
- return 1;
-
-next:
- ret = btrfs_next_extent_item(root, path, bytenr + len);
- if (ret < 0)
- return ret;
- /* No next, prev already checked, no overlap */
- if (ret > 0)
- return 0;
- __get_extent_size(root, path, &cur_start, &cur_len);
- /* head overlap*/
- if (cur_start < bytenr + len)
- return 1;
- return 0;
-}
-
-static int __btrfs_record_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode,
- u64 file_pos, u64 disk_bytenr,
- u64 *ret_num_bytes)
-{
- int ret;
- struct btrfs_fs_info *info = root->fs_info;
- struct btrfs_root *extent_root = btrfs_extent_root(info, disk_bytenr);
- struct extent_buffer *leaf;
- struct btrfs_file_extent_item *fi;
- struct btrfs_key ins_key;
- struct btrfs_path *path;
- struct btrfs_extent_item *ei;
- u64 nbytes;
- u64 extent_num_bytes;
- u64 extent_bytenr;
- u64 extent_offset;
- u64 num_bytes = *ret_num_bytes;
-
- /*
- * @objectid should be an inode number, thus it must not be smaller
- * than BTRFS_FIRST_FREE_OBJECTID.
- */
- ASSERT(objectid >= BTRFS_FIRST_FREE_OBJECTID);
-
- /*
- * All supported file system should not use its 0 extent.
- * As it's for hole
- *
- * And hole extent has no size limit, no need to loop.
- */
- if (disk_bytenr == 0) {
- ret = btrfs_insert_file_extent(trans, root, objectid,
- file_pos, disk_bytenr,
- num_bytes, num_bytes);
- return ret;
- }
- num_bytes = min_t(u64, num_bytes, BTRFS_MAX_EXTENT_SIZE);
-
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
-
- /* First to check extent overlap */
- ret = btrfs_search_overlap_extent(extent_root, path, disk_bytenr,
- num_bytes);
- if (ret < 0)
- goto fail;
- if (ret > 0) {
- /* Found overlap */
- u64 cur_start;
- u64 cur_len;
-
- __get_extent_size(extent_root, path, &cur_start, &cur_len);
- /*
- * For convert case, this extent should be a subset of
- * existing one.
- */
- BUG_ON(disk_bytenr < cur_start);
-
- extent_bytenr = cur_start;
- extent_num_bytes = cur_len;
- extent_offset = disk_bytenr - extent_bytenr;
- } else {
- /* No overlap, create new extent */
- btrfs_release_path(path);
- ins_key.objectid = disk_bytenr;
- ins_key.offset = num_bytes;
- ins_key.type = BTRFS_EXTENT_ITEM_KEY;
-
- ret = btrfs_insert_empty_item(trans, extent_root, path,
- &ins_key, sizeof(*ei));
- if (ret == 0) {
- leaf = path->nodes[0];
- ei = btrfs_item_ptr(leaf, path->slots[0],
- struct btrfs_extent_item);
-
- btrfs_set_extent_refs(leaf, ei, 0);
- btrfs_set_extent_generation(leaf, ei, trans->transid);
- btrfs_set_extent_flags(leaf, ei,
- BTRFS_EXTENT_FLAG_DATA);
- btrfs_mark_buffer_dirty(leaf);
-
- ret = btrfs_update_block_group(trans, disk_bytenr,
- num_bytes, 1, 0);
- if (ret)
- goto fail;
- } else if (ret != -EEXIST) {
- goto fail;
- }
-
- ret = remove_from_free_space_tree(trans, disk_bytenr, num_bytes);
- if (ret)
- goto fail;
-
- btrfs_run_delayed_refs(trans, -1);
- extent_bytenr = disk_bytenr;
- extent_num_bytes = num_bytes;
- extent_offset = 0;
- }
- btrfs_release_path(path);
- ins_key.objectid = objectid;
- ins_key.offset = file_pos;
- ins_key.type = BTRFS_EXTENT_DATA_KEY;
- ret = btrfs_insert_empty_item(trans, root, path, &ins_key,
- sizeof(*fi));
- if (ret)
- goto fail;
- leaf = path->nodes[0];
- fi = btrfs_item_ptr(leaf, path->slots[0],
- struct btrfs_file_extent_item);
- btrfs_set_file_extent_generation(leaf, fi, trans->transid);
- btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
- btrfs_set_file_extent_disk_bytenr(leaf, fi, extent_bytenr);
- btrfs_set_file_extent_disk_num_bytes(leaf, fi, extent_num_bytes);
- btrfs_set_file_extent_offset(leaf, fi, extent_offset);
- btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
- btrfs_set_file_extent_ram_bytes(leaf, fi, extent_num_bytes);
- btrfs_set_file_extent_compression(leaf, fi, 0);
- btrfs_set_file_extent_encryption(leaf, fi, 0);
- btrfs_set_file_extent_other_encoding(leaf, fi, 0);
- btrfs_mark_buffer_dirty(leaf);
-
- nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
- btrfs_set_stack_inode_nbytes(inode, nbytes);
- btrfs_release_path(path);
-
- ret = btrfs_inc_extent_ref(trans, extent_bytenr, extent_num_bytes,
- 0, root->root_key.objectid, objectid,
- file_pos - extent_offset);
- if (ret)
- goto fail;
- ret = 0;
- *ret_num_bytes = min(extent_num_bytes - extent_offset, num_bytes);
-fail:
- btrfs_free_path(path);
- return ret;
-}
-
-/*
- * Record a file extent. Do all the required works, such as inserting
- * file extent item, inserting extent item and backref item into extent
- * tree and updating block accounting.
- */
-int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode,
- u64 file_pos, u64 disk_bytenr,
- u64 num_bytes)
-{
- u64 cur_disk_bytenr = disk_bytenr;
- u64 cur_file_pos = file_pos;
- u64 cur_num_bytes = num_bytes;
- int ret = 0;
-
- while (num_bytes > 0) {
- ret = __btrfs_record_file_extent(trans, root, objectid,
- inode, cur_file_pos,
- cur_disk_bytenr,
- &cur_num_bytes);
- if (ret < 0)
- break;
- cur_disk_bytenr += cur_num_bytes;
- cur_file_pos += cur_num_bytes;
- num_bytes -= cur_num_bytes;
- }
- return ret;
-}
-
-
static int add_excluded_extent(struct btrfs_fs_info *fs_info,
u64 start, u64 num_bytes)
{
diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index d6de3eba..91f97ed6 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -39,6 +39,7 @@
#include "common/internal.h"
#include "common/messages.h"
#include "common/path-utils.h"
+#include "common/extent-tree-utils.h"
#include "mkfs/rootdir.h"
static u32 fs_block_size;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 17/26] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (15 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 16/26] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 18/26] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
` (9 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
We use this in print-tree to do BFS tree printing, but there are no
other users and it doesn't exist upstream. Copy the current code and
clean it up so it can exist in print-tree.c and use the local copy
there. This will allow us to remove the function call when ctree.c is
synced.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/print-tree.c | 53 +++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 9e9eb43a..5147f652 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1498,6 +1498,57 @@ out:
return ret;
}
+/*
+ * Walk up the tree as far as necessary to find the next sibling tree block.
+ * More generic version of btrfs_next_leaf(), as it could find sibling nodes
+ * if @path->lowest_level is not 0.
+ *
+ * returns 0 if it found something or 1 if there are no greater leaves.
+ * returns < 0 on io errors.
+ */
+int next_sibling_tree_block(struct btrfs_fs_info *fs_info,
+ struct btrfs_path *path)
+{
+ int slot;
+ int level = path->lowest_level + 1;
+ struct extent_buffer *c;
+ struct extent_buffer *next = NULL;
+
+ BUG_ON(path->lowest_level + 1 >= BTRFS_MAX_LEVEL);
+ do {
+ if (!path->nodes[level])
+ return 1;
+
+ slot = path->slots[level] + 1;
+ c = path->nodes[level];
+ if (slot >= btrfs_header_nritems(c)) {
+ level++;
+ if (level == BTRFS_MAX_LEVEL)
+ return 1;
+ continue;
+ }
+
+ next = btrfs_read_node_slot(c, slot);
+ if (!extent_buffer_uptodate(next))
+ return -EIO;
+ break;
+ } while (level < BTRFS_MAX_LEVEL);
+ path->slots[level] = slot;
+ while(1) {
+ level--;
+ c = path->nodes[level];
+ free_extent_buffer(c);
+ path->nodes[level] = next;
+ path->slots[level] = 0;
+ if (level == path->lowest_level)
+ break;
+ next = btrfs_read_node_slot(next, 0);
+ if (!extent_buffer_uptodate(next))
+ return -EIO;
+ }
+ return 0;
+}
+
static void bfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
{
struct btrfs_fs_info *fs_info = root_eb->fs_info;
@@ -1528,7 +1579,7 @@ static void bfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
/* Print all sibling tree blocks */
while (1) {
btrfs_print_tree(path.nodes[cur_level], mode);
- ret = btrfs_next_sibling_tree_block(fs_info, &path);
+ ret = next_sibling_tree_block(fs_info, &path);
if (ret < 0)
goto out;
if (ret > 0) {
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 18/26] btrfs-progs: don't set the ->commit_root in btrfs_create_tree
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (16 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 17/26] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 19/26] btrfs-progs: remove btrfs_create_root Josef Bacik
` (8 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In btrfs_create_tree we set ->commit_root to the current node, however
we don't add the root to the dirty list, so this is never cleaned up.
This is a problem in btrfs-progs because the transaction commit stuff
clears the commit_root when we write the dirty root out, so if we try to
re-modify this root later we'll fail to start the transaction. Fix this
by noting that we do this differently in the kernel, and drop the
assignment as we're inserting the root into the tree_root in this
function and thus don't need to update it again at transaction commit
time.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/disk-io.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index b7a98c4c..ec97ff08 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2384,7 +2384,14 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
extent_buffer_get(root->node);
- root->commit_root = root->node;
+
+ /*
+ * MODIFIED:
+ * - In the kernel we set ->commit_root here, however in btrfs-progs
+ * confuses the transaction code. For now don't set the commit_root
+ * here, if we update transaction.c to match the kernel version we
+ * need to revisit this.
+ */
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
root->root_item.flags = 0;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 19/26] btrfs-progs: remove btrfs_create_root
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (17 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 18/26] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 20/26] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
` (7 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
We have btrfs_create_root and btrfs_create_tree that do essentially the
same thing. However btrfs_create_root isn't in the kernel, and
btrfs_create_tree is. Update all of the callers of btrfs_create_root to
use btrfs_create_tree instead and then remove btrfs_create_root.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 123 ------------------------------------------
kernel-shared/ctree.h | 2 -
mkfs/main.c | 14 +++--
tune/change-csum.c | 11 +++-
tune/convert-bgt.c | 13 +++--
5 files changed, 29 insertions(+), 134 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 96d25953..327ff40c 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -193,129 +193,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
return 0;
}
-/*
- * Create a new tree root, with root objectid set to @objectid.
- *
- * NOTE: Doesn't support tree with non-zero offset, like data reloc tree.
- */
-int btrfs_create_root(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 objectid)
-{
- struct extent_buffer *node;
- struct btrfs_root *new_root;
- struct btrfs_disk_key disk_key;
- struct btrfs_key location;
- struct btrfs_root_item root_item = { 0 };
- int ret;
-
- new_root = malloc(sizeof(*new_root));
- if (!new_root)
- return -ENOMEM;
-
- btrfs_setup_root(new_root, fs_info, objectid);
- if (!is_fstree(objectid))
- set_bit(BTRFS_ROOT_TRACK_DIRTY, &new_root->state);
- add_root_to_dirty_list(new_root);
-
- new_root->objectid = objectid;
- new_root->root_key.objectid = objectid;
- new_root->root_key.type = BTRFS_ROOT_ITEM_KEY;
- new_root->root_key.offset = 0;
-
- node = btrfs_alloc_tree_block(trans, new_root, fs_info->nodesize,
- objectid, &disk_key, 0, 0, 0,
- BTRFS_NESTING_NORMAL);
- if (IS_ERR(node)) {
- ret = PTR_ERR(node);
- error("failed to create root node for tree %llu: %d (%m)",
- objectid, ret);
- return ret;
- }
- new_root->node = node;
-
- memset_extent_buffer(node, 0, 0, sizeof(struct btrfs_header));
- btrfs_set_header_bytenr(node, node->start);
- btrfs_set_header_generation(node, trans->transid);
- btrfs_set_header_backref_rev(node, BTRFS_MIXED_BACKREF_REV);
- btrfs_set_header_owner(node, objectid);
- write_extent_buffer(node, fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
- write_extent_buffer(node, fs_info->chunk_tree_uuid,
- btrfs_header_chunk_tree_uuid(node),
- BTRFS_UUID_SIZE);
- btrfs_set_header_nritems(node, 0);
- btrfs_set_header_level(node, 0);
- ret = btrfs_inc_ref(trans, new_root, node, 0);
- if (ret < 0)
- goto free;
-
- /*
- * Special tree roots may need to modify pointers in @fs_info
- * Only quota is supported yet.
- */
- switch (objectid) {
- case BTRFS_QUOTA_TREE_OBJECTID:
- if (fs_info->quota_root) {
- error("quota root already exists");
- ret = -EEXIST;
- goto free;
- }
- fs_info->quota_root = new_root;
- fs_info->quota_enabled = 1;
- break;
- case BTRFS_BLOCK_GROUP_TREE_OBJECTID:
- if (fs_info->block_group_root) {
- error("bg root already exists");
- ret = -EEXIST;
- goto free;
- }
- fs_info->block_group_root = new_root;
- break;
-
- case BTRFS_CSUM_TREE_TMP_OBJECTID:
- fs_info->csum_tree_tmp = new_root;
- break;
- /*
- * Essential trees can't be created by this function, yet.
- * As we expect such skeleton exists, or a lot of functions like
- * btrfs_alloc_tree_block() doesn't work at all
- */
- case BTRFS_ROOT_TREE_OBJECTID:
- case BTRFS_EXTENT_TREE_OBJECTID:
- case BTRFS_CHUNK_TREE_OBJECTID:
- case BTRFS_FS_TREE_OBJECTID:
- ret = -EEXIST;
- goto free;
- default:
- /* Subvolume trees don't need special handling */
- if (is_fstree(objectid))
- break;
- /* Other special trees are not supported yet */
- ret = -ENOTTY;
- goto free;
- }
- btrfs_mark_buffer_dirty(node);
- btrfs_set_root_bytenr(&root_item, btrfs_header_bytenr(node));
- btrfs_set_root_level(&root_item, 0);
- btrfs_set_root_generation(&root_item, trans->transid);
- btrfs_set_root_dirid(&root_item, 0);
- btrfs_set_root_refs(&root_item, 1);
- btrfs_set_root_used(&root_item, fs_info->nodesize);
- location.objectid = objectid;
- location.type = BTRFS_ROOT_ITEM_KEY;
- location.offset = 0;
-
- ret = btrfs_insert_root(trans, fs_info->tree_root, &location, &root_item);
- if (ret < 0)
- goto free;
- return ret;
-
-free:
- free_extent_buffer(node);
- free(new_root);
- return ret;
-}
-
/*
* check if the tree block can be shared by multiple trees
*/
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index cc71e2a5..ce1c3d25 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -958,8 +958,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
struct extent_buffer **cow_ret, u64 new_root_objectid);
-int btrfs_create_root(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, u64 objectid);
void btrfs_extend_item(struct btrfs_path *path, u32 data_size);
void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
diff --git a/mkfs/main.c b/mkfs/main.c
index e0b589cd..88fea33b 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -883,7 +883,10 @@ static int setup_quota_root(struct btrfs_fs_info *fs_info)
struct btrfs_qgroup_status_item *qsi;
struct btrfs_root *quota_root;
struct btrfs_path path = {};
- struct btrfs_key key;
+ struct btrfs_key key = {
+ .objectid = BTRFS_QUOTA_TREE_OBJECTID,
+ .type = BTRFS_ROOT_ITEM_KEY,
+ };
int qgroup_repaired = 0;
int ret;
@@ -895,12 +898,15 @@ static int setup_quota_root(struct btrfs_fs_info *fs_info)
error_msg(ERROR_MSG_START_TRANS, "%m");
return ret;
}
- ret = btrfs_create_root(trans, fs_info, BTRFS_QUOTA_TREE_OBJECTID);
- if (ret < 0) {
+
+ quota_root = btrfs_create_tree(trans, fs_info, &key);
+ if (IS_ERR(quota_root)) {
+ ret = PTR_ERR(quota_root);
error("failed to create quota root: %d (%m)", ret);
goto fail;
}
- quota_root = fs_info->quota_root;
+ fs_info->quota_root = quota_root;
+ fs_info->quota_enabled = 1;
key.objectid = 0;
key.type = BTRFS_QGROUP_STATUS_KEY;
diff --git a/tune/change-csum.c b/tune/change-csum.c
index f7917f0b..e75d0d9f 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -410,6 +410,11 @@ int rewrite_checksums(struct btrfs_fs_info *fs_info, int csum_type)
return ret;
if (ret == 1) {
+ struct btrfs_root *tmp;
+ struct btrfs_key key = {
+ .objectid = BTRFS_CSUM_TREE_TMP_OBJECTID,
+ .type = BTRFS_ROOT_ITEM_KEY,
+ };
struct item {
u64 offset;
u64 generation;
@@ -421,10 +426,12 @@ int rewrite_checksums(struct btrfs_fs_info *fs_info, int csum_type)
*/
} item[1];
- ret = btrfs_create_root(trans, fs_info, BTRFS_CSUM_TREE_TMP_OBJECTID);
- if (ret < 0) {
+ tmp = btrfs_create_tree(trans, fs_info, &key);
+ if (IS_ERR(tmp)) {
+ ret = PTR_ERR(tmp);
return ret;
} else {
+ fs_info->csum_tree_tmp = tmp;
item->offset = btrfs_header_bytenr(fs_info->csum_tree_tmp->node);
item->generation = btrfs_super_generation(fs_info->super_copy);
item->csum_type = csum_type;
diff --git a/tune/convert-bgt.c b/tune/convert-bgt.c
index 79d9169e..cdd0a007 100644
--- a/tune/convert-bgt.c
+++ b/tune/convert-bgt.c
@@ -30,7 +30,12 @@ int convert_to_bg_tree(struct btrfs_fs_info *fs_info)
{
struct btrfs_super_block *sb = fs_info->super_copy;
struct btrfs_trans_handle *trans;
+ struct btrfs_root *root;
struct cache_extent *ce;
+ struct btrfs_key key = {
+ .objectid = BTRFS_BLOCK_GROUP_TREE_OBJECTID,
+ .type = BTRFS_ROOT_ITEM_KEY,
+ };
int converted_bgs = 0;
int ret;
@@ -50,12 +55,14 @@ int convert_to_bg_tree(struct btrfs_fs_info *fs_info)
if (btrfs_super_flags(sb) & BTRFS_SUPER_FLAG_CHANGING_BG_TREE)
goto iterate_bgs;
- ret = btrfs_create_root(trans, fs_info,
- BTRFS_BLOCK_GROUP_TREE_OBJECTID);
- if (ret < 0) {
+ root = btrfs_create_tree(trans, fs_info, &key);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
error("failed to create block group root: %d", ret);
goto error;
}
+ fs_info->block_group_root = root;
+
btrfs_set_super_flags(sb,
btrfs_super_flags(sb) |
BTRFS_SUPER_FLAG_CHANGING_BG_TREE);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 20/26] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (18 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 19/26] btrfs-progs: remove btrfs_create_root Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 21/26] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
` (6 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This function is only used in mkfs, and doesn't exist in the kernel in
ctree.c. Additionally we have a uuid lookup function to see if the uuid
exists in the tree, which for mkfs it won't because we just created the
tree. Move btrfs_uuid_tree_add into mkfs, and remove the lookup
function as it's not needed.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.c | 133 ------------------------------------------
kernel-shared/ctree.h | 2 -
mkfs/main.c | 59 +++++++++++++++++++
3 files changed, 59 insertions(+), 135 deletions(-)
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 327ff40c..9cb58908 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2918,136 +2918,3 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
}
return 1;
}
-
-/*
- * Search uuid tree - unmounted
- *
- * return -ENOENT for !found, < 0 for errors, or 0 if an item was found
- */
-static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
- u8 type, u64 subid)
-{
- int ret;
- struct btrfs_path *path = NULL;
- struct extent_buffer *eb;
- int slot;
- u32 item_size;
- unsigned long offset;
- struct btrfs_key key;
-
- if (!uuid_root) {
- ret = -ENOENT;
- goto out;
- }
-
- path = btrfs_alloc_path();
- if (!path) {
- ret = -ENOMEM;
- goto out;
- }
-
- btrfs_uuid_to_key(uuid, &key);
- key.type = type;
- ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
- if (ret < 0) {
- goto out;
- } else if (ret > 0) {
- ret = -ENOENT;
- goto out;
- }
-
- eb = path->nodes[0];
- slot = path->slots[0];
- item_size = btrfs_item_size(eb, slot);
- offset = btrfs_item_ptr_offset(eb, slot);
- ret = -ENOENT;
-
- if (!IS_ALIGNED(item_size, sizeof(u64))) {
- warning("uuid item with invalid size %lu!",
- (unsigned long)item_size);
- goto out;
- }
- while (item_size) {
- __le64 data;
-
- read_extent_buffer(eb, &data, offset, sizeof(data));
- if (le64_to_cpu(data) == subid) {
- ret = 0;
- break;
- }
- offset += sizeof(data);
- item_size -= sizeof(data);
- }
-
-out:
- btrfs_free_path(path);
- return ret;
-}
-
-int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
- u64 subvol_id_cpu)
-{
- struct btrfs_fs_info *fs_info = trans->fs_info;
- struct btrfs_root *uuid_root = fs_info->uuid_root;
- int ret;
- struct btrfs_path *path = NULL;
- struct btrfs_key key;
- struct extent_buffer *eb;
- int slot;
- unsigned long offset;
- __le64 subvol_id_le;
-
- if (!uuid_root) {
- warning("%s: uuid root is not initialized", __func__);
- return -EINVAL;
- }
-
- ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subvol_id_cpu);
- if (ret != -ENOENT)
- return ret;
-
- key.type = type;
- btrfs_uuid_to_key(uuid, &key);
-
- path = btrfs_alloc_path();
- if (!path) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
- sizeof(subvol_id_le));
- if (ret < 0 && ret != -EEXIST) {
- warning(
- "inserting uuid item failed (0x%016llx, 0x%016llx) type %u: %d",
- (unsigned long long)key.objectid,
- (unsigned long long)key.offset, type, ret);
- goto out;
- }
-
- if (ret >= 0) {
- /* Add an item for the type for the first time */
- eb = path->nodes[0];
- slot = path->slots[0];
- offset = btrfs_item_ptr_offset(eb, slot);
- } else {
- /*
- * ret == -EEXIST case, An item with that type already exists.
- * Extend the item and store the new subvol_id at the end.
- */
- btrfs_extend_item(path, sizeof(subvol_id_le));
- eb = path->nodes[0];
- slot = path->slots[0];
- offset = btrfs_item_ptr_offset(eb, slot);
- offset += btrfs_item_size(eb, slot) - sizeof(subvol_id_le);
- }
-
- ret = 0;
- subvol_id_le = cpu_to_le64(subvol_id_cpu);
- write_extent_buffer(eb, &subvol_id_le, offset, sizeof(subvol_id_le));
- btrfs_mark_buffer_dirty(eb);
-
-out:
- btrfs_free_path(path);
- return ret;
-}
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index ce1c3d25..40b8854c 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1130,8 +1130,6 @@ int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid,
u64 *subvol_id);
/* uuid-tree.c, interface for unmounte filesystem */
-int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
- u64 subvol_id_cpu);
int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
u64 subid);
diff --git a/mkfs/main.c b/mkfs/main.c
index 88fea33b..a008f139 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -769,6 +769,65 @@ out:
return ret;
}
+static int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid,
+ u8 type, u64 subvol_id_cpu)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_root *uuid_root = fs_info->uuid_root;
+ int ret;
+ struct btrfs_path *path = NULL;
+ struct btrfs_key key;
+ struct extent_buffer *eb;
+ int slot;
+ unsigned long offset;
+ __le64 subvol_id_le;
+
+ key.type = type;
+ btrfs_uuid_to_key(uuid, &key);
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
+ sizeof(subvol_id_le));
+ if (ret < 0 && ret != -EEXIST) {
+ warning(
+ "inserting uuid item failed (0x%016llx, 0x%016llx) type %u: %d",
+ (unsigned long long)key.objectid,
+ (unsigned long long)key.offset, type, ret);
+ goto out;
+ }
+
+ if (ret >= 0) {
+ /* Add an item for the type for the first time */
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ offset = btrfs_item_ptr_offset(eb, slot);
+ } else {
+ /*
+ * ret == -EEXIST case, An item with that type already exists.
+ * Extend the item and store the new subvol_id at the end.
+ */
+ btrfs_extend_item(path, sizeof(subvol_id_le));
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ offset = btrfs_item_ptr_offset(eb, slot);
+ offset += btrfs_item_size(eb, slot) - sizeof(subvol_id_le);
+ }
+
+ ret = 0;
+ subvol_id_le = cpu_to_le64(subvol_id_cpu);
+ write_extent_buffer(eb, &subvol_id_le, offset, sizeof(subvol_id_le));
+ btrfs_mark_buffer_dirty(eb);
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
static int create_uuid_tree(struct btrfs_trans_handle *trans)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 21/26] btrfs-progs: make btrfs_del_ptr a void
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (19 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 20/26] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 22/26] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
` (5 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This always returns 0, and in the kernel is a void. Update the
definition to match the kernel and then update all of the callers.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/main.c | 7 +++----
kernel-shared/ctree.c | 16 ++++------------
kernel-shared/ctree.h | 2 +-
3 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/check/main.c b/check/main.c
index 5e4f5827..2643244f 100644
--- a/check/main.c
+++ b/check/main.c
@@ -3569,9 +3569,8 @@ static int repair_btree(struct btrfs_root *root,
path.slots[level]);
/* Remove the ptr */
- ret = btrfs_del_ptr(root, &path, level, path.slots[level]);
- if (ret < 0)
- goto out;
+ btrfs_del_ptr(root, &path, level, path.slots[level]);
+
/*
* Remove the corresponding extent
* return value is not concerned.
@@ -7829,7 +7828,7 @@ again:
del_ptr:
printk("deleting pointer to block %llu\n", corrupt->cache.start);
- ret = btrfs_del_ptr(extent_root, &path, level, slot);
+ btrfs_del_ptr(extent_root, &path, level, slot);
out:
btrfs_release_path(&path);
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 9cb58908..f9cf78da 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -685,9 +685,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
btrfs_clear_buffer_dirty(trans, right);
free_extent_buffer(right);
right = NULL;
- wret = btrfs_del_ptr(root, path, level + 1, pslot + 1);
- if (wret)
- ret = wret;
+ btrfs_del_ptr(root, path, level + 1, pslot + 1);
root_sub_used(root, blocksize);
wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
@@ -732,9 +730,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
btrfs_clear_buffer_dirty(trans, mid);
free_extent_buffer(mid);
mid = NULL;
- wret = btrfs_del_ptr(root, path, level + 1, pslot);
- if (wret)
- ret = wret;
+ btrfs_del_ptr(root, path, level + 1, pslot);
root_sub_used(root, blocksize);
wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
@@ -2557,12 +2553,11 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
* continuing all the way the root if required. The root is converted into
* a leaf if all the nodes are emptied.
*/
-int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
+void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot)
{
struct extent_buffer *parent = path->nodes[level];
u32 nritems;
- int ret = 0;
nritems = btrfs_header_nritems(parent);
if (slot < nritems - 1) {
@@ -2586,7 +2581,6 @@ int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
fixup_low_keys(path, &disk_key, level + 1);
}
btrfs_mark_buffer_dirty(parent);
- return ret;
}
/*
@@ -2607,9 +2601,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
int ret;
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
- ret = btrfs_del_ptr(root, path, 1, path->slots[1]);
- if (ret)
- return ret;
+ btrfs_del_ptr(root, path, 1, path->slots[1]);
root_sub_used(root, leaf->len);
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 40b8854c..88a105ab 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -941,7 +941,7 @@ int btrfs_convert_one_bg(struct btrfs_trans_handle *trans, u64 bytenr);
/* ctree.c */
int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
-int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
+void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot);
struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
int slot);
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 22/26] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (20 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 21/26] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 23/26] btrfs-progs: use path->search_for_extension Josef Bacik
` (4 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
In the kernel we pass in the parent to btrfs_alloc_tree_block instead of
the blocksize and simply derive the blocksize from the fs_info. Update
the function to match the kernel's convention and update all of the
callers so we can sync ctree.c easily.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/main.c | 3 +--
cmds/rescue-chunk-recover.c | 3 +--
kernel-shared/ctree.c | 29 ++++++++++++-----------------
kernel-shared/ctree.h | 2 +-
kernel-shared/disk-io.c | 5 ++---
kernel-shared/extent-tree.c | 9 +++++----
6 files changed, 22 insertions(+), 29 deletions(-)
diff --git a/check/main.c b/check/main.c
index 2643244f..ca49863b 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9067,8 +9067,7 @@ static struct extent_buffer *btrfs_fsck_clear_root(
if (!path)
return ERR_PTR(-ENOMEM);
- c = btrfs_alloc_tree_block(trans, gfs_info->tree_root,
- gfs_info->nodesize, key->objectid,
+ c = btrfs_alloc_tree_block(trans, gfs_info->tree_root, 0, key->objectid,
&disk_key, 0, 0, 0, BTRFS_NESTING_NORMAL);
if (IS_ERR(c)) {
btrfs_free_path(path);
diff --git a/cmds/rescue-chunk-recover.c b/cmds/rescue-chunk-recover.c
index f30612d1..660d17f7 100644
--- a/cmds/rescue-chunk-recover.c
+++ b/cmds/rescue-chunk-recover.c
@@ -1143,8 +1143,7 @@ static int __rebuild_chunk_root(struct btrfs_trans_handle *trans,
btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_ITEM_KEY);
btrfs_set_disk_key_offset(&disk_key, min_devid);
- cow = btrfs_alloc_tree_block(trans, root, root->fs_info->nodesize,
- BTRFS_CHUNK_TREE_OBJECTID,
+ cow = btrfs_alloc_tree_block(trans, root, 0, BTRFS_CHUNK_TREE_OBJECTID,
&disk_key, 0, 0, 0, BTRFS_NESTING_NORMAL);
btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid);
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index f9cf78da..2728452f 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -158,9 +158,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_item_key(buf, &disk_key, 0);
else
btrfs_node_key(buf, &disk_key, 0);
- cow = btrfs_alloc_tree_block(trans, new_root, buf->len,
- new_root_objectid, &disk_key,
- level, buf->start, 0,
+ cow = btrfs_alloc_tree_block(trans, new_root, 0, new_root_objectid,
+ &disk_key, level, buf->start, 0,
BTRFS_NESTING_NORMAL);
if (IS_ERR(cow)) {
kfree(new_root);
@@ -329,9 +328,8 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else
btrfs_node_key(buf, &disk_key, 0);
- cow = btrfs_alloc_tree_block(trans, root, buf->len,
- root->root_key.objectid, &disk_key,
- level, search_start, empty_size,
+ cow = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+ &disk_key, level, search_start, empty_size,
BTRFS_NESTING_NORMAL);
if (IS_ERR(cow))
return PTR_ERR(cow);
@@ -1395,9 +1393,8 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
else
btrfs_node_key(lower, &lower_key, 0);
- c = btrfs_alloc_tree_block(trans, root, root->fs_info->nodesize,
- root->root_key.objectid, &lower_key,
- level, root->node->start, 0,
+ c = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+ &lower_key, level, root->node->start, 0,
BTRFS_NESTING_NORMAL);
if (IS_ERR(c))
@@ -1522,10 +1519,9 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
mid = (c_nritems + 1) / 2;
btrfs_node_key(c, &disk_key, mid);
- split = btrfs_alloc_tree_block(trans, root, root->fs_info->nodesize,
- root->root_key.objectid,
- &disk_key, level, c->start, 0,
- BTRFS_NESTING_NORMAL);
+ split = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+ &disk_key, level, c->start, 0,
+ BTRFS_NESTING_NORMAL);
if (IS_ERR(split))
return PTR_ERR(split);
@@ -2088,10 +2084,9 @@ again:
else
btrfs_item_key(l, &disk_key, mid);
- right = btrfs_alloc_tree_block(trans, root, root->fs_info->nodesize,
- root->root_key.objectid,
- &disk_key, 0, l->start, 0,
- BTRFS_NESTING_NORMAL);
+ right = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+ &disk_key, 0, l->start, 0,
+ BTRFS_NESTING_NORMAL);
if (IS_ERR(right)) {
BUG_ON(1);
return PTR_ERR(right);
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 88a105ab..b68a8080 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -885,7 +885,7 @@ struct btrfs_block_group *btrfs_lookup_first_block_group(struct
u64 bytenr);
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- u32 blocksize, u64 root_objectid,
+ u64 parent, u64 root_objectid,
struct btrfs_disk_key *key, int level,
u64 hint, u64 empty_size,
enum btrfs_lock_nesting nest);
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index ec97ff08..bdf77d50 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2361,9 +2361,8 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
btrfs_setup_root(root, fs_info, key->objectid);
memcpy(&root->root_key, key, sizeof(struct btrfs_key));
- leaf = btrfs_alloc_tree_block(trans, root, fs_info->nodesize,
- root->root_key.objectid, NULL, 0, 0, 0,
- BTRFS_NESTING_NORMAL);
+ leaf = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+ NULL, 0, 0, 0, BTRFS_NESTING_NORMAL);
if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf);
leaf = NULL;
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 98c0b297..a9f3eba6 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -2480,7 +2480,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
}
static int alloc_tree_block(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 num_bytes,
+ struct btrfs_root *root, u64 parent,
u64 root_objectid, u64 generation,
u64 flags, struct btrfs_disk_key *key,
int level, u64 empty_size, u64 hint_byte,
@@ -2491,6 +2491,7 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_delayed_extent_op *extent_op;
struct btrfs_space_info *sinfo;
struct btrfs_fs_info *fs_info = root->fs_info;
+ u64 num_bytes = fs_info->nodesize;
bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
SKINNY_METADATA);
@@ -2537,7 +2538,7 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
sinfo->bytes_reserved += extent_size;
ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, ins->objectid,
- extent_size, 0, root_objectid,
+ extent_size, parent, root_objectid,
level, BTRFS_ADD_DELAYED_EXTENT,
extent_op, NULL, NULL);
return ret;
@@ -2549,7 +2550,7 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
*/
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- u32 blocksize, u64 root_objectid,
+ u64 parent, u64 root_objectid,
struct btrfs_disk_key *key, int level,
u64 hint, u64 empty_size,
enum btrfs_lock_nesting nest)
@@ -2558,7 +2559,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
int ret;
struct extent_buffer *buf;
- ret = alloc_tree_block(trans, root, blocksize, root_objectid,
+ ret = alloc_tree_block(trans, root, parent, root_objectid,
trans->transid, 0, key, level,
empty_size, hint, (u64)-1, &ins);
if (ret) {
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 23/26] btrfs-progs: use path->search_for_extension
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (21 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 22/26] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 24/26] btrfs-progs: add write_extent_buffer_chunk_tree_uuid helper Josef Bacik
` (3 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This flag is used by the kernel btrfs_search_slot to make sure that leaf
splitting decision doesn't subtract the size of an item. This is for
inline extent items and csum items where we know we're going to find the
item we want, and we're only going to want to extend it. Currently this
flag doesn't do anything, but when we sync ctree.c we'll stop making the
right decision WRT the leaf space, so add the flag usage in the places
we need it so we can sync ctree.c easily.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/extent-tree.c | 8 ++++++--
kernel-shared/file-item.c | 2 ++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index a9f3eba6..e29a1cb4 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -882,10 +882,12 @@ static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
key.offset = num_bytes;
want = extent_ref_type(parent, owner);
- if (insert)
+ if (insert) {
extra_size = btrfs_extent_inline_ref_size(want);
- else
+ path->search_for_extension = 1;
+ } else {
extra_size = -1;
+ }
if (owner < BTRFS_FIRST_FREE_OBJECTID && skinny_metadata) {
key.type = BTRFS_METADATA_ITEM_KEY;
@@ -1023,6 +1025,8 @@ again:
}
*ref_ret = (struct btrfs_extent_inline_ref *)ptr;
out:
+ if (insert)
+ path->search_for_extension = 0;
return err;
}
diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c
index fd6756e9..d6d01198 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -268,8 +268,10 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
* enough yet to put our csum in. Grow it
*/
btrfs_release_path(path);
+ path->search_for_extension = 1;
ret = btrfs_search_slot(trans, root, &file_key, path,
csum_size, 1);
+ path->search_for_extension = 0;
if (ret < 0)
goto fail;
if (ret == 0) {
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 24/26] btrfs-progs: add write_extent_buffer_chunk_tree_uuid helper
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (22 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 23/26] btrfs-progs: use path->search_for_extension Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 25/26] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
` (2 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This exists in the kernel to update the chunk tree uuid on the
btrfs_header. Add the helper to btrfs-progs to make future kernel sync
changes easier.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/ctree.h | 2 +-
kernel-shared/extent_io.c | 7 +++++++
kernel-shared/extent_io.h | 2 ++
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index b68a8080..376b8eca 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -731,7 +731,7 @@ static inline unsigned long btrfs_header_fsid(void)
return offsetof(struct btrfs_header, fsid);
}
-static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
+static inline unsigned long btrfs_header_chunk_tree_uuid(const struct extent_buffer *eb)
{
return offsetof(struct btrfs_header, chunk_tree_uuid);
}
diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c
index fbf45e9d..e942a7b4 100644
--- a/kernel-shared/extent_io.c
+++ b/kernel-shared/extent_io.c
@@ -659,6 +659,13 @@ void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *srcv)
write_extent_buffer(eb, srcv, btrfs_header_fsid(), BTRFS_FSID_SIZE);
}
+void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
+ const void *srcv)
+{
+ write_extent_buffer(eb, srcv, btrfs_header_chunk_tree_uuid(eb),
+ BTRFS_FSID_SIZE);
+}
+
/*
* btrfs_readahead_node_child - readahead a node's child block
* @node: parent node we're reading from
diff --git a/kernel-shared/extent_io.h b/kernel-shared/extent_io.h
index 544d5710..aa56c115 100644
--- a/kernel-shared/extent_io.h
+++ b/kernel-shared/extent_io.h
@@ -143,5 +143,7 @@ void extent_buffer_init_cache(struct btrfs_fs_info *fs_info);
void extent_buffer_free_cache(struct btrfs_fs_info *fs_info);
void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *srcv);
void btrfs_readahead_node_child(struct extent_buffer *node, int slot);
+void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
+ const void *src);
#endif
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 25/26] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (23 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 24/26] btrfs-progs: add write_extent_buffer_chunk_tree_uuid helper Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-04-29 20:19 ` [PATCH 26/26] btrfs-progs: sync ctree.c from the kernel Josef Bacik
2023-05-03 14:20 ` [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This is how the kernel initializes blocks, so anybody who uses
btrfs_alloc_tree_block in the kernel expects the blocks to be already
initialized. Put this init code into btrfs-progs so as we sync code
from the kernel we get the correct behavior.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
kernel-shared/extent-tree.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index e29a1cb4..6da30011 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -2559,6 +2559,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
u64 hint, u64 empty_size,
enum btrfs_lock_nesting nest)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_key ins;
int ret;
struct extent_buffer *buf;
@@ -2579,6 +2580,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
return ERR_PTR(-ENOMEM);
}
btrfs_set_buffer_uptodate(buf);
+ memset_extent_buffer(buf, 0, 0, sizeof(struct btrfs_header));
+ btrfs_set_header_level(buf, level);
+ btrfs_set_header_bytenr(buf, buf->start);
+ btrfs_set_header_generation(buf, trans->transid);
+ btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV);
+ btrfs_set_header_owner(buf, root_objectid);
+ write_extent_buffer_fsid(buf, fs_info->fs_devices->metadata_uuid);
+ write_extent_buffer_chunk_tree_uuid(buf, fs_info->chunk_tree_uuid);
trans->blocks_used++;
return buf;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 26/26] btrfs-progs: sync ctree.c from the kernel
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (24 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 25/26] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
@ 2023-04-29 20:19 ` Josef Bacik
2023-05-03 14:20 ` [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
26 siblings, 0 replies; 28+ messages in thread
From: Josef Bacik @ 2023-04-29 20:19 UTC (permalink / raw)
To: linux-btrfs, kernel-team
This patch sync's ctree.c from the kernel. This is mostly painless,
there were a few modifications that were necessary
- There is no btrfs_transaction in btrfs-progs currently, those
references had to be commented out.
- The path kmem cache has to be init'ed on open ctree, so there was
some weirdness to get that to work properly.
- Some references to page_address that had to be removed in the
btrfs_bin_search function that are optimizations for the kernel.
- We have a struct that we pass around for block validation in the
kernel that we don't have here, so removed that stuff.
These sites are all marked, otherwise it's a straight copy. There were
some changes outside of ctree.c that couldn't be done as a preparation
as it came with the behavior changes in the newer ctree.c. This are
easy to spot as they're outside of ctree.c and straightforward.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
include/kerncompat.h | 80 +
kernel-lib/trace.h | 8 +
kernel-shared/ctree.c | 4474 ++++++++++++++++++++++++++---------
kernel-shared/ctree.h | 95 +-
kernel-shared/disk-io.c | 5 +
kernel-shared/locking.c | 6 +-
kernel-shared/transaction.c | 5 +-
7 files changed, 3477 insertions(+), 1196 deletions(-)
diff --git a/include/kerncompat.h b/include/kerncompat.h
index 7472ff75..3bda16d2 100644
--- a/include/kerncompat.h
+++ b/include/kerncompat.h
@@ -202,6 +202,10 @@ typedef struct spinlock_struct {
unsigned long lock;
} spinlock_t;
+struct rw_semaphore {
+ long lock;
+};
+
#define mutex_init(m) \
do { \
(m)->lock = 1; \
@@ -244,6 +248,27 @@ static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
spin_unlock(lock);
}
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+ sem->lock = 0;
+}
+
+static inline bool down_read_trylock(struct rw_semaphore *sem)
+{
+ sem->lock++;
+ return true;
+}
+
+static inline void down_read(struct rw_semaphore *sem)
+{
+ sem->lock++;
+}
+
+static inline void up_read(struct rw_semaphore *sem)
+{
+ sem->lock--;
+}
+
#define cond_resched() do { } while (0)
#define preempt_enable() do { } while (0)
#define preempt_disable() do { } while (0)
@@ -400,6 +425,11 @@ static inline void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t mask)
return malloc(cache->size);
}
+static inline void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t mask)
+{
+ return calloc(1, cache->size);
+}
+
static inline void kmem_cache_free(struct kmem_cache *cache, void *ptr)
{
free(ptr);
@@ -704,6 +734,10 @@ static inline bool sb_rdonly(struct super_block *sb)
#define unlikely(cond) (cond)
+#define rcu_dereference(c) (c)
+
+#define rcu_assign_pointer(p, v) do { (p) = (v); } while (0)
+
static inline void atomic_set(atomic_t *a, int val)
{
*a = val;
@@ -724,6 +758,15 @@ static inline void atomic_dec(atomic_t *a)
(*a)--;
}
+static inline bool atomic_inc_not_zero(atomic_t *a)
+{
+ if (*a) {
+ atomic_inc(a);
+ return true;
+ }
+ return false;
+}
+
static inline struct workqueue_struct *alloc_workqueue(const char *name,
unsigned long flags,
int max_active, ...)
@@ -766,6 +809,10 @@ static inline void lockdep_set_class(spinlock_t *lock, struct lock_class_key *lc
{
}
+static inline void lockdep_assert_held_read(struct rw_semaphore *sem)
+{
+}
+
static inline bool cond_resched_lock(spinlock_t *lock)
{
return false;
@@ -800,11 +847,30 @@ static inline void schedule(void)
{
}
+static inline void might_sleep(void)
+{
+}
+
+static inline void rcu_read_lock(void)
+{
+}
+
+static inline void rcu_read_unlock(void)
+{
+}
+
+static inline void synchronize_rcu(void)
+{
+}
+
/*
* Temporary definitions while syncing.
*/
struct btrfs_inode;
struct extent_state;
+struct extent_buffer;
+struct btrfs_root;
+struct btrfs_trans_handle;
static inline void btrfs_merge_delalloc_extent(struct btrfs_inode *inode,
struct extent_state *state,
@@ -830,4 +896,18 @@ static inline void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
{
}
+static inline int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *buf,
+ struct extent_buffer *cow)
+{
+ return 0;
+}
+
+static inline void btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *buf)
+{
+}
+
#endif
diff --git a/kernel-lib/trace.h b/kernel-lib/trace.h
index 99bee344..10fc589d 100644
--- a/kernel-lib/trace.h
+++ b/kernel-lib/trace.h
@@ -1,6 +1,8 @@
#ifndef __PROGS_TRACE_H__
#define __PROGS_TRACE_H__
+struct btrfs_work;
+
static inline void trace_btrfs_workqueue_alloc(void *ret, const char *name)
{
}
@@ -52,4 +54,10 @@ static inline void trace_btrfs_convert_extent_bit(struct extent_io_tree *tree,
{
}
+static inline void trace_btrfs_cow_block(struct btrfs_root *root,
+ struct extent_buffer *buf,
+ struct extent_buffer *cow)
+{
+}
+
#endif /* __PROGS_TRACE_H__ */
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 2728452f..1405dde6 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1,155 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2007 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
+ * Copyright (C) 2007,2008 Oracle. All rights reserved.
*/
-#include "kernel-shared/ctree.h"
-#include "kernel-shared/disk-io.h"
-#include "kernel-shared/transaction.h"
-#include "kernel-shared/print-tree.h"
+#include "include/kerncompat.h"
#include "kernel-lib/bitops.h"
-#include "crypto/crc32c.h"
-#include "common/internal.h"
-#include "common/messages.h"
-#include "common/utils.h"
-#include "kernel-lib/sizes.h"
-#include "kernel-shared/volumes.h"
-#include "check/repair.h"
+#include "messages.h"
+#include "ctree.h"
+#include "disk-io.h"
+#include "transaction.h"
+#include "print-tree.h"
+#include "locking.h"
+#include "volumes.h"
+#include "tree-mod-log.h"
#include "tree-checker.h"
+#include "accessors.h"
+#include "file-item.h"
+#include "kernel-lib/trace.h"
+
+/*
+ * MODIFIED:
+ * - This has to be init'ed to NULL so we know to create it on usage.
+ */
+static struct kmem_cache *btrfs_path_cachep = NULL;
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
-static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, const struct btrfs_key *ins_key,
- struct btrfs_path *path, int data_size, int extend);
+static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ const struct btrfs_key *ins_key, struct btrfs_path *path,
+ int data_size, int extend);
static int push_node_left(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct extent_buffer *dst,
+ struct extent_buffer *dst,
struct extent_buffer *src, int empty);
static int balance_node_right(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
struct extent_buffer *dst_buf,
struct extent_buffer *src_buf);
-static const struct btrfs_csum {
- u16 size;
- const char name[14];
+static const struct btrfs_csums {
+ u16 size;
+ const char name[10];
+ const char driver[12];
} btrfs_csums[] = {
- [BTRFS_CSUM_TYPE_CRC32] = { 4, "crc32c" },
- [BTRFS_CSUM_TYPE_XXHASH] = { 8, "xxhash64" },
- [BTRFS_CSUM_TYPE_SHA256] = { 32, "sha256" },
- [BTRFS_CSUM_TYPE_BLAKE2] = { 32, "blake2" },
+ [BTRFS_CSUM_TYPE_CRC32] = { .size = 4, .name = "crc32c" },
+ [BTRFS_CSUM_TYPE_XXHASH] = { .size = 8, .name = "xxhash64" },
+ [BTRFS_CSUM_TYPE_SHA256] = { .size = 32, .name = "sha256" },
+ [BTRFS_CSUM_TYPE_BLAKE2] = { .size = 32, .name = "blake2b",
+ .driver = "blake2b-256" },
};
-u16 btrfs_super_csum_size(const struct btrfs_super_block *sb)
+/*
+ * The leaf data grows from end-to-front in the node. this returns the address
+ * of the start of the last item, which is the stop of the leaf data stack.
+ */
+static unsigned int leaf_data_end(const struct extent_buffer *leaf)
{
- const u16 csum_type = btrfs_super_csum_type(sb);
+ u32 nr = btrfs_header_nritems(leaf);
- return btrfs_csums[csum_type].size;
+ if (nr == 0)
+ return BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
+ return btrfs_item_offset(leaf, nr - 1);
+}
+
+/*
+ * Move data in a @leaf (using memmove, safe for overlapping ranges).
+ *
+ * @leaf: leaf that we're doing a memmove on
+ * @dst_offset: item data offset we're moving to
+ * @src_offset: item data offset were' moving from
+ * @len: length of the data we're moving
+ *
+ * Wrapper around memmove_extent_buffer() that takes into account the header on
+ * the leaf. The btrfs_item offset's start directly after the header, so we
+ * have to adjust any offsets to account for the header in the leaf. This
+ * handles that math to simplify the callers.
+ */
+static inline void memmove_leaf_data(const struct extent_buffer *leaf,
+ unsigned long dst_offset,
+ unsigned long src_offset,
+ unsigned long len)
+{
+ memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) + dst_offset,
+ btrfs_item_nr_offset(leaf, 0) + src_offset, len);
+}
+
+/*
+ * Copy item data from @src into @dst at the given @offset.
+ *
+ * @dst: destination leaf that we're copying into
+ * @src: source leaf that we're copying from
+ * @dst_offset: item data offset we're copying to
+ * @src_offset: item data offset were' copying from
+ * @len: length of the data we're copying
+ *
+ * Wrapper around copy_extent_buffer() that takes into account the header on
+ * the leaf. The btrfs_item offset's start directly after the header, so we
+ * have to adjust any offsets to account for the header in the leaf. This
+ * handles that math to simplify the callers.
+ */
+static inline void copy_leaf_data(const struct extent_buffer *dst,
+ const struct extent_buffer *src,
+ unsigned long dst_offset,
+ unsigned long src_offset, unsigned long len)
+{
+ copy_extent_buffer(dst, src, btrfs_item_nr_offset(dst, 0) + dst_offset,
+ btrfs_item_nr_offset(src, 0) + src_offset, len);
+}
+
+/*
+ * Move items in a @leaf (using memmove).
+ *
+ * @dst: destination leaf for the items
+ * @dst_item: the item nr we're copying into
+ * @src_item: the item nr we're copying from
+ * @nr_items: the number of items to copy
+ *
+ * Wrapper around memmove_extent_buffer() that does the math to get the
+ * appropriate offsets into the leaf from the item numbers.
+ */
+static inline void memmove_leaf_items(const struct extent_buffer *leaf,
+ int dst_item, int src_item, int nr_items)
+{
+ memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, dst_item),
+ btrfs_item_nr_offset(leaf, src_item),
+ nr_items * sizeof(struct btrfs_item));
+}
+
+/*
+ * Copy items from @src into @dst at the given @offset.
+ *
+ * @dst: destination leaf for the items
+ * @src: source leaf for the items
+ * @dst_item: the item nr we're copying into
+ * @src_item: the item nr we're copying from
+ * @nr_items: the number of items to copy
+ *
+ * Wrapper around copy_extent_buffer() that does the math to get the
+ * appropriate offsets into the leaf from the item numbers.
+ */
+static inline void copy_leaf_items(const struct extent_buffer *dst,
+ const struct extent_buffer *src,
+ int dst_item, int src_item, int nr_items)
+{
+ copy_extent_buffer(dst, src, btrfs_item_nr_offset(dst, dst_item),
+ btrfs_item_nr_offset(src, src_item),
+ nr_items * sizeof(struct btrfs_item));
+}
+
+/* This exists for btrfs-progs usages. */
+u16 btrfs_csum_type_size(u16 type)
+{
+ return btrfs_csums[type].size;
+}
+
+int btrfs_super_csum_size(const struct btrfs_super_block *s)
+{
+ u16 t = btrfs_super_csum_type(s);
+ /*
+ * csum type is validated at mount time
+ */
+ return btrfs_csum_type_size(t);
}
const char *btrfs_super_csum_name(u16 csum_type)
{
+ /* csum type is validated at mount time */
return btrfs_csums[csum_type].name;
}
-u16 btrfs_csum_type_size(u16 csum_type)
-{
- return btrfs_csums[csum_type].size;
-}
-
-u64 btrfs_name_hash(const char *name, int len)
-{
- return crc32c((u32)~1, name, len);
-}
-
/*
- * Figure the key offset of an extended inode ref
+ * Return driver name if defined, otherwise the name that's also a valid driver
+ * name
*/
-u64 btrfs_extref_hash(u64 parent_objectid, const char *name, int len)
+const char *btrfs_super_csum_driver(u16 csum_type)
{
- return (u64)crc32c(parent_objectid, name, len);
+ /* csum type is validated at mount time */
+ return btrfs_csums[csum_type].driver[0] ?
+ btrfs_csums[csum_type].driver :
+ btrfs_csums[csum_type].name;
+}
+
+size_t __attribute_const__ btrfs_get_num_csums(void)
+{
+ return ARRAY_SIZE(btrfs_csums);
}
struct btrfs_path *btrfs_alloc_path(void)
{
- struct btrfs_path *path;
- path = kzalloc(sizeof(struct btrfs_path), GFP_NOFS);
- return path;
+ might_sleep();
+
+ return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
}
+/* this also releases the path */
void btrfs_free_path(struct btrfs_path *p)
{
if (!p)
return;
btrfs_release_path(p);
- kfree(p);
+ kmem_cache_free(btrfs_path_cachep, p);
}
-void btrfs_release_path(struct btrfs_path *p)
+/*
+ * path release drops references on the extent buffers in the path
+ * and it drops any locks held by this path
+ *
+ * It is safe to call this on paths that no locks or extent buffers held.
+ */
+noinline void btrfs_release_path(struct btrfs_path *p)
{
int i;
+
for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
+ p->slots[i] = 0;
if (!p->nodes[i])
continue;
+ if (p->locks[i]) {
+ btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]);
+ p->locks[i] = 0;
+ }
free_extent_buffer(p->nodes[i]);
+ p->nodes[i] = NULL;
}
- memset(p, 0, sizeof(*p));
}
+/*
+ * We want the transaction abort to print stack trace only for errors where the
+ * cause could be a bug, eg. due to ENOSPC, and not for common errors that are
+ * caused by external factors.
+ */
+bool __cold abort_should_print_stack(int errno)
+{
+ switch (errno) {
+ case -EIO:
+ case -EROFS:
+ case -ENOMEM:
+ return false;
+ }
+ return true;
+}
+
+/*
+ * safely gets a reference on the root node of a tree. A lock
+ * is not taken, so a concurrent writer may put a different node
+ * at the root of the tree. See btrfs_lock_root_node for the
+ * looping required.
+ *
+ * The extent buffer returned by this has a reference taken, so
+ * it won't disappear. It may stop being the root of the tree
+ * at any time because there are no locks held.
+ */
+struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
+{
+ struct extent_buffer *eb;
+
+ while (1) {
+ rcu_read_lock();
+ eb = rcu_dereference(root->node);
+
+ /*
+ * RCU really hurts here, we could free up the root node because
+ * it was COWed but we may not get the new root node yet so do
+ * the inc_not_zero dance and if it doesn't work then
+ * synchronize_rcu and try again.
+ */
+ if (atomic_inc_not_zero(&eb->refs)) {
+ rcu_read_unlock();
+ break;
+ }
+ rcu_read_unlock();
+ synchronize_rcu();
+ }
+ return eb;
+}
+
+/*
+ * Cowonly root (not-shareable trees, everything not subvolume or reloc roots),
+ * just get put onto a simple dirty list. Transaction walks this list to make
+ * sure they get properly updated on disk.
+ */
static void add_root_to_dirty_list(struct btrfs_root *root)
{
- if (test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state) &&
- list_empty(&root->dirty_list)) {
- list_add(&root->dirty_list,
- &root->fs_info->dirty_cowonly_roots);
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ if (test_bit(BTRFS_ROOT_DIRTY, &root->state) ||
+ !test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state))
+ return;
+
+ spin_lock(&fs_info->trans_lock);
+ if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) {
+ /* Want the extent tree to be the last on the list */
+ if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID)
+ list_move_tail(&root->dirty_list,
+ &fs_info->dirty_cowonly_roots);
+ else
+ list_move(&root->dirty_list,
+ &fs_info->dirty_cowonly_roots);
}
+ spin_unlock(&fs_info->trans_lock);
}
-static void root_add_used(struct btrfs_root *root, u32 size)
-{
- btrfs_set_root_used(&root->root_item,
- btrfs_root_used(&root->root_item) + size);
-}
-
-static void root_sub_used(struct btrfs_root *root, u32 size)
-{
- btrfs_set_root_used(&root->root_item,
- btrfs_root_used(&root->root_item) - size);
-}
-
+/*
+ * used by snapshot creation to make a copy of a root for a tree with
+ * a given objectid. The buffer with the new root node is returned in
+ * cow_ret, and this func returns zero on success or a negative error code.
+ */
int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
struct extent_buffer **cow_ret, u64 new_root_objectid)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *cow;
int ret = 0;
int level;
- struct btrfs_root *new_root;
struct btrfs_disk_key disk_key;
- new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
- if (!new_root)
- return -ENOMEM;
-
- memcpy(new_root, root, sizeof(*new_root));
- new_root->root_key.objectid = new_root_objectid;
-
WARN_ON(test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
- trans->transid != root->fs_info->running_transaction->transid);
+ trans->transid != fs_info->running_transaction->transid);
WARN_ON(test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
trans->transid != root->last_trans);
@@ -158,15 +325,14 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_item_key(buf, &disk_key, 0);
else
btrfs_node_key(buf, &disk_key, 0);
- cow = btrfs_alloc_tree_block(trans, new_root, 0, new_root_objectid,
- &disk_key, level, buf->start, 0,
- BTRFS_NESTING_NORMAL);
- if (IS_ERR(cow)) {
- kfree(new_root);
- return PTR_ERR(cow);
- }
- copy_extent_buffer(cow, buf, 0, 0, cow->len);
+ cow = btrfs_alloc_tree_block(trans, root, 0, new_root_objectid,
+ &disk_key, level, buf->start, 0,
+ BTRFS_NESTING_NEW_ROOT);
+ if (IS_ERR(cow))
+ return PTR_ERR(cow);
+
+ copy_extent_buffer_full(cow, buf);
btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
@@ -177,15 +343,19 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, new_root_objectid);
- write_extent_buffer(cow, root->fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ write_extent_buffer_fsid(cow, fs_info->fs_devices->metadata_uuid);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
- ret = btrfs_inc_ref(trans, new_root, cow, 0);
- kfree(new_root);
-
- if (ret)
+ if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
+ ret = btrfs_inc_ref(trans, root, cow, 1);
+ else
+ ret = btrfs_inc_ref(trans, root, cow, 0);
+ if (ret) {
+ btrfs_tree_unlock(cow);
+ free_extent_buffer(cow);
+ btrfs_abort_transaction(trans, ret);
return ret;
+ }
btrfs_mark_buffer_dirty(cow);
*cow_ret = cow;
@@ -195,14 +365,13 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
/*
* check if the tree block can be shared by multiple trees
*/
-static int btrfs_block_can_be_shared(struct btrfs_root *root,
- struct extent_buffer *buf)
+int btrfs_block_can_be_shared(struct btrfs_root *root,
+ struct extent_buffer *buf)
{
/*
- * Tree blocks not in reference counted trees and tree roots
- * are never shared. If a block was allocated after the last
- * snapshot and the block was not allocated by tree relocation,
- * we know the block is not shared.
+ * Tree blocks not in shareable trees and tree roots are never shared.
+ * If a block was allocated after the last snapshot and the block was
+ * not allocated by tree relocation, we know the block is not shared.
*/
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
buf != root->node && buf != root->commit_root &&
@@ -210,14 +379,17 @@ static int btrfs_block_can_be_shared(struct btrfs_root *root,
btrfs_root_last_snapshot(&root->root_item) ||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
return 1;
+
return 0;
}
static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
- struct extent_buffer *cow)
+ struct extent_buffer *cow,
+ int *last_ref)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
u64 refs;
u64 owner;
u64 flags;
@@ -242,12 +414,16 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
*/
if (btrfs_block_can_be_shared(root, buf)) {
- ret = btrfs_lookup_extent_info(trans, trans->fs_info,
- buf->start,
+ ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
btrfs_header_level(buf), 1,
&refs, &flags);
- BUG_ON(ret);
- BUG_ON(refs == 0);
+ if (ret)
+ return ret;
+ if (refs == 0) {
+ ret = -EROFS;
+ btrfs_handle_fs_error(fs_info, ret, NULL);
+ return ret;
+ }
} else {
refs = 1;
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
@@ -258,22 +434,25 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
}
owner = btrfs_header_owner(buf);
- BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) &&
- owner == BTRFS_TREE_RELOC_OBJECTID);
+ BUG_ON(owner == BTRFS_TREE_RELOC_OBJECTID &&
+ !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
if (refs > 1) {
if ((owner == root->root_key.objectid ||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
ret = btrfs_inc_ref(trans, root, buf, 1);
- BUG_ON(ret);
+ if (ret)
+ return ret;
if (root->root_key.objectid ==
BTRFS_TREE_RELOC_OBJECTID) {
ret = btrfs_dec_ref(trans, root, buf, 0);
- BUG_ON(ret);
+ if (ret)
+ return ret;
ret = btrfs_inc_ref(trans, root, cow, 1);
- BUG_ON(ret);
+ if (ret)
+ return ret;
}
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
} else {
@@ -283,11 +462,13 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_inc_ref(trans, root, cow, 1);
else
ret = btrfs_inc_ref(trans, root, cow, 0);
- BUG_ON(ret);
+ if (ret)
+ return ret;
}
if (new_flags != 0) {
ret = btrfs_set_disk_extent_flags(trans, buf, new_flags);
- BUG_ON(ret);
+ if (ret)
+ return ret;
}
} else {
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
@@ -296,28 +477,53 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_inc_ref(trans, root, cow, 1);
else
ret = btrfs_inc_ref(trans, root, cow, 0);
- BUG_ON(ret);
+ if (ret)
+ return ret;
ret = btrfs_dec_ref(trans, root, buf, 1);
- BUG_ON(ret);
+ if (ret)
+ return ret;
}
btrfs_clear_buffer_dirty(trans, buf);
+ *last_ref = 1;
}
return 0;
}
-static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
+/*
+ * does the dirty work in cow of a single block. The parent block (if
+ * supplied) is updated to point to the new cow copy. The new buffer is marked
+ * dirty and returned locked. If you modify the block it needs to be marked
+ * dirty again.
+ *
+ * search_start -- an allocation hint for the new block
+ *
+ * empty_size -- a hint that you plan on doing more cow. This is the size in
+ * bytes the allocator should try to find free next to the block it returns.
+ * This is just a hint and may be ignored by the allocator.
+ */
+static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
struct extent_buffer **cow_ret,
- u64 search_start, u64 empty_size)
+ u64 search_start, u64 empty_size,
+ enum btrfs_lock_nesting nest)
{
- struct extent_buffer *cow;
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_disk_key disk_key;
- int level;
+ struct extent_buffer *cow;
+ int level, ret;
+ int last_ref = 0;
+ int unlock_orig = 0;
+ u64 parent_start = 0;
+
+ if (*cow_ret == buf)
+ unlock_orig = 1;
+
+ btrfs_assert_tree_write_locked(buf);
WARN_ON(test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
- trans->transid != root->fs_info->running_transaction->transid);
+ trans->transid != fs_info->running_transaction->transid);
WARN_ON(test_bit(BTRFS_ROOT_SHAREABLE, &root->state) &&
trans->transid != root->last_trans);
@@ -328,13 +534,18 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else
btrfs_node_key(buf, &disk_key, 0);
- cow = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
- &disk_key, level, search_start, empty_size,
- BTRFS_NESTING_NORMAL);
+ if ((root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && parent)
+ parent_start = parent->start;
+
+ cow = btrfs_alloc_tree_block(trans, root, parent_start,
+ root->root_key.objectid, &disk_key, level,
+ search_start, empty_size, nest);
if (IS_ERR(cow))
return PTR_ERR(cow);
- copy_extent_buffer(cow, buf, 0, 0, cow->len);
+ /* cow is set to blocking by btrfs_init_new_buffer */
+
+ copy_extent_buffer_full(cow, buf);
btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
@@ -345,39 +556,65 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, root->root_key.objectid);
- write_extent_buffer(cow, root->fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ write_extent_buffer_fsid(cow, fs_info->fs_devices->metadata_uuid);
- WARN_ON(!(buf->flags & EXTENT_BUFFER_BAD_TRANSID) &&
- btrfs_header_generation(buf) > trans->transid);
+ ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
+ if (ret) {
+ btrfs_tree_unlock(cow);
+ free_extent_buffer(cow);
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
- update_ref_for_cow(trans, root, buf, cow);
+ if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) {
+ ret = btrfs_reloc_cow_block(trans, root, buf, cow);
+ if (ret) {
+ btrfs_tree_unlock(cow);
+ free_extent_buffer(cow);
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ }
if (buf == root->node) {
- root->node = cow;
- extent_buffer_get(cow);
+ WARN_ON(parent && parent != buf);
+ if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
+ btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
+ parent_start = buf->start;
- btrfs_free_extent(trans, buf->start, buf->len, 0,
- root->root_key.objectid, level, 0);
+ atomic_inc(&cow->refs);
+ ret = btrfs_tree_mod_log_insert_root(root->node, cow, true);
+ BUG_ON(ret < 0);
+ rcu_assign_pointer(root->node, cow);
+
+ btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+ parent_start, last_ref);
free_extent_buffer(buf);
add_root_to_dirty_list(root);
} else {
+ WARN_ON(trans->transid != btrfs_header_generation(parent));
+ btrfs_tree_mod_log_insert_key(parent, parent_slot,
+ BTRFS_MOD_LOG_KEY_REPLACE);
btrfs_set_node_blockptr(parent, parent_slot,
cow->start);
- WARN_ON(trans->transid == 0);
btrfs_set_node_ptr_generation(parent, parent_slot,
trans->transid);
btrfs_mark_buffer_dirty(parent);
- WARN_ON(btrfs_header_generation(parent) != trans->transid);
-
- btrfs_free_extent(trans, buf->start, buf->len, 0,
- root->root_key.objectid, level, 0);
+ if (last_ref) {
+ ret = btrfs_tree_mod_log_free_eb(buf);
+ if (ret) {
+ btrfs_tree_unlock(cow);
+ free_extent_buffer(cow);
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ }
+ btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+ parent_start, last_ref);
}
- if (!list_empty(&buf->recow)) {
- list_del_init(&buf->recow);
- free_extent_buffer(buf);
- }
- free_extent_buffer(buf);
+ if (unlock_orig)
+ btrfs_tree_unlock(buf);
+ free_extent_buffer_stale(buf);
btrfs_mark_buffer_dirty(cow);
*cow_ret = cow;
return 0;
@@ -387,46 +624,137 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf)
{
+ if (btrfs_is_testing(root->fs_info))
+ return 0;
+
+ /* Ensure we can see the FORCE_COW bit */
+ smp_mb__before_atomic();
+
+ /*
+ * We do not need to cow a block if
+ * 1) this block is not created or changed in this transaction;
+ * 2) this block does not belong to TREE_RELOC tree;
+ * 3) the root is not forced COW.
+ *
+ * What is forced COW:
+ * when we create snapshot during committing the transaction,
+ * after we've finished copying src root, we must COW the shared
+ * block to ensure the metadata consistency.
+ */
if (btrfs_header_generation(buf) == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
- btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
+ btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
+ !test_bit(BTRFS_ROOT_FORCE_COW, &root->state))
return 0;
return 1;
}
-int btrfs_cow_block(struct btrfs_trans_handle *trans,
+/*
+ * cows a single block, see __btrfs_cow_block for the real work.
+ * This version of it has extra checks so that a block isn't COWed more than
+ * once per transaction, as long as it hasn't been written yet
+ */
+noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
- struct extent_buffer **cow_ret)
+ struct extent_buffer **cow_ret,
+ enum btrfs_lock_nesting nest)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
u64 search_start;
int ret;
+
+ if (test_bit(BTRFS_ROOT_DELETING, &root->state))
+ btrfs_err(fs_info,
+ "COW'ing blocks on a fs root that's being dropped");
+
/*
- if (trans->transaction != root->fs_info->running_transaction) {
- printk(KERN_CRIT "trans %llu running %llu\n", trans->transid,
- root->fs_info->running_transaction->transid);
- WARN_ON(1);
- }
+ * MODIFIED:
+ * - In the kernel we have a transaction and a trans_handle, here we
+ * only have a trans_handle, so just don't worry about this right
+ * now.
+ *
+ if (trans->transaction != fs_info->running_transaction)
+ WARN(1, KERN_CRIT "trans %llu running %llu\n",
+ trans->transid,
+ fs_info->running_transaction->transid);
*/
- if (trans->transid != root->fs_info->generation) {
- printk(KERN_CRIT "trans %llu running %llu\n",
- (unsigned long long)trans->transid,
- (unsigned long long)root->fs_info->generation);
- WARN_ON(1);
- }
+
+ if (trans->transid != fs_info->generation)
+ WARN(1, KERN_CRIT "trans %llu running %llu\n",
+ trans->transid, fs_info->generation);
+
if (!should_cow_block(trans, root, buf)) {
*cow_ret = buf;
return 0;
}
search_start = buf->start & ~((u64)SZ_1G - 1);
+
+ /*
+ * Before CoWing this block for later modification, check if it's
+ * the subtree root and do the delayed subtree trace if needed.
+ *
+ * Also We don't care about the error, as it's handled internally.
+ */
+ btrfs_qgroup_trace_subtree_after_cow(trans, root, buf);
ret = __btrfs_cow_block(trans, root, buf, parent,
- parent_slot, cow_ret, search_start, 0);
+ parent_slot, cow_ret, search_start, 0, nest);
+
+ trace_btrfs_cow_block(root, buf, *cow_ret);
+
return ret;
}
+ALLOW_ERROR_INJECTION(btrfs_cow_block, ERRNO);
-int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2)
+/*
+ * helper function for defrag to decide if two blocks pointed to by a
+ * node are actually close by
+ */
+static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
+{
+ if (blocknr < other && other - (blocknr + blocksize) < 32768)
+ return 1;
+ if (blocknr > other && blocknr - (other + blocksize) < 32768)
+ return 1;
+ return 0;
+}
+
+#ifdef __LITTLE_ENDIAN
+
+/*
+ * Compare two keys, on little-endian the disk order is same as CPU order and
+ * we can avoid the conversion.
+ */
+static int comp_keys(const struct btrfs_disk_key *disk_key,
+ const struct btrfs_key *k2)
+{
+ const struct btrfs_key *k1 = (const struct btrfs_key *)disk_key;
+
+ return btrfs_comp_cpu_keys(k1, k2);
+}
+
+#else
+
+/*
+ * compare two keys in a memcmp fashion
+ */
+static int comp_keys(const struct btrfs_disk_key *disk,
+ const struct btrfs_key *k2)
+{
+ struct btrfs_key k1;
+
+ btrfs_disk_key_to_cpu(&k1, disk);
+
+ return btrfs_comp_cpu_keys(&k1, k2);
+}
+#endif
+
+/*
+ * same as comp_keys only with two btrfs_key's
+ */
+int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2)
{
if (k1->objectid > k2->objectid)
return 1;
@@ -444,73 +772,157 @@ int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2)
}
/*
- * compare two keys in a memcmp fashion
+ * this is used by the defrag code to go through all the
+ * leaves pointed to by a node and reallocate them so that
+ * disk order is close to key order
*/
-static int btrfs_comp_keys(struct btrfs_disk_key *disk,
- const struct btrfs_key *k2)
+int btrfs_realloc_node(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct extent_buffer *parent,
+ int start_slot, u64 *last_ret,
+ struct btrfs_key *progress)
{
- struct btrfs_key k1;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct extent_buffer *cur;
+ u64 blocknr;
+ u64 search_start = *last_ret;
+ u64 last_block = 0;
+ u64 other;
+ u32 parent_nritems;
+ int end_slot;
+ int i;
+ int err = 0;
+ u32 blocksize;
+ int progress_passed = 0;
+ struct btrfs_disk_key disk_key;
- btrfs_disk_key_to_cpu(&k1, disk);
- return btrfs_comp_cpu_keys(&k1, k2);
+ /*
+ * MODIFIED:
+ * - We don't have struct btrfs_transaction in btrfs-progs yet.
+ *
+ WARN_ON(trans->transaction != fs_info->running_transaction);
+ */
+
+ WARN_ON(trans->transid != fs_info->generation);
+
+ parent_nritems = btrfs_header_nritems(parent);
+ blocksize = fs_info->nodesize;
+ end_slot = parent_nritems - 1;
+
+ if (parent_nritems <= 1)
+ return 0;
+
+ for (i = start_slot; i <= end_slot; i++) {
+ int close = 1;
+
+ btrfs_node_key(parent, &disk_key, i);
+ if (!progress_passed && comp_keys(&disk_key, progress) < 0)
+ continue;
+
+ progress_passed = 1;
+ blocknr = btrfs_node_blockptr(parent, i);
+ if (last_block == 0)
+ last_block = blocknr;
+
+ if (i > 0) {
+ other = btrfs_node_blockptr(parent, i - 1);
+ close = close_blocks(blocknr, other, blocksize);
+ }
+ if (!close && i < end_slot) {
+ other = btrfs_node_blockptr(parent, i + 1);
+ close = close_blocks(blocknr, other, blocksize);
+ }
+ if (close) {
+ last_block = blocknr;
+ continue;
+ }
+
+ cur = btrfs_read_node_slot(parent, i);
+ if (IS_ERR(cur))
+ return PTR_ERR(cur);
+ if (search_start == 0)
+ search_start = last_block;
+
+ btrfs_tree_lock(cur);
+ err = __btrfs_cow_block(trans, root, cur, parent, i,
+ &cur, search_start,
+ min(16 * blocksize,
+ (end_slot - i) * blocksize),
+ BTRFS_NESTING_COW);
+ if (err) {
+ btrfs_tree_unlock(cur);
+ free_extent_buffer(cur);
+ break;
+ }
+ search_start = cur->start;
+ last_block = cur->start;
+ *last_ret = search_start;
+ btrfs_tree_unlock(cur);
+ free_extent_buffer(cur);
+ }
+ return err;
}
/*
- * The leaf data grows from end-to-front in the node.
- * this returns the address of the start of the last item,
- * which is the stop of the leaf data stack
- */
-static inline unsigned int leaf_data_end(const struct extent_buffer *leaf)
-{
- u32 nr = btrfs_header_nritems(leaf);
- if (nr == 0)
- return BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
- return btrfs_item_offset(leaf, nr - 1);
-}
-
-static int noinline check_block(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path, int level)
-{
- enum btrfs_tree_block_status ret;
-
- if (path->skip_check_block)
- return 0;
- if (level == 0)
- ret = __btrfs_check_leaf(path->nodes[0]);
- else
- ret = __btrfs_check_node(path->nodes[level]);
- if (ret == BTRFS_TREE_BLOCK_CLEAN)
- return 0;
- return -EIO;
-}
-
-/*
- * search for key in the extent_buffer. The items start at offset p,
- * and they are item_size apart. There are 'max' items in p.
+ * Search for a key in the given extent_buffer.
*
- * the slot in the array is returned via slot, and it points to
- * the place where you would insert key if it is not found in
- * the array.
+ * The lower boundary for the search is specified by the slot number @first_slot.
+ * Use a value of 0 to search over the whole extent buffer. Works for both
+ * leaves and nodes.
*
- * slot may point to max if the key is bigger than all of the keys
+ * The slot in the extent buffer is returned via @slot. If the key exists in the
+ * extent buffer, then @slot will point to the slot where the key is, otherwise
+ * it points to the slot where you would insert the key.
+ *
+ * Slot may point to the total number of items (i.e. one position beyond the last
+ * key) if the key is bigger than the last key in the extent buffer.
*/
-static int generic_bin_search(struct extent_buffer *eb, unsigned long p,
- int item_size, const struct btrfs_key *key,
- int max, int *slot)
+int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
+ const struct btrfs_key *key, int *slot)
{
- int low = 0;
- int high = max;
- int mid;
+ unsigned long p;
+ int item_size;
+ /*
+ * Use unsigned types for the low and high slots, so that we get a more
+ * efficient division in the search loop below.
+ */
+ u32 low = first_slot;
+ u32 high = btrfs_header_nritems(eb);
int ret;
- unsigned long offset;
- struct btrfs_disk_key *tmp;
+ const int key_size = sizeof(struct btrfs_disk_key);
+
+ if (unlikely(low > high)) {
+ btrfs_err(eb->fs_info,
+ "%s: low (%u) > high (%u) eb %llu owner %llu level %d",
+ __func__, low, high, eb->start,
+ btrfs_header_owner(eb), btrfs_header_level(eb));
+ return -EINVAL;
+ }
+
+ if (btrfs_header_level(eb) == 0) {
+ p = offsetof(struct btrfs_leaf, items);
+ item_size = sizeof(struct btrfs_item);
+ } else {
+ p = offsetof(struct btrfs_node, ptrs);
+ item_size = sizeof(struct btrfs_key_ptr);
+ }
+
+ /*
+ * MODIFIED:
+ * - Removed the oip + key_size <= PAGE_SIZE optimization.
+ */
+ while (low < high) {
+ unsigned long offset;
+ struct btrfs_disk_key *tmp;
+ struct btrfs_disk_key unaligned;
+ int mid;
- while(low < high) {
mid = (low + high) / 2;
offset = p + mid * item_size;
- tmp = (struct btrfs_disk_key *)(eb->data + offset);
- ret = btrfs_comp_keys(tmp, key);
+ read_extent_buffer(eb, &unaligned, offset, key_size);
+ tmp = &unaligned;
+
+ ret = comp_keys(tmp, key);
if (ret < 0)
low = mid + 1;
@@ -525,79 +937,79 @@ static int generic_bin_search(struct extent_buffer *eb, unsigned long p,
return 1;
}
-/*
- * simple bin_search frontend that does the right thing for
- * leaves vs nodes
- */
-int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
- const struct btrfs_key *key, int *slot)
+static void root_add_used(struct btrfs_root *root, u32 size)
{
- if (btrfs_header_level(eb) == 0)
- return generic_bin_search(eb,
- offsetof(struct btrfs_leaf, items),
- sizeof(struct btrfs_item),
- key, btrfs_header_nritems(eb),
- slot);
- else
- return generic_bin_search(eb,
- offsetof(struct btrfs_node, ptrs),
- sizeof(struct btrfs_key_ptr),
- key, btrfs_header_nritems(eb),
- slot);
+ spin_lock(&root->accounting_lock);
+ btrfs_set_root_used(&root->root_item,
+ btrfs_root_used(&root->root_item) + size);
+ spin_unlock(&root->accounting_lock);
}
+static void root_sub_used(struct btrfs_root *root, u32 size)
+{
+ spin_lock(&root->accounting_lock);
+ btrfs_set_root_used(&root->root_item,
+ btrfs_root_used(&root->root_item) - size);
+ spin_unlock(&root->accounting_lock);
+}
+
+/* given a node and slot number, this reads the blocks it points to. The
+ * extent buffer is returned with a reference taken (but unlocked).
+ *
+ * MODIFIED:
+ * - Removed the btrfs_tree_parent_check stuff as we don't have that yet.
+ */
struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
int slot)
{
- struct btrfs_fs_info *fs_info = parent->fs_info;
- struct extent_buffer *ret;
int level = btrfs_header_level(parent);
+ struct extent_buffer *eb;
+ struct btrfs_key first_key;
- if (slot < 0)
- return NULL;
- if (slot >= btrfs_header_nritems(parent))
- return NULL;
+ if (slot < 0 || slot >= btrfs_header_nritems(parent))
+ return ERR_PTR(-ENOENT);
- if (level == 0)
- return NULL;
+ ASSERT(level);
- ret = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
- btrfs_header_owner(parent),
- btrfs_node_ptr_generation(parent, slot),
- level - 1, NULL);
- if (!extent_buffer_uptodate(ret))
- return ERR_PTR(-EIO);
-
- if (btrfs_header_level(ret) != level - 1) {
- error(
-"child eb corrupted: parent bytenr=%llu item=%d parent level=%d child bytenr=%llu child level=%d",
- btrfs_header_bytenr(parent), slot, btrfs_header_level(parent),
- btrfs_header_bytenr(ret), btrfs_header_level(ret));
- free_extent_buffer(ret);
+ eb = read_tree_block(parent->fs_info, btrfs_node_blockptr(parent, slot),
+ btrfs_header_owner(parent),
+ btrfs_node_ptr_generation(parent, slot),
+ level - 1, &first_key);
+ if (IS_ERR(eb))
+ return eb;
+ if (!extent_buffer_uptodate(eb)) {
+ free_extent_buffer(eb);
return ERR_PTR(-EIO);
}
- return ret;
+
+ return eb;
}
-static int balance_level(struct btrfs_trans_handle *trans,
+/*
+ * node level balancing, used to make sure nodes are in proper order for
+ * item deletion. We balance from the top down, so we have to make sure
+ * that a deletion won't leave an node completely empty later on.
+ */
+static noinline int balance_level(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int level)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *right = NULL;
struct extent_buffer *mid;
struct extent_buffer *left = NULL;
struct extent_buffer *parent = NULL;
- struct btrfs_fs_info *fs_info = root->fs_info;
int ret = 0;
int wret;
int pslot;
int orig_slot = path->slots[level];
u64 orig_ptr;
- if (level == 0)
- return 0;
+ ASSERT(level > 0);
mid = path->nodes[level];
+
+ WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK);
WARN_ON(btrfs_header_generation(mid) != trans->transid);
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
@@ -619,42 +1031,75 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* promote the child to a root */
child = btrfs_read_node_slot(mid, 0);
- BUG_ON(!extent_buffer_uptodate(child));
- ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
- BUG_ON(ret);
+ if (IS_ERR(child)) {
+ ret = PTR_ERR(child);
+ btrfs_handle_fs_error(fs_info, ret, NULL);
+ goto enospc;
+ }
+
+ btrfs_tree_lock(child);
+ ret = btrfs_cow_block(trans, root, child, mid, 0, &child,
+ BTRFS_NESTING_COW);
+ if (ret) {
+ btrfs_tree_unlock(child);
+ free_extent_buffer(child);
+ goto enospc;
+ }
+
+ ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
+ BUG_ON(ret < 0);
+ rcu_assign_pointer(root->node, child);
- root->node = child;
add_root_to_dirty_list(root);
+ btrfs_tree_unlock(child);
+
+ path->locks[level] = 0;
path->nodes[level] = NULL;
btrfs_clear_buffer_dirty(trans, mid);
+ btrfs_tree_unlock(mid);
/* once for the path */
free_extent_buffer(mid);
root_sub_used(root, mid->len);
-
- ret = btrfs_free_extent(trans, mid->start, mid->len, 0,
- root->root_key.objectid, level, 0);
+ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
/* once for the root ptr */
- free_extent_buffer(mid);
- return ret;
+ free_extent_buffer_stale(mid);
+ return 0;
}
if (btrfs_header_nritems(mid) >
BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)
return 0;
- left = btrfs_read_node_slot(parent, pslot - 1);
- if (extent_buffer_uptodate(left)) {
+ if (pslot) {
+ left = btrfs_read_node_slot(parent, pslot - 1);
+ if (IS_ERR(left)) {
+ ret = PTR_ERR(left);
+ left = NULL;
+ goto enospc;
+ }
+
+ __btrfs_tree_lock(left, BTRFS_NESTING_LEFT);
wret = btrfs_cow_block(trans, root, left,
- parent, pslot - 1, &left);
+ parent, pslot - 1, &left,
+ BTRFS_NESTING_LEFT_COW);
if (wret) {
ret = wret;
goto enospc;
}
}
- right = btrfs_read_node_slot(parent, pslot + 1);
- if (extent_buffer_uptodate(right)) {
+
+ if (pslot + 1 < btrfs_header_nritems(parent)) {
+ right = btrfs_read_node_slot(parent, pslot + 1);
+ if (IS_ERR(right)) {
+ ret = PTR_ERR(right);
+ right = NULL;
+ goto enospc;
+ }
+
+ __btrfs_tree_lock(right, BTRFS_NESTING_RIGHT);
wret = btrfs_cow_block(trans, root, right,
- parent, pslot + 1, &right);
+ parent, pslot + 1, &right,
+ BTRFS_NESTING_RIGHT_COW);
if (wret) {
ret = wret;
goto enospc;
@@ -664,7 +1109,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* first, try to make some room in the middle buffer */
if (left) {
orig_slot += btrfs_header_nritems(left);
- wret = push_node_left(trans, root, left, mid, 1);
+ wret = push_node_left(trans, left, mid, 1);
if (wret < 0)
ret = wret;
}
@@ -673,27 +1118,24 @@ static int balance_level(struct btrfs_trans_handle *trans,
* then try to empty the right most buffer into the middle
*/
if (right) {
- wret = push_node_left(trans, root, mid, right, 1);
+ wret = push_node_left(trans, mid, right, 1);
if (wret < 0 && wret != -ENOSPC)
ret = wret;
if (btrfs_header_nritems(right) == 0) {
- u64 bytenr = right->start;
- u32 blocksize = right->len;
-
btrfs_clear_buffer_dirty(trans, right);
- free_extent_buffer(right);
- right = NULL;
+ btrfs_tree_unlock(right);
btrfs_del_ptr(root, path, level + 1, pslot + 1);
-
- root_sub_used(root, blocksize);
- wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
- root->root_key.objectid, level,
- 0);
- if (wret)
- ret = wret;
+ root_sub_used(root, right->len);
+ btrfs_free_tree_block(trans, btrfs_root_id(root), right,
+ 0, 1);
+ free_extent_buffer_stale(right);
+ right = NULL;
} else {
struct btrfs_disk_key right_key;
btrfs_node_key(right, &right_key, 0);
+ ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
+ BTRFS_MOD_LOG_KEY_REPLACE);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
}
@@ -708,37 +1150,38 @@ static int balance_level(struct btrfs_trans_handle *trans,
* otherwise we would have pulled some pointers from the
* right
*/
- BUG_ON(!left);
- wret = balance_node_right(trans, root, mid, left);
+ if (!left) {
+ ret = -EROFS;
+ btrfs_handle_fs_error(fs_info, ret, NULL);
+ goto enospc;
+ }
+ wret = balance_node_right(trans, mid, left);
if (wret < 0) {
ret = wret;
goto enospc;
}
if (wret == 1) {
- wret = push_node_left(trans, root, left, mid, 1);
+ wret = push_node_left(trans, left, mid, 1);
if (wret < 0)
ret = wret;
}
BUG_ON(wret == 1);
}
if (btrfs_header_nritems(mid) == 0) {
- /* we've managed to empty the middle node, drop it */
- u64 bytenr = mid->start;
- u32 blocksize = mid->len;
btrfs_clear_buffer_dirty(trans, mid);
- free_extent_buffer(mid);
- mid = NULL;
+ btrfs_tree_unlock(mid);
btrfs_del_ptr(root, path, level + 1, pslot);
-
- root_sub_used(root, blocksize);
- wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
- root->root_key.objectid, level, 0);
- if (wret)
- ret = wret;
+ root_sub_used(root, mid->len);
+ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+ free_extent_buffer_stale(mid);
+ mid = NULL;
} else {
/* update the parent key to reflect our changes */
struct btrfs_disk_key mid_key;
btrfs_node_key(mid, &mid_key, 0);
+ ret = btrfs_tree_mod_log_insert_key(parent, pslot,
+ BTRFS_MOD_LOG_KEY_REPLACE);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent);
}
@@ -746,40 +1189,50 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* update the path */
if (left) {
if (btrfs_header_nritems(left) > orig_slot) {
- extent_buffer_get(left);
+ atomic_inc(&left->refs);
+ /* left was locked after cow */
path->nodes[level] = left;
path->slots[level + 1] -= 1;
path->slots[level] = orig_slot;
- if (mid)
+ if (mid) {
+ btrfs_tree_unlock(mid);
free_extent_buffer(mid);
+ }
} else {
orig_slot -= btrfs_header_nritems(left);
path->slots[level] = orig_slot;
}
}
/* double check we haven't messed things up */
- check_block(root->fs_info, path, level);
if (orig_ptr !=
btrfs_node_blockptr(path->nodes[level], path->slots[level]))
BUG();
enospc:
- if (right)
+ if (right) {
+ btrfs_tree_unlock(right);
free_extent_buffer(right);
- if (left)
+ }
+ if (left) {
+ if (path->nodes[level] != left)
+ btrfs_tree_unlock(left);
free_extent_buffer(left);
+ }
return ret;
}
-/* returns zero if the push worked, non-zero otherwise */
-static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
+/* Node balancing for insertion. Here we only split or push nodes around
+ * when they are completely full. This is also done top down, so we
+ * have to be pessimistic.
+ */
+static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int level)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *right = NULL;
struct extent_buffer *mid;
struct extent_buffer *left = NULL;
struct extent_buffer *parent = NULL;
- struct btrfs_fs_info *fs_info = root->fs_info;
int ret = 0;
int wret;
int pslot;
@@ -799,22 +1252,27 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
if (!parent)
return 1;
- left = btrfs_read_node_slot(parent, pslot - 1);
-
/* first, try to make some room in the middle buffer */
- if (extent_buffer_uptodate(left)) {
+ if (pslot) {
u32 left_nr;
+
+ left = btrfs_read_node_slot(parent, pslot - 1);
+ if (IS_ERR(left))
+ return PTR_ERR(left);
+
+ __btrfs_tree_lock(left, BTRFS_NESTING_LEFT);
+
left_nr = btrfs_header_nritems(left);
if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) {
wret = 1;
} else {
ret = btrfs_cow_block(trans, root, left, parent,
- pslot - 1, &left);
+ pslot - 1, &left,
+ BTRFS_NESTING_LEFT_COW);
if (ret)
wret = 1;
else {
- wret = push_node_left(trans, root,
- left, mid, 0);
+ wret = push_node_left(trans, left, mid, 0);
}
}
if (wret < 0)
@@ -823,42 +1281,53 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key;
orig_slot += left_nr;
btrfs_node_key(mid, &disk_key, 0);
+ ret = btrfs_tree_mod_log_insert_key(parent, pslot,
+ BTRFS_MOD_LOG_KEY_REPLACE);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent);
if (btrfs_header_nritems(left) > orig_slot) {
path->nodes[level] = left;
path->slots[level + 1] -= 1;
path->slots[level] = orig_slot;
+ btrfs_tree_unlock(mid);
free_extent_buffer(mid);
} else {
orig_slot -=
btrfs_header_nritems(left);
path->slots[level] = orig_slot;
+ btrfs_tree_unlock(left);
free_extent_buffer(left);
}
return 0;
}
+ btrfs_tree_unlock(left);
free_extent_buffer(left);
}
- right= btrfs_read_node_slot(parent, pslot + 1);
/*
* then try to empty the right most buffer into the middle
*/
- if (extent_buffer_uptodate(right)) {
+ if (pslot + 1 < btrfs_header_nritems(parent)) {
u32 right_nr;
+
+ right = btrfs_read_node_slot(parent, pslot + 1);
+ if (IS_ERR(right))
+ return PTR_ERR(right);
+
+ __btrfs_tree_lock(right, BTRFS_NESTING_RIGHT);
+
right_nr = btrfs_header_nritems(right);
- if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - 1) {
+ if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) {
wret = 1;
} else {
ret = btrfs_cow_block(trans, root, right,
parent, pslot + 1,
- &right);
+ &right, BTRFS_NESTING_RIGHT_COW);
if (ret)
wret = 1;
else {
- wret = balance_node_right(trans, root,
- right, mid);
+ wret = balance_node_right(trans, right, mid);
}
}
if (wret < 0)
@@ -867,6 +1336,9 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key;
btrfs_node_key(right, &disk_key, 0);
+ ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
+ BTRFS_MOD_LOG_KEY_REPLACE);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
@@ -875,244 +1347,1045 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
path->slots[level + 1] += 1;
path->slots[level] = orig_slot -
btrfs_header_nritems(mid);
+ btrfs_tree_unlock(mid);
free_extent_buffer(mid);
} else {
+ btrfs_tree_unlock(right);
free_extent_buffer(right);
}
return 0;
}
+ btrfs_tree_unlock(right);
free_extent_buffer(right);
}
return 1;
}
/*
- * readahead one full node of leaves
+ * readahead one full node of leaves, finding things that are close
+ * to the block in 'slot', and triggering ra on them.
*/
static void reada_for_search(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path, int level, int slot,
- u64 objectid)
+ struct btrfs_path *path,
+ int level, int slot, u64 objectid)
{
struct extent_buffer *node;
struct btrfs_disk_key disk_key;
u32 nritems;
u64 search;
- u64 lowest_read;
- u64 highest_read;
+ u64 target;
u64 nread = 0;
- int direction = path->reada;
- struct extent_buffer *eb;
+ u64 nread_max;
u32 nr;
+ u32 blocksize;
u32 nscan = 0;
- if (level != 1)
+ if (level != 1 && path->reada != READA_FORWARD_ALWAYS)
return;
if (!path->nodes[level])
return;
node = path->nodes[level];
- search = btrfs_node_blockptr(node, slot);
- eb = btrfs_find_tree_block(fs_info, search, fs_info->nodesize);
- if (eb) {
- free_extent_buffer(eb);
- return;
+
+ /*
+ * Since the time between visiting leaves is much shorter than the time
+ * between visiting nodes, limit read ahead of nodes to 1, to avoid too
+ * much IO at once (possibly random).
+ */
+ if (path->reada == READA_FORWARD_ALWAYS) {
+ if (level > 1)
+ nread_max = node->fs_info->nodesize;
+ else
+ nread_max = SZ_128K;
+ } else {
+ nread_max = SZ_64K;
}
- highest_read = search;
- lowest_read = search;
+ search = btrfs_node_blockptr(node, slot);
+ blocksize = fs_info->nodesize;
+ if (path->reada != READA_FORWARD_ALWAYS) {
+ struct extent_buffer *eb;
+
+ eb = find_extent_buffer(fs_info, search);
+ if (eb) {
+ free_extent_buffer(eb);
+ return;
+ }
+ }
+
+ target = search;
nritems = btrfs_header_nritems(node);
nr = slot;
- while(1) {
- if (direction < 0) {
+
+ while (1) {
+ if (path->reada == READA_BACK) {
if (nr == 0)
break;
nr--;
- } else if (direction > 0) {
+ } else if (path->reada == READA_FORWARD ||
+ path->reada == READA_FORWARD_ALWAYS) {
nr++;
if (nr >= nritems)
break;
}
- if (path->reada < 0 && objectid) {
+ if (path->reada == READA_BACK && objectid) {
btrfs_node_key(node, &disk_key, nr);
if (btrfs_disk_key_objectid(&disk_key) != objectid)
break;
}
search = btrfs_node_blockptr(node, nr);
- if ((search >= lowest_read && search <= highest_read) ||
- (search < lowest_read && lowest_read - search <= 32768) ||
- (search > highest_read && search - highest_read <= 32768)) {
- readahead_tree_block(fs_info, search,
- btrfs_node_ptr_generation(node, nr));
- nread += fs_info->nodesize;
+ if (path->reada == READA_FORWARD_ALWAYS ||
+ (search <= target && target - search <= 65536) ||
+ (search > target && search - target <= 65536)) {
+ btrfs_readahead_node_child(node, nr);
+ nread += blocksize;
}
nscan++;
- if (path->reada < 2 && (nread > SZ_256K || nscan > 32))
+ if (nread > nread_max || nscan > 32)
break;
- if(nread > SZ_1M || nscan > 128)
- break;
-
- if (search < lowest_read)
- lowest_read = search;
- if (search > highest_read)
- highest_read = search;
}
}
-int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
+static noinline void reada_for_balance(struct btrfs_path *path, int level)
+{
+ struct extent_buffer *parent;
+ int slot;
+ int nritems;
+
+ parent = path->nodes[level + 1];
+ if (!parent)
+ return;
+
+ nritems = btrfs_header_nritems(parent);
+ slot = path->slots[level + 1];
+
+ if (slot > 0)
+ btrfs_readahead_node_child(parent, slot - 1);
+ if (slot + 1 < nritems)
+ btrfs_readahead_node_child(parent, slot + 1);
+}
+
+
+/*
+ * when we walk down the tree, it is usually safe to unlock the higher layers
+ * in the tree. The exceptions are when our path goes through slot 0, because
+ * operations on the tree might require changing key pointers higher up in the
+ * tree.
+ *
+ * callers might also have set path->keep_locks, which tells this code to keep
+ * the lock if the path points to the last slot in the block. This is part of
+ * walking through the tree, and selecting the next slot in the higher block.
+ *
+ * lowest_unlock sets the lowest level in the tree we're allowed to unlock. so
+ * if lowest_unlock is 1, level 0 won't be unlocked
+ */
+static noinline void unlock_up(struct btrfs_path *path, int level,
+ int lowest_unlock, int min_write_lock_level,
+ int *write_lock_level)
+{
+ int i;
+ int skip_level = level;
+ bool check_skip = true;
+
+ for (i = level; i < BTRFS_MAX_LEVEL; i++) {
+ if (!path->nodes[i])
+ break;
+ if (!path->locks[i])
+ break;
+
+ if (check_skip) {
+ if (path->slots[i] == 0) {
+ skip_level = i + 1;
+ continue;
+ }
+
+ if (path->keep_locks) {
+ u32 nritems;
+
+ nritems = btrfs_header_nritems(path->nodes[i]);
+ if (nritems < 1 || path->slots[i] >= nritems - 1) {
+ skip_level = i + 1;
+ continue;
+ }
+ }
+ }
+
+ if (i >= lowest_unlock && i > skip_level) {
+ check_skip = false;
+ btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
+ path->locks[i] = 0;
+ if (write_lock_level &&
+ i > min_write_lock_level &&
+ i <= *write_lock_level) {
+ *write_lock_level = i - 1;
+ }
+ }
+ }
+}
+
+/*
+ * Helper function for btrfs_search_slot() and other functions that do a search
+ * on a btree. The goal is to find a tree block in the cache (the radix tree at
+ * fs_info->buffer_radix), but if we can't find it, or it's not up to date, read
+ * its pages from disk.
+ *
+ * Returns -EAGAIN, with the path unlocked, if the caller needs to repeat the
+ * whole btree search, starting again from the current root node.
+ *
+ * MODIFIED:
+ * - Removed the btrfs_tree_parent_check stuff as that doesn't exist yet.
+ */
+static int
+read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
+ struct extent_buffer **eb_ret, int level, int slot,
+ const struct btrfs_key *key)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_key first_key;
+ u64 blocknr;
+ u64 gen;
+ struct extent_buffer *tmp;
+ int ret;
+ int parent_level;
+ bool unlock_up;
+
+ unlock_up = ((level + 1 < BTRFS_MAX_LEVEL) && p->locks[level + 1]);
+ blocknr = btrfs_node_blockptr(*eb_ret, slot);
+ gen = btrfs_node_ptr_generation(*eb_ret, slot);
+ parent_level = btrfs_header_level(*eb_ret);
+ btrfs_node_key_to_cpu(*eb_ret, &first_key, slot);
+
+ /*
+ * If we need to read an extent buffer from disk and we are holding locks
+ * on upper level nodes, we unlock all the upper nodes before reading the
+ * extent buffer, and then return -EAGAIN to the caller as it needs to
+ * restart the search. We don't release the lock on the current level
+ * because we need to walk this node to figure out which blocks to read.
+ */
+ tmp = find_extent_buffer(fs_info, blocknr);
+ if (tmp) {
+ if (p->reada == READA_FORWARD_ALWAYS)
+ reada_for_search(fs_info, p, level, slot, key->objectid);
+
+ /* first we do an atomic uptodate check */
+ if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
+ /*
+ * Do extra check for first_key, eb can be stale due to
+ * being cached, read from scrub, or have multiple
+ * parents (shared tree blocks).
+ */
+ if (btrfs_verify_level_key(tmp,
+ parent_level - 1, &first_key, gen)) {
+ free_extent_buffer(tmp);
+ return -EUCLEAN;
+ }
+ *eb_ret = tmp;
+ return 0;
+ }
+
+ if (p->nowait) {
+ free_extent_buffer(tmp);
+ return -EAGAIN;
+ }
+
+ if (unlock_up)
+ btrfs_unlock_up_safe(p, level + 1);
+
+ /* now we're allowed to do a blocking uptodate check */
+ ret = btrfs_read_extent_buffer(tmp, gen, parent_level - 1,
+ &first_key);
+ if (ret) {
+ free_extent_buffer(tmp);
+ btrfs_release_path(p);
+ return -EIO;
+ }
+ if (btrfs_check_eb_owner(tmp, root->root_key.objectid)) {
+ free_extent_buffer(tmp);
+ btrfs_release_path(p);
+ return -EUCLEAN;
+ }
+
+ if (unlock_up)
+ ret = -EAGAIN;
+
+ goto out;
+ } else if (p->nowait) {
+ return -EAGAIN;
+ }
+
+ if (unlock_up) {
+ btrfs_unlock_up_safe(p, level + 1);
+ ret = -EAGAIN;
+ } else {
+ ret = 0;
+ }
+
+ if (p->reada != READA_NONE)
+ reada_for_search(fs_info, p, level, slot, key->objectid);
+
+ tmp = read_tree_block(fs_info, blocknr, root->root_key.objectid,
+ gen, parent_level - 1, &first_key);
+ if (IS_ERR(tmp)) {
+ btrfs_release_path(p);
+ return PTR_ERR(tmp);
+ }
+ /*
+ * If the read above didn't mark this buffer up to date,
+ * it will never end up being up to date. Set ret to EIO now
+ * and give up so that our caller doesn't loop forever
+ * on our EAGAINs.
+ */
+ if (!extent_buffer_uptodate(tmp))
+ ret = -EIO;
+
+out:
+ if (ret == 0) {
+ *eb_ret = tmp;
+ } else {
+ free_extent_buffer(tmp);
+ btrfs_release_path(p);
+ }
+
+ return ret;
+}
+
+/*
+ * helper function for btrfs_search_slot. This does all of the checks
+ * for node-level blocks and does any balancing required based on
+ * the ins_len.
+ *
+ * If no extra work was required, zero is returned. If we had to
+ * drop the path, -EAGAIN is returned and btrfs_search_slot must
+ * start over
+ */
+static int
+setup_nodes_for_search(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_path *p,
+ struct extent_buffer *b, int level, int ins_len,
+ int *write_lock_level)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ int ret = 0;
+
+ if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=
+ BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 3) {
+
+ if (*write_lock_level < level + 1) {
+ *write_lock_level = level + 1;
+ btrfs_release_path(p);
+ return -EAGAIN;
+ }
+
+ reada_for_balance(p, level);
+ ret = split_node(trans, root, p, level);
+
+ b = p->nodes[level];
+ } else if (ins_len < 0 && btrfs_header_nritems(b) <
+ BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 2) {
+
+ if (*write_lock_level < level + 1) {
+ *write_lock_level = level + 1;
+ btrfs_release_path(p);
+ return -EAGAIN;
+ }
+
+ reada_for_balance(p, level);
+ ret = balance_level(trans, root, p, level);
+ if (ret)
+ return ret;
+
+ b = p->nodes[level];
+ if (!b) {
+ btrfs_release_path(p);
+ return -EAGAIN;
+ }
+ BUG_ON(btrfs_header_nritems(b) == 1);
+ }
+ return ret;
+}
+
+int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key)
{
int ret;
struct btrfs_key key;
struct extent_buffer *eb;
- struct btrfs_path *path;
+
+ ASSERT(path);
+ ASSERT(found_key);
key.type = key_type;
key.objectid = iobjectid;
key.offset = ioff;
- if (found_path == NULL) {
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
- } else
- path = found_path;
-
ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
- if ((ret < 0) || (found_key == NULL))
- goto out;
+ if (ret < 0)
+ return ret;
eb = path->nodes[0];
if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
ret = btrfs_next_leaf(fs_root, path);
if (ret)
- goto out;
+ return ret;
eb = path->nodes[0];
}
btrfs_item_key_to_cpu(eb, found_key, path->slots[0]);
if (found_key->type != key.type ||
- found_key->objectid != key.objectid) {
- ret = 1;
+ found_key->objectid != key.objectid)
+ return 1;
+
+ return 0;
+}
+
+static struct extent_buffer *btrfs_search_slot_get_root(struct btrfs_root *root,
+ struct btrfs_path *p,
+ int write_lock_level)
+{
+ struct extent_buffer *b;
+ int root_lock = 0;
+ int level = 0;
+
+ if (p->search_commit_root) {
+ b = root->commit_root;
+ atomic_inc(&b->refs);
+ level = btrfs_header_level(b);
+ /*
+ * Ensure that all callers have set skip_locking when
+ * p->search_commit_root = 1.
+ */
+ ASSERT(p->skip_locking == 1);
+
goto out;
}
+ if (p->skip_locking) {
+ b = btrfs_root_node(root);
+ level = btrfs_header_level(b);
+ goto out;
+ }
+
+ /* We try very hard to do read locks on the root */
+ root_lock = BTRFS_READ_LOCK;
+
+ /*
+ * If the level is set to maximum, we can skip trying to get the read
+ * lock.
+ */
+ if (write_lock_level < BTRFS_MAX_LEVEL) {
+ /*
+ * We don't know the level of the root node until we actually
+ * have it read locked
+ */
+ if (p->nowait) {
+ b = btrfs_try_read_lock_root_node(root);
+ if (IS_ERR(b))
+ return b;
+ } else {
+ b = btrfs_read_lock_root_node(root);
+ }
+ level = btrfs_header_level(b);
+ if (level > write_lock_level)
+ goto out;
+
+ /* Whoops, must trade for write lock */
+ btrfs_tree_read_unlock(b);
+ free_extent_buffer(b);
+ }
+
+ b = btrfs_lock_root_node(root);
+ root_lock = BTRFS_WRITE_LOCK;
+
+ /* The level might have changed, check again */
+ level = btrfs_header_level(b);
+
out:
- if (path != found_path)
- btrfs_free_path(path);
+ /*
+ * The root may have failed to write out at some point, and thus is no
+ * longer valid, return an error in this case.
+ */
+ if (!extent_buffer_uptodate(b)) {
+ if (root_lock)
+ btrfs_tree_unlock_rw(b, root_lock);
+ free_extent_buffer(b);
+ return ERR_PTR(-EIO);
+ }
+
+ p->nodes[level] = b;
+ if (!p->skip_locking)
+ p->locks[level] = root_lock;
+ /*
+ * Callers are responsible for dropping b's references.
+ */
+ return b;
+}
+
+/*
+ * Replace the extent buffer at the lowest level of the path with a cloned
+ * version. The purpose is to be able to use it safely, after releasing the
+ * commit root semaphore, even if relocation is happening in parallel, the
+ * transaction used for relocation is committed and the extent buffer is
+ * reallocated in the next transaction.
+ *
+ * This is used in a context where the caller does not prevent transaction
+ * commits from happening, either by holding a transaction handle or holding
+ * some lock, while it's doing searches through a commit root.
+ * At the moment it's only used for send operations.
+ */
+static int finish_need_commit_sem_search(struct btrfs_path *path)
+{
+ const int i = path->lowest_level;
+ const int slot = path->slots[i];
+ struct extent_buffer *lowest = path->nodes[i];
+ struct extent_buffer *clone;
+
+ ASSERT(path->need_commit_sem);
+
+ if (!lowest)
+ return 0;
+
+ lockdep_assert_held_read(&lowest->fs_info->commit_root_sem);
+
+ clone = btrfs_clone_extent_buffer(lowest);
+ if (!clone)
+ return -ENOMEM;
+
+ btrfs_release_path(path);
+ path->nodes[i] = clone;
+ path->slots[i] = slot;
+
+ return 0;
+}
+
+static inline int search_for_key_slot(struct extent_buffer *eb,
+ int search_low_slot,
+ const struct btrfs_key *key,
+ int prev_cmp,
+ int *slot)
+{
+ /*
+ * If a previous call to btrfs_bin_search() on a parent node returned an
+ * exact match (prev_cmp == 0), we can safely assume the target key will
+ * always be at slot 0 on lower levels, since each key pointer
+ * (struct btrfs_key_ptr) refers to the lowest key accessible from the
+ * subtree it points to. Thus we can skip searching lower levels.
+ */
+ if (prev_cmp == 0) {
+ *slot = 0;
+ return 0;
+ }
+
+ return btrfs_bin_search(eb, search_low_slot, key, slot);
+}
+
+static int search_leaf(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ const struct btrfs_key *key,
+ struct btrfs_path *path,
+ int ins_len,
+ int prev_cmp)
+{
+ struct extent_buffer *leaf = path->nodes[0];
+ int leaf_free_space = -1;
+ int search_low_slot = 0;
+ int ret;
+ bool do_bin_search = true;
+
+ /*
+ * If we are doing an insertion, the leaf has enough free space and the
+ * destination slot for the key is not slot 0, then we can unlock our
+ * write lock on the parent, and any other upper nodes, before doing the
+ * binary search on the leaf (with search_for_key_slot()), allowing other
+ * tasks to lock the parent and any other upper nodes.
+ */
+ if (ins_len > 0) {
+ /*
+ * Cache the leaf free space, since we will need it later and it
+ * will not change until then.
+ */
+ leaf_free_space = btrfs_leaf_free_space(leaf);
+
+ /*
+ * !path->locks[1] means we have a single node tree, the leaf is
+ * the root of the tree.
+ */
+ if (path->locks[1] && leaf_free_space >= ins_len) {
+ struct btrfs_disk_key first_key;
+
+ ASSERT(btrfs_header_nritems(leaf) > 0);
+ btrfs_item_key(leaf, &first_key, 0);
+
+ /*
+ * Doing the extra comparison with the first key is cheap,
+ * taking into account that the first key is very likely
+ * already in a cache line because it immediately follows
+ * the extent buffer's header and we have recently accessed
+ * the header's level field.
+ */
+ ret = comp_keys(&first_key, key);
+ if (ret < 0) {
+ /*
+ * The first key is smaller than the key we want
+ * to insert, so we are safe to unlock all upper
+ * nodes and we have to do the binary search.
+ *
+ * We do use btrfs_unlock_up_safe() and not
+ * unlock_up() because the later does not unlock
+ * nodes with a slot of 0 - we can safely unlock
+ * any node even if its slot is 0 since in this
+ * case the key does not end up at slot 0 of the
+ * leaf and there's no need to split the leaf.
+ */
+ btrfs_unlock_up_safe(path, 1);
+ search_low_slot = 1;
+ } else {
+ /*
+ * The first key is >= then the key we want to
+ * insert, so we can skip the binary search as
+ * the target key will be at slot 0.
+ *
+ * We can not unlock upper nodes when the key is
+ * less than the first key, because we will need
+ * to update the key at slot 0 of the parent node
+ * and possibly of other upper nodes too.
+ * If the key matches the first key, then we can
+ * unlock all the upper nodes, using
+ * btrfs_unlock_up_safe() instead of unlock_up()
+ * as stated above.
+ */
+ if (ret == 0)
+ btrfs_unlock_up_safe(path, 1);
+ /*
+ * ret is already 0 or 1, matching the result of
+ * a btrfs_bin_search() call, so there is no need
+ * to adjust it.
+ */
+ do_bin_search = false;
+ path->slots[0] = 0;
+ }
+ }
+ }
+
+ if (do_bin_search) {
+ ret = search_for_key_slot(leaf, search_low_slot, key,
+ prev_cmp, &path->slots[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ins_len > 0) {
+ /*
+ * Item key already exists. In this case, if we are allowed to
+ * insert the item (for example, in dir_item case, item key
+ * collision is allowed), it will be merged with the original
+ * item. Only the item size grows, no new btrfs item will be
+ * added. If search_for_extension is not set, ins_len already
+ * accounts the size btrfs_item, deduct it here so leaf space
+ * check will be correct.
+ */
+ if (ret == 0 && !path->search_for_extension) {
+ ASSERT(ins_len >= sizeof(struct btrfs_item));
+ ins_len -= sizeof(struct btrfs_item);
+ }
+
+ ASSERT(leaf_free_space >= 0);
+
+ if (leaf_free_space < ins_len) {
+ int err;
+
+ err = split_leaf(trans, root, key, path, ins_len,
+ (ret == 0));
+ ASSERT(err <= 0);
+ if (WARN_ON(err > 0))
+ err = -EUCLEAN;
+ if (err)
+ ret = err;
+ }
+ }
+
return ret;
}
/*
- * look for key in the tree. path is filled in with nodes along the way
- * if key is found, we return zero and you can find the item in the leaf
- * level of the path (level 0)
+ * btrfs_search_slot - look for a key in a tree and perform necessary
+ * modifications to preserve tree invariants.
*
- * If the key isn't found, the path points to the slot where it should
- * be inserted, and 1 is returned. If there are other errors during the
- * search a negative error number is returned.
+ * @trans: Handle of transaction, used when modifying the tree
+ * @p: Holds all btree nodes along the search path
+ * @root: The root node of the tree
+ * @key: The key we are looking for
+ * @ins_len: Indicates purpose of search:
+ * >0 for inserts it's size of item inserted (*)
+ * <0 for deletions
+ * 0 for plain searches, not modifying the tree
*
- * if ins_len > 0, nodes and leaves will be split as we walk down the
- * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if
- * possible)
+ * (*) If size of item inserted doesn't include
+ * sizeof(struct btrfs_item), then p->search_for_extension must
+ * be set.
+ * @cow: boolean should CoW operations be performed. Must always be 1
+ * when modifying the tree.
+ *
+ * If @ins_len > 0, nodes and leaves will be split as we walk down the tree.
+ * If @ins_len < 0, nodes will be merged as we walk down the tree (if possible)
+ *
+ * If @key is found, 0 is returned and you can find the item in the leaf level
+ * of the path (level 0)
+ *
+ * If @key isn't found, 1 is returned and the leaf level of the path (level 0)
+ * points to the slot where it should be inserted
+ *
+ * If an error is encountered while searching the tree a negative error number
+ * is returned
*/
-int btrfs_search_slot(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, const struct btrfs_key *key,
- struct btrfs_path *p, int ins_len, int cow)
+int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ const struct btrfs_key *key, struct btrfs_path *p,
+ int ins_len, int cow)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *b;
int slot;
int ret;
+ int err;
int level;
- int should_reada = p->reada;
- struct btrfs_fs_info *fs_info = root->fs_info;
+ int lowest_unlock = 1;
+ /* everything at write_lock_level or lower must be write locked */
+ int write_lock_level = 0;
u8 lowest_level = 0;
+ int min_write_lock_level;
+ int prev_cmp;
+
+ might_sleep();
lowest_level = p->lowest_level;
WARN_ON(lowest_level && ins_len > 0);
WARN_ON(p->nodes[0] != NULL);
-again:
- b = root->node;
- extent_buffer_get(b);
- while (b) {
- level = btrfs_header_level(b);
- if (cow) {
- int wret;
- wret = btrfs_cow_block(trans, root, b,
- p->nodes[level + 1],
- p->slots[level + 1],
- &b);
- if (wret) {
- free_extent_buffer(b);
- return wret;
- }
- }
- BUG_ON(!cow && ins_len);
- if (level != btrfs_header_level(b))
- WARN_ON(1);
- level = btrfs_header_level(b);
- p->nodes[level] = b;
- ret = check_block(fs_info, p, level);
- if (ret)
- return -1;
- ret = btrfs_bin_search(b, 0, key, &slot);
- if (level != 0) {
- if (ret && slot > 0)
- slot -= 1;
- p->slots[level] = slot;
- if ((p->search_for_split || ins_len > 0) &&
- btrfs_header_nritems(b) >=
- BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 3) {
- int sret = split_node(trans, root, p, level);
- BUG_ON(sret > 0);
- if (sret)
- return sret;
- b = p->nodes[level];
- slot = p->slots[level];
- } else if (ins_len < 0) {
- int sret = balance_level(trans, root, p,
- level);
- if (sret)
- return sret;
- b = p->nodes[level];
- if (!b) {
- btrfs_release_path(p);
- goto again;
- }
- slot = p->slots[level];
- BUG_ON(btrfs_header_nritems(b) == 1);
- }
- /* this is only true while dropping a snapshot */
- if (level == lowest_level)
- break;
+ BUG_ON(!cow && ins_len);
- if (should_reada)
- reada_for_search(fs_info, p, level, slot,
- key->objectid);
+ /*
+ * For now only allow nowait for read only operations. There's no
+ * strict reason why we can't, we just only need it for reads so it's
+ * only implemented for reads.
+ */
+ ASSERT(!p->nowait || !cow);
- b = btrfs_read_node_slot(b, slot);
- if (!extent_buffer_uptodate(b))
- return -EIO;
+ if (ins_len < 0) {
+ lowest_unlock = 2;
+
+ /* when we are removing items, we might have to go up to level
+ * two as we update tree pointers Make sure we keep write
+ * for those levels as well
+ */
+ write_lock_level = 2;
+ } else if (ins_len > 0) {
+ /*
+ * for inserting items, make sure we have a write lock on
+ * level 1 so we can update keys
+ */
+ write_lock_level = 1;
+ }
+
+ if (!cow)
+ write_lock_level = -1;
+
+ if (cow && (p->keep_locks || p->lowest_level))
+ write_lock_level = BTRFS_MAX_LEVEL;
+
+ min_write_lock_level = write_lock_level;
+
+ if (p->need_commit_sem) {
+ ASSERT(p->search_commit_root);
+ if (p->nowait) {
+ if (!down_read_trylock(&fs_info->commit_root_sem))
+ return -EAGAIN;
} else {
- p->slots[level] = slot;
- if (ins_len > 0 &&
- ins_len > btrfs_leaf_free_space(b)) {
- int sret = split_leaf(trans, root, key,
- p, ins_len, ret == 0);
- BUG_ON(sret > 0);
- if (sret)
- return sret;
- }
- return ret;
+ down_read(&fs_info->commit_root_sem);
}
}
- return 1;
+
+again:
+ prev_cmp = -1;
+ b = btrfs_search_slot_get_root(root, p, write_lock_level);
+ if (IS_ERR(b)) {
+ ret = PTR_ERR(b);
+ goto done;
+ }
+
+ while (b) {
+ int dec = 0;
+
+ level = btrfs_header_level(b);
+
+ if (cow) {
+ bool last_level = (level == (BTRFS_MAX_LEVEL - 1));
+
+ /*
+ * if we don't really need to cow this block
+ * then we don't want to set the path blocking,
+ * so we test it here
+ */
+ if (!should_cow_block(trans, root, b))
+ goto cow_done;
+
+ /*
+ * must have write locks on this node and the
+ * parent
+ */
+ if (level > write_lock_level ||
+ (level + 1 > write_lock_level &&
+ level + 1 < BTRFS_MAX_LEVEL &&
+ p->nodes[level + 1])) {
+ write_lock_level = level + 1;
+ btrfs_release_path(p);
+ goto again;
+ }
+
+ if (last_level)
+ err = btrfs_cow_block(trans, root, b, NULL, 0,
+ &b,
+ BTRFS_NESTING_COW);
+ else
+ err = btrfs_cow_block(trans, root, b,
+ p->nodes[level + 1],
+ p->slots[level + 1], &b,
+ BTRFS_NESTING_COW);
+ if (err) {
+ ret = err;
+ goto done;
+ }
+ }
+cow_done:
+ p->nodes[level] = b;
+
+ /*
+ * we have a lock on b and as long as we aren't changing
+ * the tree, there is no way to for the items in b to change.
+ * It is safe to drop the lock on our parent before we
+ * go through the expensive btree search on b.
+ *
+ * If we're inserting or deleting (ins_len != 0), then we might
+ * be changing slot zero, which may require changing the parent.
+ * So, we can't drop the lock until after we know which slot
+ * we're operating on.
+ */
+ if (!ins_len && !p->keep_locks) {
+ int u = level + 1;
+
+ if (u < BTRFS_MAX_LEVEL && p->locks[u]) {
+ btrfs_tree_unlock_rw(p->nodes[u], p->locks[u]);
+ p->locks[u] = 0;
+ }
+ }
+
+ if (level == 0) {
+ if (ins_len > 0)
+ ASSERT(write_lock_level >= 1);
+
+ ret = search_leaf(trans, root, key, p, ins_len, prev_cmp);
+ if (!p->search_for_split)
+ unlock_up(p, level, lowest_unlock,
+ min_write_lock_level, NULL);
+ goto done;
+ }
+
+ ret = search_for_key_slot(b, 0, key, prev_cmp, &slot);
+ if (ret < 0)
+ goto done;
+ prev_cmp = ret;
+
+ if (ret && slot > 0) {
+ dec = 1;
+ slot--;
+ }
+ p->slots[level] = slot;
+ err = setup_nodes_for_search(trans, root, p, b, level, ins_len,
+ &write_lock_level);
+ if (err == -EAGAIN)
+ goto again;
+ if (err) {
+ ret = err;
+ goto done;
+ }
+ b = p->nodes[level];
+ slot = p->slots[level];
+
+ /*
+ * Slot 0 is special, if we change the key we have to update
+ * the parent pointer which means we must have a write lock on
+ * the parent
+ */
+ if (slot == 0 && ins_len && write_lock_level < level + 1) {
+ write_lock_level = level + 1;
+ btrfs_release_path(p);
+ goto again;
+ }
+
+ unlock_up(p, level, lowest_unlock, min_write_lock_level,
+ &write_lock_level);
+
+ if (level == lowest_level) {
+ if (dec)
+ p->slots[level]++;
+ goto done;
+ }
+
+ err = read_block_for_search(root, p, &b, level, slot, key);
+ if (err == -EAGAIN)
+ goto again;
+ if (err) {
+ ret = err;
+ goto done;
+ }
+
+ if (!p->skip_locking) {
+ level = btrfs_header_level(b);
+
+ btrfs_maybe_reset_lockdep_class(root, b);
+
+ if (level <= write_lock_level) {
+ btrfs_tree_lock(b);
+ p->locks[level] = BTRFS_WRITE_LOCK;
+ } else {
+ if (p->nowait) {
+ if (!btrfs_try_tree_read_lock(b)) {
+ free_extent_buffer(b);
+ ret = -EAGAIN;
+ goto done;
+ }
+ } else {
+ btrfs_tree_read_lock(b);
+ }
+ p->locks[level] = BTRFS_READ_LOCK;
+ }
+ p->nodes[level] = b;
+ }
+ }
+ ret = 1;
+done:
+ if (ret < 0 && !p->skip_release_on_error)
+ btrfs_release_path(p);
+
+ if (p->need_commit_sem) {
+ int ret2;
+
+ ret2 = finish_need_commit_sem_search(p);
+ up_read(&fs_info->commit_root_sem);
+ if (ret2)
+ ret = ret2;
+ }
+
+ return ret;
+}
+ALLOW_ERROR_INJECTION(btrfs_search_slot, ERRNO);
+
+/*
+ * Like btrfs_search_slot, this looks for a key in the given tree. It uses the
+ * current state of the tree together with the operations recorded in the tree
+ * modification log to search for the key in a previous version of this tree, as
+ * denoted by the time_seq parameter.
+ *
+ * Naturally, there is no support for insert, delete or cow operations.
+ *
+ * The resulting path and return value will be set up as if we called
+ * btrfs_search_slot at that point in time with ins_len and cow both set to 0.
+ */
+int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key,
+ struct btrfs_path *p, u64 time_seq)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct extent_buffer *b;
+ int slot;
+ int ret;
+ int err;
+ int level;
+ int lowest_unlock = 1;
+ u8 lowest_level = 0;
+
+ lowest_level = p->lowest_level;
+ WARN_ON(p->nodes[0] != NULL);
+ ASSERT(!p->nowait);
+
+ if (p->search_commit_root) {
+ BUG_ON(time_seq);
+ return btrfs_search_slot(NULL, root, key, p, 0, 0);
+ }
+
+again:
+ b = btrfs_get_old_root(root, time_seq);
+ if (!b) {
+ ret = -EIO;
+ goto done;
+ }
+ level = btrfs_header_level(b);
+ p->locks[level] = BTRFS_READ_LOCK;
+
+ while (b) {
+ int dec = 0;
+
+ level = btrfs_header_level(b);
+ p->nodes[level] = b;
+
+ /*
+ * we have a lock on b and as long as we aren't changing
+ * the tree, there is no way to for the items in b to change.
+ * It is safe to drop the lock on our parent before we
+ * go through the expensive btree search on b.
+ */
+ btrfs_unlock_up_safe(p, level + 1);
+
+ ret = btrfs_bin_search(b, 0, key, &slot);
+ if (ret < 0)
+ goto done;
+
+ if (level == 0) {
+ p->slots[level] = slot;
+ unlock_up(p, level, lowest_unlock, 0, NULL);
+ goto done;
+ }
+
+ if (ret && slot > 0) {
+ dec = 1;
+ slot--;
+ }
+ p->slots[level] = slot;
+ unlock_up(p, level, lowest_unlock, 0, NULL);
+
+ if (level == lowest_level) {
+ if (dec)
+ p->slots[level]++;
+ goto done;
+ }
+
+ err = read_block_for_search(root, p, &b, level, slot, key);
+ if (err == -EAGAIN)
+ goto again;
+ if (err) {
+ ret = err;
+ goto done;
+ }
+
+ level = btrfs_header_level(b);
+ btrfs_tree_read_lock(b);
+ b = btrfs_tree_mod_log_rewind(fs_info, p, b, time_seq);
+ if (!b) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ p->locks[level] = BTRFS_READ_LOCK;
+ p->nodes[level] = b;
+ }
+ ret = 1;
+done:
+ if (ret < 0)
+ btrfs_release_path(p);
+
+ return ret;
}
/*
- * Helper to use instead of search slot if no exact match is needed but
+ * helper to use instead of search slot if no exact match is needed but
* instead the next or previous item should be returned.
* When find_higher is true, the next higher item is returned, the next lower
* otherwise.
@@ -1124,65 +2397,126 @@ again:
* < 0 on error
*/
int btrfs_search_slot_for_read(struct btrfs_root *root,
- const struct btrfs_key *key,
- struct btrfs_path *p, int find_higher,
- int return_any)
+ const struct btrfs_key *key,
+ struct btrfs_path *p, int find_higher,
+ int return_any)
{
- int ret;
- struct extent_buffer *leaf;
+ int ret;
+ struct extent_buffer *leaf;
again:
- ret = btrfs_search_slot(NULL, root, key, p, 0, 0);
- if (ret <= 0)
- return ret;
- /*
- * A return value of 1 means the path is at the position where the item
- * should be inserted. Normally this is the next bigger item, but in
- * case the previous item is the last in a leaf, path points to the
- * first free slot in the previous leaf, i.e. at an invalid item.
- */
- leaf = p->nodes[0];
+ ret = btrfs_search_slot(NULL, root, key, p, 0, 0);
+ if (ret <= 0)
+ return ret;
+ /*
+ * a return value of 1 means the path is at the position where the
+ * item should be inserted. Normally this is the next bigger item,
+ * but in case the previous item is the last in a leaf, path points
+ * to the first free slot in the previous leaf, i.e. at an invalid
+ * item.
+ */
+ leaf = p->nodes[0];
- if (find_higher) {
- if (p->slots[0] >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(root, p);
- if (ret <= 0)
- return ret;
- if (!return_any)
- return 1;
- /*
- * No higher item found, return the next lower instead
- */
- return_any = 0;
- find_higher = 0;
- btrfs_release_path(p);
- goto again;
- }
- } else {
- if (p->slots[0] == 0) {
- ret = btrfs_prev_leaf(root, p);
- if (ret < 0)
- return ret;
- if (!ret) {
- leaf = p->nodes[0];
- if (p->slots[0] == btrfs_header_nritems(leaf))
- p->slots[0]--;
- return 0;
- }
- if (!return_any)
- return 1;
- /*
- * No lower item found, return the next higher instead
- */
- return_any = 0;
- find_higher = 1;
- btrfs_release_path(p);
- goto again;
- } else {
- --p->slots[0];
- }
- }
- return 0;
+ if (find_higher) {
+ if (p->slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, p);
+ if (ret <= 0)
+ return ret;
+ if (!return_any)
+ return 1;
+ /*
+ * no higher item found, return the next
+ * lower instead
+ */
+ return_any = 0;
+ find_higher = 0;
+ btrfs_release_path(p);
+ goto again;
+ }
+ } else {
+ if (p->slots[0] == 0) {
+ ret = btrfs_prev_leaf(root, p);
+ if (ret < 0)
+ return ret;
+ if (!ret) {
+ leaf = p->nodes[0];
+ if (p->slots[0] == btrfs_header_nritems(leaf))
+ p->slots[0]--;
+ return 0;
+ }
+ if (!return_any)
+ return 1;
+ /*
+ * no lower item found, return the next
+ * higher instead
+ */
+ return_any = 0;
+ find_higher = 1;
+ btrfs_release_path(p);
+ goto again;
+ } else {
+ --p->slots[0];
+ }
+ }
+ return 0;
+}
+
+/*
+ * Execute search and call btrfs_previous_item to traverse backwards if the item
+ * was not found.
+ *
+ * Return 0 if found, 1 if not found and < 0 if error.
+ */
+int btrfs_search_backwards(struct btrfs_root *root, struct btrfs_key *key,
+ struct btrfs_path *path)
+{
+ int ret;
+
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ if (ret > 0)
+ ret = btrfs_previous_item(root, path, key->objectid, key->type);
+
+ if (ret == 0)
+ btrfs_item_key_to_cpu(path->nodes[0], key, path->slots[0]);
+
+ return ret;
+}
+
+/*
+ * Search for a valid slot for the given path.
+ *
+ * @root: The root node of the tree.
+ * @key: Will contain a valid item if found.
+ * @path: The starting point to validate the slot.
+ *
+ * Return: 0 if the item is valid
+ * 1 if not found
+ * <0 if error.
+ */
+int btrfs_get_next_valid_item(struct btrfs_root *root, struct btrfs_key *key,
+ struct btrfs_path *path)
+{
+ while (1) {
+ int ret;
+ const int slot = path->slots[0];
+ const struct extent_buffer *leaf = path->nodes[0];
+
+ /* This is where we start walking the path. */
+ if (slot >= btrfs_header_nritems(leaf)) {
+ /*
+ * If we've reached the last slot in this leaf we need
+ * to go to the next leaf and reset the path.
+ */
+ ret = btrfs_next_leaf(root, path);
+ if (ret)
+ return ret;
+ continue;
+ }
+ /* Store the found, valid item in @key. */
+ btrfs_item_key_to_cpu(leaf, key, slot);
+ break;
+ }
+ return 0;
}
/*
@@ -1191,18 +2525,24 @@ again:
* This is used after shifting pointers to the left, so it stops
* fixing up pointers when a given leaf/node is not in slot 0 of the
* higher levels
+ *
*/
-static void fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key,
- int level)
+static void fixup_low_keys(struct btrfs_path *path,
+ struct btrfs_disk_key *key, int level)
{
int i;
struct extent_buffer *t;
+ int ret;
for (i = level; i < BTRFS_MAX_LEVEL; i++) {
int tslot = path->slots[i];
+
if (!path->nodes[i])
break;
t = path->nodes[i];
+ ret = btrfs_tree_mod_log_insert_key(t, tslot,
+ BTRFS_MOD_LOG_KEY_REPLACE);
+ BUG_ON(ret < 0);
btrfs_set_node_key(t, key, tslot);
btrfs_mark_buffer_dirty(path->nodes[i]);
if (tslot != 0)
@@ -1228,11 +2568,31 @@ void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
slot = path->slots[0];
if (slot > 0) {
btrfs_item_key(eb, &disk_key, slot - 1);
- BUG_ON(btrfs_comp_keys(&disk_key, new_key) >= 0);
+ if (unlikely(comp_keys(&disk_key, new_key) >= 0)) {
+ btrfs_crit(fs_info,
+ "slot %u key (%llu %u %llu) new key (%llu %u %llu)",
+ slot, btrfs_disk_key_objectid(&disk_key),
+ btrfs_disk_key_type(&disk_key),
+ btrfs_disk_key_offset(&disk_key),
+ new_key->objectid, new_key->type,
+ new_key->offset);
+ btrfs_print_leaf(eb);
+ BUG();
+ }
}
if (slot < btrfs_header_nritems(eb) - 1) {
btrfs_item_key(eb, &disk_key, slot + 1);
- BUG_ON(btrfs_comp_keys(&disk_key, new_key) <= 0);
+ if (unlikely(comp_keys(&disk_key, new_key) <= 0)) {
+ btrfs_crit(fs_info,
+ "slot %u key (%llu %u %llu) new key (%llu %u %llu)",
+ slot, btrfs_disk_key_objectid(&disk_key),
+ btrfs_disk_key_type(&disk_key),
+ btrfs_disk_key_offset(&disk_key),
+ new_key->objectid, new_key->type,
+ new_key->offset);
+ btrfs_print_leaf(eb);
+ BUG();
+ }
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -1242,6 +2602,58 @@ void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
fixup_low_keys(path, &disk_key, 1);
}
+/*
+ * Check key order of two sibling extent buffers.
+ *
+ * Return true if something is wrong.
+ * Return false if everything is fine.
+ *
+ * Tree-checker only works inside one tree block, thus the following
+ * corruption can not be detected by tree-checker:
+ *
+ * Leaf @left | Leaf @right
+ * --------------------------------------------------------------
+ * | 1 | 2 | 3 | 4 | 5 | f6 | | 7 | 8 |
+ *
+ * Key f6 in leaf @left itself is valid, but not valid when the next
+ * key in leaf @right is 7.
+ * This can only be checked at tree block merge time.
+ * And since tree checker has ensured all key order in each tree block
+ * is correct, we only need to bother the last key of @left and the first
+ * key of @right.
+ */
+static bool check_sibling_keys(struct extent_buffer *left,
+ struct extent_buffer *right)
+{
+ struct btrfs_key left_last;
+ struct btrfs_key right_first;
+ int level = btrfs_header_level(left);
+ int nr_left = btrfs_header_nritems(left);
+ int nr_right = btrfs_header_nritems(right);
+
+ /* No key to check in one of the tree blocks */
+ if (!nr_left || !nr_right)
+ return false;
+
+ if (level) {
+ btrfs_node_key_to_cpu(left, &left_last, nr_left - 1);
+ btrfs_node_key_to_cpu(right, &right_first, 0);
+ } else {
+ btrfs_item_key_to_cpu(left, &left_last, nr_left - 1);
+ btrfs_item_key_to_cpu(right, &right_first, 0);
+ }
+
+ if (btrfs_comp_cpu_keys(&left_last, &right_first) >= 0) {
+ btrfs_crit(left->fs_info,
+"bad key order, sibling blocks, left last (%llu %u %llu) right first (%llu %u %llu)",
+ left_last.objectid, left_last.type,
+ left_last.offset, right_first.objectid,
+ right_first.type, right_first.offset);
+ return true;
+ }
+ return false;
+}
+
/*
* try to push data from one node into the next node left in the
* tree.
@@ -1250,9 +2662,10 @@ void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
* error, and > 0 if there was no room in the left hand block.
*/
static int push_node_left(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct extent_buffer *dst,
+ struct extent_buffer *dst,
struct extent_buffer *src, int empty)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
int push_items = 0;
int src_nritems;
int dst_nritems;
@@ -1260,16 +2673,15 @@ static int push_node_left(struct btrfs_trans_handle *trans,
src_nritems = btrfs_header_nritems(src);
dst_nritems = btrfs_header_nritems(dst);
- push_items = BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - dst_nritems;
+ push_items = BTRFS_NODEPTRS_PER_BLOCK(fs_info) - dst_nritems;
WARN_ON(btrfs_header_generation(src) != trans->transid);
WARN_ON(btrfs_header_generation(dst) != trans->transid);
if (!empty && src_nritems <= 8)
return 1;
- if (push_items <= 0) {
+ if (push_items <= 0)
return 1;
- }
if (empty) {
push_items = min(src_nritems, push_items);
@@ -1286,12 +2698,27 @@ static int push_node_left(struct btrfs_trans_handle *trans,
} else
push_items = min(src_nritems - 8, push_items);
+ /* dst is the left eb, src is the middle eb */
+ if (check_sibling_keys(dst, src)) {
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ ret = btrfs_tree_mod_log_eb_copy(dst, src, dst_nritems, 0, push_items);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(dst, dst_nritems),
btrfs_node_key_ptr_offset(src, 0),
- push_items * sizeof(struct btrfs_key_ptr));
+ push_items * sizeof(struct btrfs_key_ptr));
if (push_items < src_nritems) {
+ /*
+ * Don't call btrfs_tree_mod_log_insert_move() here, key removal
+ * was already fully logged by btrfs_tree_mod_log_eb_copy() above.
+ */
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(src, 0),
btrfs_node_key_ptr_offset(src, push_items),
(src_nritems - push_items) *
@@ -1315,10 +2742,10 @@ static int push_node_left(struct btrfs_trans_handle *trans,
* this will only push up to 1/2 the contents of the left node over
*/
static int balance_node_right(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
struct extent_buffer *dst,
struct extent_buffer *src)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
int push_items = 0;
int max_push;
int src_nritems;
@@ -1330,33 +2757,44 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
src_nritems = btrfs_header_nritems(src);
dst_nritems = btrfs_header_nritems(dst);
- push_items = BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - dst_nritems;
- if (push_items <= 0) {
+ push_items = BTRFS_NODEPTRS_PER_BLOCK(fs_info) - dst_nritems;
+ if (push_items <= 0)
return 1;
- }
- if (src_nritems < 4) {
+ if (src_nritems < 4)
return 1;
- }
max_push = src_nritems / 2 + 1;
/* don't try to empty the node */
- if (max_push >= src_nritems) {
+ if (max_push >= src_nritems)
return 1;
- }
if (max_push < push_items)
push_items = max_push;
+ /* dst is the right eb, src is the middle eb */
+ if (check_sibling_keys(src, dst)) {
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ ret = btrfs_tree_mod_log_insert_move(dst, push_items, 0, dst_nritems);
+ BUG_ON(ret < 0);
memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(dst, push_items),
btrfs_node_key_ptr_offset(dst, 0),
(dst_nritems) *
sizeof(struct btrfs_key_ptr));
+ ret = btrfs_tree_mod_log_eb_copy(dst, src, 0, src_nritems - push_items,
+ push_items);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(dst, 0),
btrfs_node_key_ptr_offset(src, src_nritems - push_items),
- push_items * sizeof(struct btrfs_key_ptr));
+ push_items * sizeof(struct btrfs_key_ptr));
btrfs_set_header_nritems(src, src_nritems - push_items);
btrfs_set_header_nritems(dst, dst_nritems + push_items);
@@ -1374,15 +2812,17 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
*
* returns zero on success or < 0 on failure.
*/
-static int noinline insert_new_root(struct btrfs_trans_handle *trans,
+static noinline int insert_new_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int level)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
u64 lower_gen;
struct extent_buffer *lower;
struct extent_buffer *c;
struct extent_buffer *old;
struct btrfs_disk_key lower_key;
+ int ret;
BUG_ON(path->nodes[level]);
BUG_ON(path->nodes[level-1] != root->node);
@@ -1395,28 +2835,13 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
c = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
&lower_key, level, root->node->start, 0,
- BTRFS_NESTING_NORMAL);
-
+ BTRFS_NESTING_NEW_ROOT);
if (IS_ERR(c))
return PTR_ERR(c);
- memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
+ root_add_used(root, fs_info->nodesize);
+
btrfs_set_header_nritems(c, 1);
- btrfs_set_header_level(c, level);
- btrfs_set_header_bytenr(c, c->start);
- btrfs_set_header_generation(c, trans->transid);
- btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
- btrfs_set_header_owner(c, root->root_key.objectid);
-
- root_add_used(root, root->fs_info->nodesize);
-
- write_extent_buffer(c, root->fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
-
- write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
- btrfs_header_chunk_tree_uuid(c),
- BTRFS_UUID_SIZE);
-
btrfs_set_node_key(c, &lower_key, 0);
btrfs_set_node_blockptr(c, 0, lower->start);
lower_gen = btrfs_header_generation(lower);
@@ -1427,14 +2852,17 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(c);
old = root->node;
- root->node = c;
+ ret = btrfs_tree_mod_log_insert_root(root->node, c, false);
+ BUG_ON(ret < 0);
+ rcu_assign_pointer(root->node, c);
/* the super has an extra ref to root->node */
free_extent_buffer(old);
add_root_to_dirty_list(root);
- extent_buffer_get(c);
+ atomic_inc(&c->refs);
path->nodes[level] = c;
+ path->locks[level] = BTRFS_WRITE_LOCK;
path->slots[level] = 0;
return 0;
}
@@ -1445,37 +2873,44 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
*
* slot and level indicate where you want the key to go, and
* blocknr is the block the key points to.
- *
- * returns zero on success and < 0 on any error
*/
-static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, struct btrfs_disk_key
- *key, u64 bytenr, int slot, int level)
+static void insert_ptr(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path,
+ struct btrfs_disk_key *key, u64 bytenr,
+ int slot, int level)
{
struct extent_buffer *lower;
int nritems;
+ int ret;
BUG_ON(!path->nodes[level]);
+ btrfs_assert_tree_write_locked(path->nodes[level]);
lower = path->nodes[level];
nritems = btrfs_header_nritems(lower);
- if (slot > nritems)
- BUG();
- if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root->fs_info))
- BUG();
- if (slot < nritems) {
- /* shift the items */
+ BUG_ON(slot > nritems);
+ BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(trans->fs_info));
+ if (slot != nritems) {
+ if (level) {
+ ret = btrfs_tree_mod_log_insert_move(lower, slot + 1,
+ slot, nritems - slot);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(lower,
btrfs_node_key_ptr_offset(lower, slot + 1),
btrfs_node_key_ptr_offset(lower, slot),
(nritems - slot) * sizeof(struct btrfs_key_ptr));
}
+ if (level) {
+ ret = btrfs_tree_mod_log_insert_key(lower, slot,
+ BTRFS_MOD_LOG_KEY_ADD);
+ BUG_ON(ret < 0);
+ }
btrfs_set_node_key(lower, key, slot);
btrfs_set_node_blockptr(lower, slot, bytenr);
WARN_ON(trans->transid == 0);
btrfs_set_node_ptr_generation(lower, slot, trans->transid);
btrfs_set_header_nritems(lower, nritems + 1);
btrfs_mark_buffer_dirty(lower);
- return 0;
}
/*
@@ -1487,21 +2922,31 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
*
* returns 0 on success and < 0 on failure
*/
-static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, int level)
+static noinline int split_node(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, int level)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *c;
struct extent_buffer *split;
struct btrfs_disk_key disk_key;
int mid;
int ret;
- int wret;
u32 c_nritems;
c = path->nodes[level];
WARN_ON(btrfs_header_generation(c) != trans->transid);
if (c == root->node) {
- /* trying to split the root, lets make a new one */
+ /*
+ * trying to split the root, lets make a new one
+ *
+ * tree mod log: We don't log_removal old root in
+ * insert_new_root, because that root buffer will be kept as a
+ * normal node. We are going to log removal of half of the
+ * elements below with btrfs_tree_mod_log_eb_copy(). We're
+ * holding a tree lock on the buffer, which is why we cannot
+ * race with other tree_mod_log users.
+ */
ret = insert_new_root(trans, root, path, level + 1);
if (ret)
return ret;
@@ -1509,7 +2954,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
ret = push_nodes_for_insert(trans, root, path, level);
c = path->nodes[level];
if (!ret && btrfs_header_nritems(c) <
- BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - 3)
+ BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 3)
return 0;
if (ret < 0)
return ret;
@@ -1521,50 +2966,42 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
split = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
&disk_key, level, c->start, 0,
- BTRFS_NESTING_NORMAL);
+ BTRFS_NESTING_SPLIT);
if (IS_ERR(split))
return PTR_ERR(split);
- memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header));
- btrfs_set_header_level(split, btrfs_header_level(c));
- btrfs_set_header_bytenr(split, split->start);
- btrfs_set_header_generation(split, trans->transid);
- btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
- btrfs_set_header_owner(split, root->root_key.objectid);
- write_extent_buffer(split, root->fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
- write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
- btrfs_header_chunk_tree_uuid(split),
- BTRFS_UUID_SIZE);
-
- root_add_used(root, root->fs_info->nodesize);
+ root_add_used(root, fs_info->nodesize);
+ ASSERT(btrfs_header_level(c) == level);
+ ret = btrfs_tree_mod_log_eb_copy(split, c, 0, mid, c_nritems - mid);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
copy_extent_buffer(split, c,
btrfs_node_key_ptr_offset(split, 0),
btrfs_node_key_ptr_offset(c, mid),
(c_nritems - mid) * sizeof(struct btrfs_key_ptr));
btrfs_set_header_nritems(split, c_nritems - mid);
btrfs_set_header_nritems(c, mid);
- ret = 0;
btrfs_mark_buffer_dirty(c);
btrfs_mark_buffer_dirty(split);
- wret = insert_ptr(trans, root, path, &disk_key, split->start,
- path->slots[level + 1] + 1,
- level + 1);
- if (wret)
- ret = wret;
+ insert_ptr(trans, path, &disk_key, split->start,
+ path->slots[level + 1] + 1, level + 1);
if (path->slots[level] >= mid) {
path->slots[level] -= mid;
+ btrfs_tree_unlock(c);
free_extent_buffer(c);
path->nodes[level] = split;
path->slots[level + 1] += 1;
} else {
+ btrfs_tree_unlock(split);
free_extent_buffer(split);
}
- return ret;
+ return 0;
}
/*
@@ -1580,7 +3017,7 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
if (!nr)
return 0;
- data_len = btrfs_item_data_end(l, start);
+ data_len = btrfs_item_offset(l, start) + btrfs_item_size(l, start);
data_len = data_len - btrfs_item_offset(l, end);
data_len += sizeof(struct btrfs_item) * nr;
WARN_ON(data_len < 0);
@@ -1592,103 +3029,78 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
* the start of the leaf data. IOW, how much room
* the leaf has left for both items and data
*/
-int btrfs_leaf_free_space(struct extent_buffer *leaf)
+noinline int btrfs_leaf_free_space(struct extent_buffer *leaf)
{
+ struct btrfs_fs_info *fs_info = leaf->fs_info;
int nritems = btrfs_header_nritems(leaf);
- u32 leaf_data_size;
int ret;
- BUG_ON(!leaf->fs_info);
- BUG_ON(leaf->fs_info->nodesize != leaf->len);
- leaf_data_size = BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
- ret = leaf_data_size - leaf_space_used(leaf, 0 ,nritems);
+ ret = BTRFS_LEAF_DATA_SIZE(fs_info) - leaf_space_used(leaf, 0, nritems);
if (ret < 0) {
- printk("leaf free space ret %d, leaf data size %u, used %d nritems %d\n",
- ret, leaf_data_size, leaf_space_used(leaf, 0, nritems),
- nritems);
+ btrfs_crit(fs_info,
+ "leaf free space ret %d, leaf data size %lu, used %d nritems %d",
+ ret,
+ (unsigned long) BTRFS_LEAF_DATA_SIZE(fs_info),
+ leaf_space_used(leaf, 0, nritems), nritems);
}
return ret;
}
/*
- * push some data in the path leaf to the right, trying to free up at
- * least data_size bytes. returns zero if the push worked, nonzero otherwise
- *
- * returns 1 if the push failed because the other node didn't have enough
- * room, 0 if everything worked out and < 0 if there were major errors.
+ * min slot controls the lowest index we're willing to push to the
+ * right. We'll push up to and including min_slot, but no lower
*/
-static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, int data_size,
- int empty)
+static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path,
+ int data_size, int empty,
+ struct extent_buffer *right,
+ int free_space, u32 left_nritems,
+ u32 min_slot)
{
+ struct btrfs_fs_info *fs_info = right->fs_info;
struct extent_buffer *left = path->nodes[0];
- struct extent_buffer *right;
- struct extent_buffer *upper;
+ struct extent_buffer *upper = path->nodes[1];
+ struct btrfs_map_token token;
struct btrfs_disk_key disk_key;
int slot;
u32 i;
- int free_space;
int push_space = 0;
int push_items = 0;
- u32 left_nritems;
u32 nr;
u32 right_nritems;
u32 data_end;
u32 this_item_size;
- int ret;
-
- slot = path->slots[1];
- if (!path->nodes[1]) {
- return 1;
- }
- upper = path->nodes[1];
- if (slot >= btrfs_header_nritems(upper) - 1)
- return 1;
-
- right = btrfs_read_node_slot(upper, slot + 1);
- if (!extent_buffer_uptodate(right)) {
- if (IS_ERR(right))
- return PTR_ERR(right);
- return -EIO;
- }
- free_space = btrfs_leaf_free_space(right);
- if (free_space < data_size) {
- free_extent_buffer(right);
- return 1;
- }
-
- /* cow and double check */
- ret = btrfs_cow_block(trans, root, right, upper,
- slot + 1, &right);
- if (ret) {
- free_extent_buffer(right);
- return 1;
- }
- free_space = btrfs_leaf_free_space(right);
- if (free_space < data_size) {
- free_extent_buffer(right);
- return 1;
- }
-
- left_nritems = btrfs_header_nritems(left);
- if (left_nritems == 0) {
- free_extent_buffer(right);
- return 1;
- }
if (empty)
nr = 0;
else
- nr = 1;
+ nr = max_t(u32, 1, min_slot);
+ if (path->slots[0] >= left_nritems)
+ push_space += data_size;
+
+ slot = path->slots[1];
i = left_nritems - 1;
while (i >= nr) {
+ if (!empty && push_items > 0) {
+ if (path->slots[0] > i)
+ break;
+ if (path->slots[0] == i) {
+ int space = btrfs_leaf_free_space(left);
+
+ if (space + push_space * 2 > free_space)
+ break;
+ }
+ }
+
if (path->slots[0] == i)
- push_space += data_size + sizeof(struct btrfs_item);
+ push_space += data_size;
this_item_size = btrfs_item_size(left, i);
- if (this_item_size + sizeof(struct btrfs_item) + push_space > free_space)
+ if (this_item_size + sizeof(struct btrfs_item) +
+ push_space > free_space)
break;
+
push_items++;
push_space += this_item_size + sizeof(struct btrfs_item);
if (i == 0)
@@ -1696,13 +3108,10 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
i--;
}
- if (push_items == 0) {
- free_extent_buffer(right);
- return 1;
- }
+ if (push_items == 0)
+ goto out_unlock;
- if (!empty && push_items == left_nritems)
- WARN_ON(1);
+ WARN_ON(!empty && push_items == left_nritems);
/* push left to right */
right_nritems = btrfs_header_nritems(right);
@@ -1712,32 +3121,26 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
/* make room in the right data area */
data_end = leaf_data_end(right);
- memmove_extent_buffer(right,
- btrfs_item_nr_offset(right, 0) + data_end - push_space,
- btrfs_item_nr_offset(right, 0) + data_end,
- BTRFS_LEAF_DATA_SIZE(root->fs_info) - data_end);
+ memmove_leaf_data(right, data_end - push_space, data_end,
+ BTRFS_LEAF_DATA_SIZE(fs_info) - data_end);
/* copy from the left data area */
- copy_extent_buffer(right, left, btrfs_item_nr_offset(right, 0) +
- BTRFS_LEAF_DATA_SIZE(root->fs_info) - push_space,
- btrfs_item_nr_offset(left, 0) + leaf_data_end(left), push_space);
+ copy_leaf_data(right, left, BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
+ leaf_data_end(left), push_space);
- memmove_extent_buffer(right, btrfs_item_nr_offset(right, push_items),
- btrfs_item_nr_offset(right, 0),
- right_nritems * sizeof(struct btrfs_item));
+ memmove_leaf_items(right, push_items, 0, right_nritems);
/* copy the items from left to right */
- copy_extent_buffer(right, left, btrfs_item_nr_offset(right, 0),
- btrfs_item_nr_offset(left, left_nritems - push_items),
- push_items * sizeof(struct btrfs_item));
+ copy_leaf_items(right, left, 0, left_nritems - push_items, push_items);
/* update the item pointers */
+ btrfs_init_map_token(&token, right);
right_nritems += push_items;
btrfs_set_header_nritems(right, right_nritems);
- push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info);
+ push_space = BTRFS_LEAF_DATA_SIZE(fs_info);
for (i = 0; i < right_nritems; i++) {
- push_space -= btrfs_item_size(right, i);
- btrfs_set_item_offset(right, i, push_space);
+ push_space -= btrfs_token_item_size(&token, i);
+ btrfs_set_token_item_offset(&token, i, push_space);
}
left_nritems -= push_items;
@@ -1745,6 +3148,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
if (left_nritems)
btrfs_mark_buffer_dirty(left);
+ else
+ btrfs_clear_buffer_dirty(trans, left);
+
btrfs_mark_buffer_dirty(right);
btrfs_item_key(right, &disk_key, 0);
@@ -1754,36 +3160,259 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
/* then fixup the leaf pointer in the path */
if (path->slots[0] >= left_nritems) {
path->slots[0] -= left_nritems;
+ if (btrfs_header_nritems(path->nodes[0]) == 0)
+ btrfs_clear_buffer_dirty(trans, path->nodes[0]);
+ btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[1] += 1;
} else {
+ btrfs_tree_unlock(right);
free_extent_buffer(right);
}
return 0;
+
+out_unlock:
+ btrfs_tree_unlock(right);
+ free_extent_buffer(right);
+ return 1;
}
+
+/*
+ * push some data in the path leaf to the right, trying to free up at
+ * least data_size bytes. returns zero if the push worked, nonzero otherwise
+ *
+ * returns 1 if the push failed because the other node didn't have enough
+ * room, 0 if everything worked out and < 0 if there were major errors.
+ *
+ * this will push starting from min_slot to the end of the leaf. It won't
+ * push any slot lower than min_slot
+ */
+static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path,
+ int min_data_size, int data_size,
+ int empty, u32 min_slot)
+{
+ struct extent_buffer *left = path->nodes[0];
+ struct extent_buffer *right;
+ struct extent_buffer *upper;
+ int slot;
+ int free_space;
+ u32 left_nritems;
+ int ret;
+
+ if (!path->nodes[1])
+ return 1;
+
+ slot = path->slots[1];
+ upper = path->nodes[1];
+ if (slot >= btrfs_header_nritems(upper) - 1)
+ return 1;
+
+ btrfs_assert_tree_write_locked(path->nodes[1]);
+
+ right = btrfs_read_node_slot(upper, slot + 1);
+ if (IS_ERR(right))
+ return PTR_ERR(right);
+
+ __btrfs_tree_lock(right, BTRFS_NESTING_RIGHT);
+
+ free_space = btrfs_leaf_free_space(right);
+ if (free_space < data_size)
+ goto out_unlock;
+
+ ret = btrfs_cow_block(trans, root, right, upper,
+ slot + 1, &right, BTRFS_NESTING_RIGHT_COW);
+ if (ret)
+ goto out_unlock;
+
+ left_nritems = btrfs_header_nritems(left);
+ if (left_nritems == 0)
+ goto out_unlock;
+
+ if (check_sibling_keys(left, right)) {
+ ret = -EUCLEAN;
+ btrfs_tree_unlock(right);
+ free_extent_buffer(right);
+ return ret;
+ }
+ if (path->slots[0] == left_nritems && !empty) {
+ /* Key greater than all keys in the leaf, right neighbor has
+ * enough room for it and we're not emptying our leaf to delete
+ * it, therefore use right neighbor to insert the new item and
+ * no need to touch/dirty our left leaf. */
+ btrfs_tree_unlock(left);
+ free_extent_buffer(left);
+ path->nodes[0] = right;
+ path->slots[0] = 0;
+ path->slots[1]++;
+ return 0;
+ }
+
+ return __push_leaf_right(trans, path, min_data_size, empty, right,
+ free_space, left_nritems, min_slot);
+out_unlock:
+ btrfs_tree_unlock(right);
+ free_extent_buffer(right);
+ return 1;
+}
+
/*
* push some data in the path leaf to the left, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
+ *
+ * max_slot can put a limit on how far into the leaf we'll push items. The
+ * item at 'max_slot' won't be touched. Use (u32)-1 to make us do all the
+ * items
*/
-static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, int data_size,
- int empty)
+static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path, int data_size,
+ int empty, struct extent_buffer *left,
+ int free_space, u32 right_nritems,
+ u32 max_slot)
{
+ struct btrfs_fs_info *fs_info = left->fs_info;
struct btrfs_disk_key disk_key;
struct extent_buffer *right = path->nodes[0];
- struct extent_buffer *left;
- int slot;
int i;
- int free_space;
int push_space = 0;
int push_items = 0;
u32 old_left_nritems;
- u32 right_nritems;
u32 nr;
int ret = 0;
u32 this_item_size;
u32 old_left_item_size;
+ struct btrfs_map_token token;
+
+ if (empty)
+ nr = min(right_nritems, max_slot);
+ else
+ nr = min(right_nritems - 1, max_slot);
+
+ for (i = 0; i < nr; i++) {
+ if (!empty && push_items > 0) {
+ if (path->slots[0] < i)
+ break;
+ if (path->slots[0] == i) {
+ int space = btrfs_leaf_free_space(right);
+
+ if (space + push_space * 2 > free_space)
+ break;
+ }
+ }
+
+ if (path->slots[0] == i)
+ push_space += data_size;
+
+ this_item_size = btrfs_item_size(right, i);
+ if (this_item_size + sizeof(struct btrfs_item) + push_space >
+ free_space)
+ break;
+
+ push_items++;
+ push_space += this_item_size + sizeof(struct btrfs_item);
+ }
+
+ if (push_items == 0) {
+ ret = 1;
+ goto out;
+ }
+ WARN_ON(!empty && push_items == btrfs_header_nritems(right));
+
+ /* push data from right to left */
+ copy_leaf_items(left, right, btrfs_header_nritems(left), 0, push_items);
+
+ push_space = BTRFS_LEAF_DATA_SIZE(fs_info) -
+ btrfs_item_offset(right, push_items - 1);
+
+ copy_leaf_data(left, right, leaf_data_end(left) - push_space,
+ btrfs_item_offset(right, push_items - 1), push_space);
+ old_left_nritems = btrfs_header_nritems(left);
+ BUG_ON(old_left_nritems <= 0);
+
+ btrfs_init_map_token(&token, left);
+ old_left_item_size = btrfs_item_offset(left, old_left_nritems - 1);
+ for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
+ u32 ioff;
+
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i,
+ ioff - (BTRFS_LEAF_DATA_SIZE(fs_info) - old_left_item_size));
+ }
+ btrfs_set_header_nritems(left, old_left_nritems + push_items);
+
+ /* fixup right node */
+ if (push_items > right_nritems)
+ WARN(1, KERN_CRIT "push items %d nr %u\n", push_items,
+ right_nritems);
+
+ if (push_items < right_nritems) {
+ push_space = btrfs_item_offset(right, push_items - 1) -
+ leaf_data_end(right);
+ memmove_leaf_data(right,
+ BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
+ leaf_data_end(right), push_space);
+
+ memmove_leaf_items(right, 0, push_items,
+ btrfs_header_nritems(right) - push_items);
+ }
+
+ btrfs_init_map_token(&token, right);
+ right_nritems -= push_items;
+ btrfs_set_header_nritems(right, right_nritems);
+ push_space = BTRFS_LEAF_DATA_SIZE(fs_info);
+ for (i = 0; i < right_nritems; i++) {
+ push_space = push_space - btrfs_token_item_size(&token, i);
+ btrfs_set_token_item_offset(&token, i, push_space);
+ }
+
+ btrfs_mark_buffer_dirty(left);
+ if (right_nritems)
+ btrfs_mark_buffer_dirty(right);
+ else
+ btrfs_clear_buffer_dirty(trans, right);
+
+ btrfs_item_key(right, &disk_key, 0);
+ fixup_low_keys(path, &disk_key, 1);
+
+ /* then fixup the leaf pointer in the path */
+ if (path->slots[0] < push_items) {
+ path->slots[0] += old_left_nritems;
+ btrfs_tree_unlock(path->nodes[0]);
+ free_extent_buffer(path->nodes[0]);
+ path->nodes[0] = left;
+ path->slots[1] -= 1;
+ } else {
+ btrfs_tree_unlock(left);
+ free_extent_buffer(left);
+ path->slots[0] -= push_items;
+ }
+ BUG_ON(path->slots[0] < 0);
+ return ret;
+out:
+ btrfs_tree_unlock(left);
+ free_extent_buffer(left);
+ return ret;
+}
+
+/*
+ * push some data in the path leaf to the left, trying to free up at
+ * least data_size bytes. returns zero if the push worked, nonzero otherwise
+ *
+ * max_slot can put a limit on how far into the leaf we'll push items. The
+ * item at 'max_slot' won't be touched. Use (u32)-1 to make us push all the
+ * items
+ */
+static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int min_data_size,
+ int data_size, int empty, u32 max_slot)
+{
+ struct extent_buffer *right = path->nodes[0];
+ struct extent_buffer *left;
+ int slot;
+ int free_space;
+ u32 right_nritems;
+ int ret = 0;
slot = path->slots[1];
if (slot == 0)
@@ -1792,198 +3421,165 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
return 1;
right_nritems = btrfs_header_nritems(right);
- if (right_nritems == 0) {
+ if (right_nritems == 0)
return 1;
- }
+
+ btrfs_assert_tree_write_locked(path->nodes[1]);
left = btrfs_read_node_slot(path->nodes[1], slot - 1);
+ if (IS_ERR(left))
+ return PTR_ERR(left);
+
+ __btrfs_tree_lock(left, BTRFS_NESTING_LEFT);
+
free_space = btrfs_leaf_free_space(left);
if (free_space < data_size) {
- free_extent_buffer(left);
- return 1;
+ ret = 1;
+ goto out;
}
- /* cow and double check */
ret = btrfs_cow_block(trans, root, left,
- path->nodes[1], slot - 1, &left);
+ path->nodes[1], slot - 1, &left,
+ BTRFS_NESTING_LEFT_COW);
if (ret) {
/* we hit -ENOSPC, but it isn't fatal here */
- free_extent_buffer(left);
- return 1;
+ if (ret == -ENOSPC)
+ ret = 1;
+ goto out;
}
- free_space = btrfs_leaf_free_space(left);
- if (free_space < data_size) {
- free_extent_buffer(left);
- return 1;
+ if (check_sibling_keys(left, right)) {
+ ret = -EUCLEAN;
+ goto out;
}
-
- if (empty)
- nr = right_nritems;
- else
- nr = right_nritems - 1;
-
- for (i = 0; i < nr; i++) {
- if (path->slots[0] == i)
- push_space += data_size + sizeof(struct btrfs_item);
-
- this_item_size = btrfs_item_size(right, i);
- if (this_item_size + sizeof(struct btrfs_item) + push_space > free_space)
- break;
-
- push_items++;
- push_space += this_item_size + sizeof(struct btrfs_item);
- }
-
- if (push_items == 0) {
- free_extent_buffer(left);
- return 1;
- }
- if (!empty && push_items == btrfs_header_nritems(right))
- WARN_ON(1);
-
- /* push data from right to left */
- copy_extent_buffer(left, right,
- btrfs_item_nr_offset(left, btrfs_header_nritems(left)),
- btrfs_item_nr_offset(right, 0),
- push_items * sizeof(struct btrfs_item));
-
- push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info) -
- btrfs_item_offset(right, push_items -1);
-
- copy_extent_buffer(left, right, btrfs_item_nr_offset(left, 0) +
- leaf_data_end(left) - push_space,
- btrfs_item_nr_offset(right, 0) +
- btrfs_item_offset(right, push_items - 1),
- push_space);
- old_left_nritems = btrfs_header_nritems(left);
- BUG_ON(old_left_nritems == 0);
-
- old_left_item_size = btrfs_item_offset(left, old_left_nritems - 1);
- for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
- u32 ioff;
-
- ioff = btrfs_item_offset(left, i);
- btrfs_set_item_offset(left, i,
- ioff - (BTRFS_LEAF_DATA_SIZE(root->fs_info) -
- old_left_item_size));
- }
- btrfs_set_header_nritems(left, old_left_nritems + push_items);
-
- /* fixup right node */
- if (push_items > right_nritems) {
- printk("push items %d nr %u\n", push_items, right_nritems);
- WARN_ON(1);
- }
-
- if (push_items < right_nritems) {
- push_space = btrfs_item_offset(right, push_items - 1) -
- leaf_data_end(right);
- memmove_extent_buffer(right, btrfs_item_nr_offset(right, 0) +
- BTRFS_LEAF_DATA_SIZE(root->fs_info) -
- push_space,
- btrfs_item_nr_offset(right, 0) +
- leaf_data_end(right), push_space);
-
- memmove_extent_buffer(right, btrfs_item_nr_offset(right, 0),
- btrfs_item_nr_offset(right, push_items),
- (btrfs_header_nritems(right) - push_items) *
- sizeof(struct btrfs_item));
- }
- right_nritems -= push_items;
- btrfs_set_header_nritems(right, right_nritems);
- push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info);
- for (i = 0; i < right_nritems; i++) {
- push_space = push_space - btrfs_item_size(right, i);
- btrfs_set_item_offset(right, i, push_space);
- }
-
- btrfs_mark_buffer_dirty(left);
- if (right_nritems)
- btrfs_mark_buffer_dirty(right);
-
- btrfs_item_key(right, &disk_key, 0);
- fixup_low_keys(path, &disk_key, 1);
-
- /* then fixup the leaf pointer in the path */
- if (path->slots[0] < push_items) {
- path->slots[0] += old_left_nritems;
- free_extent_buffer(path->nodes[0]);
- path->nodes[0] = left;
- path->slots[1] -= 1;
- } else {
- free_extent_buffer(left);
- path->slots[0] -= push_items;
- }
- BUG_ON(path->slots[0] < 0);
+ return __push_leaf_left(trans, path, min_data_size, empty, left,
+ free_space, right_nritems, max_slot);
+out:
+ btrfs_tree_unlock(left);
+ free_extent_buffer(left);
return ret;
}
/*
* split the path's leaf in two, making sure there is at least data_size
* available for the resulting leaf level of the path.
- *
- * returns 0 if all went well and < 0 on failure.
*/
-static noinline int copy_for_split(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct extent_buffer *l,
- struct extent_buffer *right,
- int slot, int mid, int nritems)
+static noinline void copy_for_split(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path,
+ struct extent_buffer *l,
+ struct extent_buffer *right,
+ int slot, int mid, int nritems)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
int data_copy_size;
int rt_data_off;
int i;
- int ret = 0;
- int wret;
struct btrfs_disk_key disk_key;
+ struct btrfs_map_token token;
nritems = nritems - mid;
btrfs_set_header_nritems(right, nritems);
data_copy_size = btrfs_item_data_end(l, mid) - leaf_data_end(l);
- copy_extent_buffer(right, l, btrfs_item_nr_offset(right, 0),
- btrfs_item_nr_offset(l, mid),
- nritems * sizeof(struct btrfs_item));
+ copy_leaf_items(right, l, 0, mid, nritems);
- copy_extent_buffer(right, l,
- btrfs_item_nr_offset(right, 0) +
- BTRFS_LEAF_DATA_SIZE(root->fs_info) - data_copy_size,
- btrfs_item_nr_offset(l, 0) + leaf_data_end(l), data_copy_size);
+ copy_leaf_data(right, l, BTRFS_LEAF_DATA_SIZE(fs_info) - data_copy_size,
+ leaf_data_end(l), data_copy_size);
- rt_data_off = BTRFS_LEAF_DATA_SIZE(root->fs_info) -
- btrfs_item_data_end(l, mid);
+ rt_data_off = BTRFS_LEAF_DATA_SIZE(fs_info) - btrfs_item_data_end(l, mid);
+ btrfs_init_map_token(&token, right);
for (i = 0; i < nritems; i++) {
- u32 ioff = btrfs_item_offset(right, i);
- btrfs_set_item_offset(right, i, ioff + rt_data_off);
+ u32 ioff;
+
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i, ioff + rt_data_off);
}
btrfs_set_header_nritems(l, mid);
- ret = 0;
btrfs_item_key(right, &disk_key, 0);
- wret = insert_ptr(trans, root, path, &disk_key, right->start,
- path->slots[1] + 1, 1);
- if (wret)
- ret = wret;
+ insert_ptr(trans, path, &disk_key, right->start, path->slots[1] + 1, 1);
btrfs_mark_buffer_dirty(right);
btrfs_mark_buffer_dirty(l);
BUG_ON(path->slots[0] != slot);
if (mid <= slot) {
+ btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] -= mid;
path->slots[1] += 1;
} else {
+ btrfs_tree_unlock(right);
free_extent_buffer(right);
}
BUG_ON(path->slots[0] < 0);
+}
- return ret;
+/*
+ * double splits happen when we need to insert a big item in the middle
+ * of a leaf. A double split can leave us with 3 mostly empty leaves:
+ * leaf: [ slots 0 - N] [ our target ] [ N + 1 - total in leaf ]
+ * A B C
+ *
+ * We avoid this by trying to push the items on either side of our target
+ * into the adjacent leaves. If all goes well we can avoid the double split
+ * completely.
+ */
+static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ int data_size)
+{
+ int ret;
+ int progress = 0;
+ int slot;
+ u32 nritems;
+ int space_needed = data_size;
+
+ slot = path->slots[0];
+ if (slot < btrfs_header_nritems(path->nodes[0]))
+ space_needed -= btrfs_leaf_free_space(path->nodes[0]);
+
+ /*
+ * try to push all the items after our slot into the
+ * right leaf
+ */
+ ret = push_leaf_right(trans, root, path, 1, space_needed, 0, slot);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ progress++;
+
+ nritems = btrfs_header_nritems(path->nodes[0]);
+ /*
+ * our goal is to get our slot at the start or end of a leaf. If
+ * we've done so we're done
+ */
+ if (path->slots[0] == 0 || path->slots[0] == nritems)
+ return 0;
+
+ if (btrfs_leaf_free_space(path->nodes[0]) >= data_size)
+ return 0;
+
+ /* try to push all the items before our slot into the next leaf */
+ slot = path->slots[0];
+ space_needed = data_size;
+ if (slot > 0)
+ space_needed -= btrfs_leaf_free_space(path->nodes[0]);
+ ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ progress++;
+
+ if (progress)
+ return 0;
+ return 1;
}
/*
@@ -2004,24 +3600,36 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
int mid;
int slot;
struct extent_buffer *right;
+ struct btrfs_fs_info *fs_info = root->fs_info;
int ret = 0;
int wret;
int split;
int num_doubles = 0;
+ int tried_avoid_double = 0;
l = path->nodes[0];
slot = path->slots[0];
if (extend && data_size + btrfs_item_size(l, slot) +
- sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info))
+ sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(fs_info))
return -EOVERFLOW;
/* first try to make some room by pushing left and right */
- if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
- wret = push_leaf_right(trans, root, path, data_size, 0);
+ if (data_size && path->nodes[1]) {
+ int space_needed = data_size;
+
+ if (slot < btrfs_header_nritems(l))
+ space_needed -= btrfs_leaf_free_space(l);
+
+ wret = push_leaf_right(trans, root, path, space_needed,
+ space_needed, 0, 0);
if (wret < 0)
return wret;
if (wret) {
- wret = push_leaf_left(trans, root, path, data_size, 0);
+ space_needed = data_size;
+ if (slot > 0)
+ space_needed -= btrfs_leaf_free_space(l);
+ wret = push_leaf_left(trans, root, path, space_needed,
+ space_needed, 0, (u32)-1);
if (wret < 0)
return wret;
}
@@ -2047,22 +3655,23 @@ again:
if (mid <= slot) {
if (nritems == 1 ||
leaf_space_used(l, mid, nritems - mid) + data_size >
- BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
+ BTRFS_LEAF_DATA_SIZE(fs_info)) {
if (slot >= nritems) {
split = 0;
} else {
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
- data_size >
- BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
+ data_size > BTRFS_LEAF_DATA_SIZE(fs_info)) {
+ if (data_size && !tried_avoid_double)
+ goto push_for_double;
split = 2;
}
}
}
} else {
if (leaf_space_used(l, 0, mid) + data_size >
- BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
+ BTRFS_LEAF_DATA_SIZE(fs_info)) {
if (!extend && data_size && slot == 0) {
split = 0;
} else if ((extend || !data_size) && slot == 0) {
@@ -2071,9 +3680,10 @@ again:
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
- data_size >
- BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
- split = 2 ;
+ data_size > BTRFS_LEAF_DATA_SIZE(fs_info)) {
+ if (data_size && !tried_avoid_double)
+ goto push_for_double;
+ split = 2;
}
}
}
@@ -2084,62 +3694,53 @@ again:
else
btrfs_item_key(l, &disk_key, mid);
+ /*
+ * We have to about BTRFS_NESTING_NEW_ROOT here if we've done a double
+ * split, because we're only allowed to have MAX_LOCKDEP_SUBCLASSES
+ * subclasses, which is 8 at the time of this patch, and we've maxed it
+ * out. In the future we could add a
+ * BTRFS_NESTING_SPLIT_THE_SPLITTENING if we need to, but for now just
+ * use BTRFS_NESTING_NEW_ROOT.
+ */
right = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
&disk_key, 0, l->start, 0,
- BTRFS_NESTING_NORMAL);
- if (IS_ERR(right)) {
- BUG_ON(1);
+ num_doubles ? BTRFS_NESTING_NEW_ROOT :
+ BTRFS_NESTING_SPLIT);
+ if (IS_ERR(right))
return PTR_ERR(right);
- }
- memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
- btrfs_set_header_bytenr(right, right->start);
- btrfs_set_header_generation(right, trans->transid);
- btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV);
- btrfs_set_header_owner(right, root->root_key.objectid);
- btrfs_set_header_level(right, 0);
- write_extent_buffer(right, root->fs_info->fs_devices->metadata_uuid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
-
- write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
- btrfs_header_chunk_tree_uuid(right),
- BTRFS_UUID_SIZE);
-
- root_add_used(root, root->fs_info->nodesize);
+ root_add_used(root, fs_info->nodesize);
if (split == 0) {
if (mid <= slot) {
btrfs_set_header_nritems(right, 0);
- wret = insert_ptr(trans, root, path,
- &disk_key, right->start,
- path->slots[1] + 1, 1);
- if (wret)
- ret = wret;
-
+ insert_ptr(trans, path, &disk_key,
+ right->start, path->slots[1] + 1, 1);
+ btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
path->slots[1] += 1;
} else {
btrfs_set_header_nritems(right, 0);
- wret = insert_ptr(trans, root, path,
- &disk_key,
- right->start,
- path->slots[1], 1);
- if (wret)
- ret = wret;
+ insert_ptr(trans, path, &disk_key,
+ right->start, path->slots[1], 1);
+ btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
if (path->slots[1] == 0)
fixup_low_keys(path, &disk_key, 1);
}
- btrfs_mark_buffer_dirty(right);
+ /*
+ * We create a new leaf 'right' for the required ins_len and
+ * we'll do btrfs_mark_buffer_dirty() on this leaf after copying
+ * the content of ins_len to 'right'.
+ */
return ret;
}
- ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems);
- BUG_ON(ret);
+ copy_for_split(trans, path, l, right, slot, mid, nritems);
if (split == 2) {
BUG_ON(num_doubles != 0);
@@ -2147,9 +3748,143 @@ again:
goto again;
}
+ return 0;
+
+push_for_double:
+ push_for_double_split(trans, root, path, data_size);
+ tried_avoid_double = 1;
+ if (btrfs_leaf_free_space(path->nodes[0]) >= data_size)
+ return 0;
+ goto again;
+}
+
+static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, int ins_len)
+{
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ struct btrfs_file_extent_item *fi;
+ u64 extent_len = 0;
+ u32 item_size;
+ int ret;
+
+ leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+
+ BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY &&
+ key.type != BTRFS_EXTENT_CSUM_KEY);
+
+ if (btrfs_leaf_free_space(leaf) >= ins_len)
+ return 0;
+
+ item_size = btrfs_item_size(leaf, path->slots[0]);
+ if (key.type == BTRFS_EXTENT_DATA_KEY) {
+ fi = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ extent_len = btrfs_file_extent_num_bytes(leaf, fi);
+ }
+ btrfs_release_path(path);
+
+ path->keep_locks = 1;
+ path->search_for_split = 1;
+ ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ path->search_for_split = 0;
+ if (ret > 0)
+ ret = -EAGAIN;
+ if (ret < 0)
+ goto err;
+
+ ret = -EAGAIN;
+ leaf = path->nodes[0];
+ /* if our item isn't there, return now */
+ if (item_size != btrfs_item_size(leaf, path->slots[0]))
+ goto err;
+
+ /* the leaf has changed, it now has room. return now */
+ if (btrfs_leaf_free_space(path->nodes[0]) >= ins_len)
+ goto err;
+
+ if (key.type == BTRFS_EXTENT_DATA_KEY) {
+ fi = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ if (extent_len != btrfs_file_extent_num_bytes(leaf, fi))
+ goto err;
+ }
+
+ ret = split_leaf(trans, root, &key, path, ins_len, 1);
+ if (ret)
+ goto err;
+
+ path->keep_locks = 0;
+ btrfs_unlock_up_safe(path, 1);
+ return 0;
+err:
+ path->keep_locks = 0;
return ret;
}
+static noinline int split_item(struct btrfs_path *path,
+ const struct btrfs_key *new_key,
+ unsigned long split_offset)
+{
+ struct extent_buffer *leaf;
+ int orig_slot, slot;
+ char *buf;
+ u32 nritems;
+ u32 item_size;
+ u32 orig_offset;
+ struct btrfs_disk_key disk_key;
+
+ leaf = path->nodes[0];
+ BUG_ON(btrfs_leaf_free_space(leaf) < sizeof(struct btrfs_item));
+
+ orig_slot = path->slots[0];
+ orig_offset = btrfs_item_offset(leaf, path->slots[0]);
+ item_size = btrfs_item_size(leaf, path->slots[0]);
+
+ buf = kmalloc(item_size, GFP_NOFS);
+ if (!buf)
+ return -ENOMEM;
+
+ read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
+ path->slots[0]), item_size);
+
+ slot = path->slots[0] + 1;
+ nritems = btrfs_header_nritems(leaf);
+ if (slot != nritems) {
+ /* shift the items */
+ memmove_leaf_items(leaf, slot + 1, slot, nritems - slot);
+ }
+
+ btrfs_cpu_key_to_disk(&disk_key, new_key);
+ btrfs_set_item_key(leaf, &disk_key, slot);
+
+ btrfs_set_item_offset(leaf, slot, orig_offset);
+ btrfs_set_item_size(leaf, slot, item_size - split_offset);
+
+ btrfs_set_item_offset(leaf, orig_slot,
+ orig_offset + item_size - split_offset);
+ btrfs_set_item_size(leaf, orig_slot, split_offset);
+
+ btrfs_set_header_nritems(leaf, nritems + 1);
+
+ /* write the data for the start of the original item */
+ write_extent_buffer(leaf, buf,
+ btrfs_item_ptr_offset(leaf, path->slots[0]),
+ split_offset);
+
+ /* write the data for the new item */
+ write_extent_buffer(leaf, buf + split_offset,
+ btrfs_item_ptr_offset(leaf, slot),
+ item_size - split_offset);
+ btrfs_mark_buffer_dirty(leaf);
+
+ BUG_ON(btrfs_leaf_free_space(leaf) < 0);
+ kfree(buf);
+ return 0;
+}
+
/*
* This function splits a single item into two items,
* giving 'new_key' to the new item and splitting the
@@ -2168,99 +3903,25 @@ again:
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct btrfs_key *new_key,
+ const struct btrfs_key *new_key,
unsigned long split_offset)
{
- u32 item_size;
- struct extent_buffer *leaf;
- struct btrfs_key orig_key;
- int ret = 0;
- int slot;
- u32 nritems;
- u32 orig_offset;
- struct btrfs_disk_key disk_key;
- char *buf;
+ int ret;
+ ret = setup_leaf_for_split(trans, root, path,
+ sizeof(struct btrfs_item));
+ if (ret)
+ return ret;
- leaf = path->nodes[0];
- btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
- if (btrfs_leaf_free_space(leaf) >=
- sizeof(struct btrfs_item))
- goto split;
-
- item_size = btrfs_item_size(leaf, path->slots[0]);
- btrfs_release_path(path);
-
- path->search_for_split = 1;
-
- ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
- path->search_for_split = 0;
-
- /* if our item isn't there or got smaller, return now */
- if (ret != 0 || item_size != btrfs_item_size(path->nodes[0],
- path->slots[0])) {
- return -EAGAIN;
- }
-
- ret = split_leaf(trans, root, &orig_key, path, 0, 0);
- BUG_ON(ret);
-
- BUG_ON(btrfs_leaf_free_space(leaf) < sizeof(struct btrfs_item));
- leaf = path->nodes[0];
-
-split:
- orig_offset = btrfs_item_offset(leaf, path->slots[0]);
- item_size = btrfs_item_size(leaf, path->slots[0]);
-
-
- buf = kmalloc(item_size, GFP_NOFS);
- BUG_ON(!buf);
- read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
- path->slots[0]), item_size);
- slot = path->slots[0] + 1;
- leaf = path->nodes[0];
-
- nritems = btrfs_header_nritems(leaf);
-
- if (slot < nritems) {
- /* shift the items */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot + 1),
- btrfs_item_nr_offset(leaf, slot),
- (nritems - slot) * sizeof(struct btrfs_item));
-
- }
-
- btrfs_cpu_key_to_disk(&disk_key, new_key);
- btrfs_set_item_key(leaf, &disk_key, slot);
-
- btrfs_set_item_offset(leaf, slot, orig_offset);
- btrfs_set_item_size(leaf, slot, item_size - split_offset);
-
- btrfs_set_item_offset(leaf, path->slots[0],
- orig_offset + item_size - split_offset);
- btrfs_set_item_size(leaf, path->slots[0], split_offset);
-
- btrfs_set_header_nritems(leaf, nritems + 1);
-
- /* write the data for the start of the original item */
- write_extent_buffer(leaf, buf,
- btrfs_item_ptr_offset(leaf, path->slots[0]),
- split_offset);
-
- /* write the data for the new item */
- write_extent_buffer(leaf, buf + split_offset,
- btrfs_item_ptr_offset(leaf, slot),
- item_size - split_offset);
- btrfs_mark_buffer_dirty(leaf);
-
- ret = 0;
- if (btrfs_leaf_free_space(leaf) < 0) {
- btrfs_print_leaf(leaf);
- BUG();
- }
- kfree(buf);
+ ret = split_item(path, new_key, split_offset);
return ret;
}
+/*
+ * make the item pointed to by the path smaller. new_size indicates
+ * how small to make it, and from_end tells us if we just chop bytes
+ * off the end of the item or if we shift the item to chop bytes off
+ * the front.
+ */
void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
{
int slot;
@@ -2271,6 +3932,7 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
unsigned int old_size;
unsigned int size_diff;
int i;
+ struct btrfs_map_token token;
leaf = path->nodes[0];
slot = path->slots[0];
@@ -2293,17 +3955,18 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
* item0..itemN ... dataN.offset..dataN.size .. data0.size
*/
/* first correct the data pointers */
+ btrfs_init_map_token(&token, leaf);
for (i = slot; i < nritems; i++) {
u32 ioff;
- ioff = btrfs_item_offset(leaf, i);
- btrfs_set_item_offset(leaf, i, ioff + size_diff);
+
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i, ioff + size_diff);
}
/* shift the data */
if (from_end) {
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) +
- data_end + size_diff, btrfs_item_nr_offset(leaf, 0) +
- data_end, old_data_start + new_size - data_end);
+ memmove_leaf_data(leaf, data_end + size_diff, data_end,
+ old_data_start + new_size - data_end);
} else {
struct btrfs_disk_key disk_key;
u64 offset;
@@ -2323,15 +3986,13 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
BTRFS_FILE_EXTENT_INLINE) {
ptr = btrfs_item_ptr_offset(leaf, slot);
memmove_extent_buffer(leaf, ptr,
- (unsigned long)fi,
- offsetof(struct btrfs_file_extent_item,
- disk_bytenr));
+ (unsigned long)fi,
+ BTRFS_FILE_EXTENT_INLINE_DATA_START);
}
}
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) +
- data_end + size_diff, btrfs_item_nr_offset(leaf, 0) +
- data_end, old_data_start - data_end);
+ memmove_leaf_data(leaf, data_end + size_diff, data_end,
+ old_data_start - data_end);
offset = btrfs_disk_key_offset(&disk_key);
btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
@@ -2349,6 +4010,9 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
}
}
+/*
+ * make the item pointed to by the path bigger, data_size is the added size.
+ */
void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
{
int slot;
@@ -2358,6 +4022,7 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
unsigned int old_data;
unsigned int old_size;
int i;
+ struct btrfs_map_token token;
leaf = path->nodes[0];
@@ -2374,24 +4039,26 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
BUG_ON(slot < 0);
if (slot >= nritems) {
btrfs_print_leaf(leaf);
- printk("slot %d too large, nritems %u\n", slot, nritems);
- BUG_ON(1);
+ btrfs_crit(leaf->fs_info, "slot %d too large, nritems %d",
+ slot, nritems);
+ BUG();
}
/*
* item0..itemN ... dataN.offset..dataN.size .. data0.size
*/
/* first correct the data pointers */
+ btrfs_init_map_token(&token, leaf);
for (i = slot; i < nritems; i++) {
u32 ioff;
- ioff = btrfs_item_offset(leaf, i);
- btrfs_set_item_offset(leaf, i, ioff - data_size);
+
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i, ioff - data_size);
}
/* shift the data */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) +
- data_end - data_size, btrfs_item_nr_offset(leaf, 0) +
- data_end, old_data - data_end);
+ memmove_leaf_data(leaf, data_end - data_size, data_end,
+ old_data - data_end);
data_end = old_data;
old_size = btrfs_item_size(leaf, slot);
@@ -2405,64 +4072,63 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
}
/*
- * Given a key and some data, insert an item into the tree.
- * This does all the path init required, making room in the tree if needed.
+ * Make space in the node before inserting one or more items.
+ *
+ * @root: root we are inserting items to
+ * @path: points to the leaf/slot where we are going to insert new items
+ * @batch: information about the batch of items to insert
+ *
+ * Main purpose is to save stack depth by doing the bulk of the work in a
+ * function that doesn't call btrfs_search_slot
*/
-int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct btrfs_key *cpu_key, u32 *data_size,
- int nr)
+static void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
+ const struct btrfs_item_batch *batch)
{
- struct extent_buffer *leaf;
- int ret = 0;
- int slot;
+ struct btrfs_fs_info *fs_info = root->fs_info;
int i;
u32 nritems;
- u32 total_size = 0;
- u32 total_data = 0;
unsigned int data_end;
struct btrfs_disk_key disk_key;
+ struct extent_buffer *leaf;
+ int slot;
+ struct btrfs_map_token token;
+ u32 total_size;
- for (i = 0; i < nr; i++) {
- total_data += data_size[i];
+ /*
+ * Before anything else, update keys in the parent and other ancestors
+ * if needed, then release the write locks on them, so that other tasks
+ * can use them while we modify the leaf.
+ */
+ if (path->slots[0] == 0) {
+ btrfs_cpu_key_to_disk(&disk_key, &batch->keys[0]);
+ fixup_low_keys(path, &disk_key, 1);
}
-
- /* create a root if there isn't one */
- if (!root->node)
- BUG();
-
- total_size = total_data + nr * sizeof(struct btrfs_item);
- ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
- if (ret == 0) {
- return -EEXIST;
- }
- if (ret < 0)
- goto out;
+ btrfs_unlock_up_safe(path, 1);
leaf = path->nodes[0];
+ slot = path->slots[0];
nritems = btrfs_header_nritems(leaf);
data_end = leaf_data_end(leaf);
+ total_size = batch->total_data_size + (batch->nr * sizeof(struct btrfs_item));
if (btrfs_leaf_free_space(leaf) < total_size) {
btrfs_print_leaf(leaf);
- printk("not enough freespace need %u have %d\n",
- total_size, btrfs_leaf_free_space(leaf));
+ btrfs_crit(fs_info, "not enough freespace need %u have %d",
+ total_size, btrfs_leaf_free_space(leaf));
BUG();
}
- slot = path->slots[0];
- BUG_ON(slot < 0);
-
- if (slot < nritems) {
+ btrfs_init_map_token(&token, leaf);
+ if (slot != nritems) {
unsigned int old_data = btrfs_item_data_end(leaf, slot);
if (old_data < data_end) {
btrfs_print_leaf(leaf);
- printk("slot %d old_data %u data_end %u\n",
- slot, old_data, data_end);
- BUG_ON(1);
+ btrfs_crit(fs_info,
+ "item at slot %d with data offset %u beyond data end of leaf %u",
+ slot, old_data, data_end);
+ BUG();
}
/*
* item0..itemN ... dataN.offset..dataN.size .. data0.size
@@ -2471,55 +4137,94 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
for (i = slot; i < nritems; i++) {
u32 ioff;
- ioff = btrfs_item_offset(leaf, i);
- btrfs_set_item_offset(leaf, i, ioff - total_data);
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i,
+ ioff - batch->total_data_size);
}
-
/* shift the items */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot + nr),
- btrfs_item_nr_offset(leaf, slot),
- (nritems - slot) * sizeof(struct btrfs_item));
+ memmove_leaf_items(leaf, slot + batch->nr, slot, nritems - slot);
/* shift the data */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) +
- data_end - total_data, btrfs_item_nr_offset(leaf, 0) +
- data_end, old_data - data_end);
+ memmove_leaf_data(leaf, data_end - batch->total_data_size,
+ data_end, old_data - data_end);
data_end = old_data;
}
/* setup the item for the new data */
- for (i = 0; i < nr; i++) {
- btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
+ for (i = 0; i < batch->nr; i++) {
+ btrfs_cpu_key_to_disk(&disk_key, &batch->keys[i]);
btrfs_set_item_key(leaf, &disk_key, slot + i);
- btrfs_set_item_offset(leaf, slot + i, data_end - data_size[i]);
- data_end -= data_size[i];
- btrfs_set_item_size(leaf, slot + i, data_size[i]);
+ data_end -= batch->data_sizes[i];
+ btrfs_set_token_item_offset(&token, slot + i, data_end);
+ btrfs_set_token_item_size(&token, slot + i, batch->data_sizes[i]);
}
- btrfs_set_header_nritems(leaf, nritems + nr);
- btrfs_mark_buffer_dirty(leaf);
- ret = 0;
- if (slot == 0) {
- btrfs_cpu_key_to_disk(&disk_key, cpu_key);
- fixup_low_keys(path, &disk_key, 1);
- }
+ btrfs_set_header_nritems(leaf, nritems + batch->nr);
+ btrfs_mark_buffer_dirty(leaf);
if (btrfs_leaf_free_space(leaf) < 0) {
btrfs_print_leaf(leaf);
BUG();
}
+}
-out:
- return ret;
+/*
+ * Insert a new item into a leaf.
+ *
+ * @root: The root of the btree.
+ * @path: A path pointing to the target leaf and slot.
+ * @key: The key of the new item.
+ * @data_size: The size of the data associated with the new key.
+ */
+void btrfs_setup_item_for_insert(struct btrfs_root *root,
+ struct btrfs_path *path,
+ const struct btrfs_key *key,
+ u32 data_size)
+{
+ struct btrfs_item_batch batch;
+
+ batch.keys = key;
+ batch.data_sizes = &data_size;
+ batch.total_data_size = data_size;
+ batch.nr = 1;
+
+ setup_items_for_insert(root, path, &batch);
+}
+
+/*
+ * Given a key and some data, insert items into the tree.
+ * This does all the path init required, making room in the tree if needed.
+ */
+int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const struct btrfs_item_batch *batch)
+{
+ int ret = 0;
+ int slot;
+ u32 total_size;
+
+ total_size = batch->total_data_size + (batch->nr * sizeof(struct btrfs_item));
+ ret = btrfs_search_slot(trans, root, &batch->keys[0], path, total_size, 1);
+ if (ret == 0)
+ return -EEXIST;
+ if (ret < 0)
+ return ret;
+
+ slot = path->slots[0];
+ BUG_ON(slot < 0);
+
+ setup_items_for_insert(root, path, batch);
+ return 0;
}
/*
* Given a key and some data, insert an item into the tree.
* This does all the path init required, making room in the tree if needed.
*/
-int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_key *cpu_key, void *data, u32
- data_size)
+int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ const struct btrfs_key *cpu_key, void *data,
+ u32 data_size)
{
int ret = 0;
struct btrfs_path *path;
@@ -2529,7 +4234,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
-
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
if (!ret) {
leaf = path->nodes[0];
@@ -2541,28 +4245,73 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
return ret;
}
+/*
+ * This function duplicates an item, giving 'new_key' to the new item.
+ * It guarantees both items live in the same tree leaf and the new item is
+ * contiguous with the original item.
+ *
+ * This allows us to split a file extent in place, keeping a lock on the leaf
+ * the entire time.
+ */
+int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const struct btrfs_key *new_key)
+{
+ struct extent_buffer *leaf;
+ int ret;
+ u32 item_size;
+
+ leaf = path->nodes[0];
+ item_size = btrfs_item_size(leaf, path->slots[0]);
+ ret = setup_leaf_for_split(trans, root, path,
+ item_size + sizeof(struct btrfs_item));
+ if (ret)
+ return ret;
+
+ path->slots[0]++;
+ btrfs_setup_item_for_insert(root, path, new_key, item_size);
+ leaf = path->nodes[0];
+ memcpy_extent_buffer(leaf,
+ btrfs_item_ptr_offset(leaf, path->slots[0]),
+ btrfs_item_ptr_offset(leaf, path->slots[0] - 1),
+ item_size);
+ return 0;
+}
+
/*
* delete the pointer from a given node.
*
- * If the delete empties a node, the node is removed from the tree,
- * continuing all the way the root if required. The root is converted into
- * a leaf if all the nodes are emptied.
+ * the tree should have been previously balanced so the deletion does not
+ * empty a node.
+ *
+ * This is exported for use inside btrfs-progs, don't un-export it.
*/
void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
- int level, int slot)
+ int level, int slot)
{
struct extent_buffer *parent = path->nodes[level];
u32 nritems;
+ int ret;
nritems = btrfs_header_nritems(parent);
- if (slot < nritems - 1) {
- /* shift the items */
+ if (slot != nritems - 1) {
+ if (level) {
+ ret = btrfs_tree_mod_log_insert_move(parent, slot,
+ slot + 1, nritems - slot - 1);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(parent,
btrfs_node_key_ptr_offset(parent, slot),
btrfs_node_key_ptr_offset(parent, slot + 1),
sizeof(struct btrfs_key_ptr) *
(nritems - slot - 1));
+ } else if (level) {
+ ret = btrfs_tree_mod_log_insert_key(parent, slot,
+ BTRFS_MOD_LOG_KEY_REMOVE);
+ BUG_ON(ret < 0);
}
+
nritems--;
btrfs_set_header_nritems(parent, nritems);
if (nritems == 0 && parent == root->node) {
@@ -2588,23 +4337,26 @@ void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
* The path must have already been setup for deleting the leaf, including
* all the proper balancing. path->nodes[1] must be locked.
*/
-static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- struct extent_buffer *leaf)
+static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct extent_buffer *leaf)
{
- int ret;
-
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
btrfs_del_ptr(root, path, 1, path->slots[1]);
+ /*
+ * btrfs_free_extent is expensive, we want to make sure we
+ * aren't holding any locks when we call it
+ */
+ btrfs_unlock_up_safe(path, 0);
+
root_sub_used(root, leaf->len);
- ret = btrfs_free_extent(trans, leaf->start, leaf->len, 0,
- root->root_key.objectid, 0, 0);
- return ret;
+ atomic_inc(&leaf->refs);
+ btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
+ free_extent_buffer_stale(leaf);
}
-
/*
* delete the item at the leaf level in path. If that empties
* the leaf, remove it from the tree
@@ -2612,41 +4364,37 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int slot, int nr)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *leaf;
- int last_off;
- int dsize = 0;
int ret = 0;
int wret;
- int i;
u32 nritems;
leaf = path->nodes[0];
- last_off = btrfs_item_offset(leaf, slot + nr - 1);
-
- for (i = 0; i < nr; i++)
- dsize += btrfs_item_size(leaf, slot + i);
-
nritems = btrfs_header_nritems(leaf);
if (slot + nr != nritems) {
- int data_end = leaf_data_end(leaf);
+ const u32 last_off = btrfs_item_offset(leaf, slot + nr - 1);
+ const int data_end = leaf_data_end(leaf);
+ struct btrfs_map_token token;
+ u32 dsize = 0;
+ int i;
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, 0) +
- data_end + dsize,
- btrfs_item_nr_offset(leaf, 0) + data_end,
- last_off - data_end);
+ for (i = 0; i < nr; i++)
+ dsize += btrfs_item_size(leaf, slot + i);
+ memmove_leaf_data(leaf, data_end + dsize, data_end,
+ last_off - data_end);
+
+ btrfs_init_map_token(&token, leaf);
for (i = slot + nr; i < nritems; i++) {
u32 ioff;
- ioff = btrfs_item_offset(leaf, i);
- btrfs_set_item_offset(leaf, i, ioff + dsize);
+ ioff = btrfs_token_item_offset(&token, i);
+ btrfs_set_token_item_offset(&token, i, ioff + dsize);
}
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot),
- btrfs_item_nr_offset(leaf, slot + nr),
- sizeof(struct btrfs_item) *
- (nritems - slot - nr));
+ memmove_leaf_items(leaf, slot, slot + nr, nritems - slot - nr);
}
btrfs_set_header_nritems(leaf, nritems - nr);
nritems -= nr;
@@ -2657,10 +4405,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
btrfs_set_header_level(leaf, 0);
} else {
btrfs_clear_buffer_dirty(trans, leaf);
- wret = btrfs_del_leaf(trans, root, path, leaf);
- BUG_ON(ret);
- if (wret)
- ret = wret;
+ btrfs_del_leaf(trans, root, path, leaf);
}
} else {
int used = leaf_space_used(leaf, 0, nritems);
@@ -2671,35 +4416,67 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
fixup_low_keys(path, &disk_key, 1);
}
- /* delete the leaf if it is mostly empty */
- if (used < BTRFS_LEAF_DATA_SIZE(root->fs_info) / 4) {
+ /*
+ * Try to delete the leaf if it is mostly empty. We do this by
+ * trying to move all its items into its left and right neighbours.
+ * If we can't move all the items, then we don't delete it - it's
+ * not ideal, but future insertions might fill the leaf with more
+ * items, or items from other leaves might be moved later into our
+ * leaf due to deletions on those leaves.
+ */
+ if (used < BTRFS_LEAF_DATA_SIZE(fs_info) / 3) {
+ u32 min_push_space;
+
/* push_leaf_left fixes the path.
* make sure the path still points to our leaf
- * for possible call to del_ptr below
+ * for possible call to btrfs_del_ptr below
*/
slot = path->slots[1];
- extent_buffer_get(leaf);
-
- wret = push_leaf_left(trans, root, path, 1, 1);
+ atomic_inc(&leaf->refs);
+ /*
+ * We want to be able to at least push one item to the
+ * left neighbour leaf, and that's the first item.
+ */
+ min_push_space = sizeof(struct btrfs_item) +
+ btrfs_item_size(leaf, 0);
+ wret = push_leaf_left(trans, root, path, 0,
+ min_push_space, 1, (u32)-1);
if (wret < 0 && wret != -ENOSPC)
ret = wret;
if (path->nodes[0] == leaf &&
btrfs_header_nritems(leaf)) {
- wret = push_leaf_right(trans, root, path, 1, 1);
+ /*
+ * If we were not able to push all items from our
+ * leaf to its left neighbour, then attempt to
+ * either push all the remaining items to the
+ * right neighbour or none. There's no advantage
+ * in pushing only some items, instead of all, as
+ * it's pointless to end up with a leaf having
+ * too few items while the neighbours can be full
+ * or nearly full.
+ */
+ nritems = btrfs_header_nritems(leaf);
+ min_push_space = leaf_space_used(leaf, 0, nritems);
+ wret = push_leaf_right(trans, root, path, 0,
+ min_push_space, 1, 0);
if (wret < 0 && wret != -ENOSPC)
ret = wret;
}
if (btrfs_header_nritems(leaf) == 0) {
- btrfs_clear_buffer_dirty(trans, leaf);
path->slots[1] = slot;
- ret = btrfs_del_leaf(trans, root, path, leaf);
- BUG_ON(ret);
+ btrfs_del_leaf(trans, root, path, leaf);
free_extent_buffer(leaf);
-
+ ret = 0;
} else {
- btrfs_mark_buffer_dirty(leaf);
+ /* if we're still in the path, make sure
+ * we're dirty. Otherwise, one of the
+ * push_leaf functions must have already
+ * dirtied this buffer
+ */
+ if (path->nodes[0] == leaf)
+ btrfs_mark_buffer_dirty(leaf);
free_extent_buffer(leaf);
}
} else {
@@ -2710,124 +4487,469 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
/*
- * walk up the tree as far as required to find the previous leaf.
+ * search the tree again to find a leaf with lesser keys
* returns 0 if it found something or 1 if there are no lesser leaves.
* returns < 0 on io errors.
+ *
+ * This may release the path, and so you may lose any locks held at the
+ * time you call it.
*/
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
{
- int slot;
- int level = 1;
- struct extent_buffer *c;
- struct extent_buffer *next = NULL;
+ struct btrfs_key key;
+ struct btrfs_disk_key found_key;
+ int ret;
- while(level < BTRFS_MAX_LEVEL) {
- if (!path->nodes[level])
- return 1;
+ btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
- slot = path->slots[level];
- c = path->nodes[level];
- if (slot == 0) {
- level++;
- if (level == BTRFS_MAX_LEVEL)
- return 1;
- continue;
- }
- slot--;
-
- next = btrfs_read_node_slot(c, slot);
- if (!extent_buffer_uptodate(next)) {
- if (IS_ERR(next))
- return PTR_ERR(next);
- return -EIO;
- }
- break;
+ if (key.offset > 0) {
+ key.offset--;
+ } else if (key.type > 0) {
+ key.type--;
+ key.offset = (u64)-1;
+ } else if (key.objectid > 0) {
+ key.objectid--;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
+ } else {
+ return 1;
}
- path->slots[level] = slot;
- while(1) {
- level--;
- c = path->nodes[level];
- free_extent_buffer(c);
- slot = btrfs_header_nritems(next);
- if (slot != 0)
- slot--;
- path->nodes[level] = next;
- path->slots[level] = slot;
- if (!level)
- break;
- next = btrfs_read_node_slot(next, slot);
- if (!extent_buffer_uptodate(next)) {
- if (IS_ERR(next))
- return PTR_ERR(next);
- return -EIO;
- }
- }
- return 0;
+
+ btrfs_release_path(path);
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+ btrfs_item_key(path->nodes[0], &found_key, 0);
+ ret = comp_keys(&found_key, &key);
+ /*
+ * We might have had an item with the previous key in the tree right
+ * before we released our path. And after we released our path, that
+ * item might have been pushed to the first slot (0) of the leaf we
+ * were holding due to a tree balance. Alternatively, an item with the
+ * previous key can exist as the only element of a leaf (big fat item).
+ * Therefore account for these 2 cases, so that our callers (like
+ * btrfs_previous_item) don't miss an existing item with a key matching
+ * the previous key we computed above.
+ */
+ if (ret <= 0)
+ return 0;
+ return 1;
}
/*
- * Walk up the tree as far as necessary to find the next sibling tree block.
- * More generic version of btrfs_next_leaf(), as it could find sibling nodes
- * if @path->lowest_level is not 0.
+ * A helper function to walk down the tree starting at min_key, and looking
+ * for nodes or leaves that are have a minimum transaction id.
+ * This is used by the btree defrag code, and tree logging
*
- * returns 0 if it found something or 1 if there are no greater leaves.
- * returns < 0 on io errors.
+ * This does not cow, but it does stuff the starting key it finds back
+ * into min_key, so you can call btrfs_search_slot with cow=1 on the
+ * key and get a writable path.
+ *
+ * This honors path->lowest_level to prevent descent past a given level
+ * of the tree.
+ *
+ * min_trans indicates the oldest transaction that you are interested
+ * in walking through. Any nodes or leaves older than min_trans are
+ * skipped over (without reading them).
+ *
+ * returns zero if something useful was found, < 0 on error and 1 if there
+ * was nothing in the tree that matched the search criteria.
*/
-int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path)
+int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
+ struct btrfs_path *path,
+ u64 min_trans)
+{
+ struct extent_buffer *cur;
+ struct btrfs_key found_key;
+ int slot;
+ int sret;
+ u32 nritems;
+ int level;
+ int ret = 1;
+ int keep_locks = path->keep_locks;
+
+ ASSERT(!path->nowait);
+ path->keep_locks = 1;
+again:
+ cur = btrfs_read_lock_root_node(root);
+ level = btrfs_header_level(cur);
+ WARN_ON(path->nodes[level]);
+ path->nodes[level] = cur;
+ path->locks[level] = BTRFS_READ_LOCK;
+
+ if (btrfs_header_generation(cur) < min_trans) {
+ ret = 1;
+ goto out;
+ }
+ while (1) {
+ nritems = btrfs_header_nritems(cur);
+ level = btrfs_header_level(cur);
+ sret = btrfs_bin_search(cur, 0, min_key, &slot);
+ if (sret < 0) {
+ ret = sret;
+ goto out;
+ }
+
+ /* at the lowest level, we're done, setup the path and exit */
+ if (level == path->lowest_level) {
+ if (slot >= nritems)
+ goto find_next_key;
+ ret = 0;
+ path->slots[level] = slot;
+ btrfs_item_key_to_cpu(cur, &found_key, slot);
+ goto out;
+ }
+ if (sret && slot > 0)
+ slot--;
+ /*
+ * check this node pointer against the min_trans parameters.
+ * If it is too old, skip to the next one.
+ */
+ while (slot < nritems) {
+ u64 gen;
+
+ gen = btrfs_node_ptr_generation(cur, slot);
+ if (gen < min_trans) {
+ slot++;
+ continue;
+ }
+ break;
+ }
+find_next_key:
+ /*
+ * we didn't find a candidate key in this node, walk forward
+ * and find another one
+ */
+ if (slot >= nritems) {
+ path->slots[level] = slot;
+ sret = btrfs_find_next_key(root, path, min_key, level,
+ min_trans);
+ if (sret == 0) {
+ btrfs_release_path(path);
+ goto again;
+ } else {
+ goto out;
+ }
+ }
+ /* save our key for returning back */
+ btrfs_node_key_to_cpu(cur, &found_key, slot);
+ path->slots[level] = slot;
+ if (level == path->lowest_level) {
+ ret = 0;
+ goto out;
+ }
+ cur = btrfs_read_node_slot(cur, slot);
+ if (IS_ERR(cur)) {
+ ret = PTR_ERR(cur);
+ goto out;
+ }
+
+ btrfs_tree_read_lock(cur);
+
+ path->locks[level - 1] = BTRFS_READ_LOCK;
+ path->nodes[level - 1] = cur;
+ unlock_up(path, level, 1, 0, NULL);
+ }
+out:
+ path->keep_locks = keep_locks;
+ if (ret == 0) {
+ btrfs_unlock_up_safe(path, path->lowest_level + 1);
+ memcpy(min_key, &found_key, sizeof(found_key));
+ }
+ return ret;
+}
+
+/*
+ * this is similar to btrfs_next_leaf, but does not try to preserve
+ * and fixup the path. It looks for and returns the next key in the
+ * tree based on the current path and the min_trans parameters.
+ *
+ * 0 is returned if another key is found, < 0 if there are any errors
+ * and 1 is returned if there are no higher keys in the tree
+ *
+ * path->keep_locks should be set to 1 on the search made before
+ * calling this function.
+ */
+int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
+ struct btrfs_key *key, int level, u64 min_trans)
{
int slot;
- int level = path->lowest_level + 1;
struct extent_buffer *c;
- struct extent_buffer *next = NULL;
- BUG_ON(path->lowest_level + 1 >= BTRFS_MAX_LEVEL);
- do {
+ WARN_ON(!path->keep_locks && !path->skip_locking);
+ while (level < BTRFS_MAX_LEVEL) {
if (!path->nodes[level])
return 1;
+ slot = path->slots[level] + 1;
+ c = path->nodes[level];
+next:
+ if (slot >= btrfs_header_nritems(c)) {
+ int ret;
+ int orig_lowest;
+ struct btrfs_key cur_key;
+ if (level + 1 >= BTRFS_MAX_LEVEL ||
+ !path->nodes[level + 1])
+ return 1;
+
+ if (path->locks[level + 1] || path->skip_locking) {
+ level++;
+ continue;
+ }
+
+ slot = btrfs_header_nritems(c) - 1;
+ if (level == 0)
+ btrfs_item_key_to_cpu(c, &cur_key, slot);
+ else
+ btrfs_node_key_to_cpu(c, &cur_key, slot);
+
+ orig_lowest = path->lowest_level;
+ btrfs_release_path(path);
+ path->lowest_level = level;
+ ret = btrfs_search_slot(NULL, root, &cur_key, path,
+ 0, 0);
+ path->lowest_level = orig_lowest;
+ if (ret < 0)
+ return ret;
+
+ c = path->nodes[level];
+ slot = path->slots[level];
+ if (ret == 0)
+ slot++;
+ goto next;
+ }
+
+ if (level == 0)
+ btrfs_item_key_to_cpu(c, key, slot);
+ else {
+ u64 gen = btrfs_node_ptr_generation(c, slot);
+
+ if (gen < min_trans) {
+ slot++;
+ goto next;
+ }
+ btrfs_node_key_to_cpu(c, key, slot);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
+ u64 time_seq)
+{
+ int slot;
+ int level;
+ struct extent_buffer *c;
+ struct extent_buffer *next;
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_key key;
+ bool need_commit_sem = false;
+ u32 nritems;
+ int ret;
+ int i;
+
+ /*
+ * The nowait semantics are used only for write paths, where we don't
+ * use the tree mod log and sequence numbers.
+ */
+ if (time_seq)
+ ASSERT(!path->nowait);
+
+ nritems = btrfs_header_nritems(path->nodes[0]);
+ if (nritems == 0)
+ return 1;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
+again:
+ level = 1;
+ next = NULL;
+ btrfs_release_path(path);
+
+ path->keep_locks = 1;
+
+ if (time_seq) {
+ ret = btrfs_search_old_slot(root, &key, path, time_seq);
+ } else {
+ if (path->need_commit_sem) {
+ path->need_commit_sem = 0;
+ need_commit_sem = true;
+ if (path->nowait) {
+ if (!down_read_trylock(&fs_info->commit_root_sem)) {
+ ret = -EAGAIN;
+ goto done;
+ }
+ } else {
+ down_read(&fs_info->commit_root_sem);
+ }
+ }
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ }
+ path->keep_locks = 0;
+
+ if (ret < 0)
+ goto done;
+
+ nritems = btrfs_header_nritems(path->nodes[0]);
+ /*
+ * by releasing the path above we dropped all our locks. A balance
+ * could have added more items next to the key that used to be
+ * at the very end of the block. So, check again here and
+ * advance the path if there are now more items available.
+ */
+ if (nritems > 0 && path->slots[0] < nritems - 1) {
+ if (ret == 0)
+ path->slots[0]++;
+ ret = 0;
+ goto done;
+ }
+ /*
+ * So the above check misses one case:
+ * - after releasing the path above, someone has removed the item that
+ * used to be at the very end of the block, and balance between leafs
+ * gets another one with bigger key.offset to replace it.
+ *
+ * This one should be returned as well, or we can get leaf corruption
+ * later(esp. in __btrfs_drop_extents()).
+ *
+ * And a bit more explanation about this check,
+ * with ret > 0, the key isn't found, the path points to the slot
+ * where it should be inserted, so the path->slots[0] item must be the
+ * bigger one.
+ */
+ if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
+ ret = 0;
+ goto done;
+ }
+
+ while (level < BTRFS_MAX_LEVEL) {
+ if (!path->nodes[level]) {
+ ret = 1;
+ goto done;
+ }
+
slot = path->slots[level] + 1;
c = path->nodes[level];
if (slot >= btrfs_header_nritems(c)) {
level++;
- if (level == BTRFS_MAX_LEVEL)
- return 1;
+ if (level == BTRFS_MAX_LEVEL) {
+ ret = 1;
+ goto done;
+ }
continue;
}
- if (path->reada)
- reada_for_search(fs_info, path, level, slot, 0);
- next = btrfs_read_node_slot(c, slot);
- if (!extent_buffer_uptodate(next))
- return -EIO;
+ /*
+ * Our current level is where we're going to start from, and to
+ * make sure lockdep doesn't complain we need to drop our locks
+ * and nodes from 0 to our current level.
+ */
+ for (i = 0; i < level; i++) {
+ if (path->locks[level]) {
+ btrfs_tree_read_unlock(path->nodes[i]);
+ path->locks[i] = 0;
+ }
+ free_extent_buffer(path->nodes[i]);
+ path->nodes[i] = NULL;
+ }
+
+ next = c;
+ ret = read_block_for_search(root, path, &next, level,
+ slot, &key);
+ if (ret == -EAGAIN && !path->nowait)
+ goto again;
+
+ if (ret < 0) {
+ btrfs_release_path(path);
+ goto done;
+ }
+
+ if (!path->skip_locking) {
+ ret = btrfs_try_tree_read_lock(next);
+ if (!ret && path->nowait) {
+ ret = -EAGAIN;
+ goto done;
+ }
+ if (!ret && time_seq) {
+ /*
+ * If we don't get the lock, we may be racing
+ * with push_leaf_left, holding that lock while
+ * itself waiting for the leaf we've currently
+ * locked. To solve this situation, we give up
+ * on our lock and cycle.
+ */
+ free_extent_buffer(next);
+ btrfs_release_path(path);
+ cond_resched();
+ goto again;
+ }
+ if (!ret)
+ btrfs_tree_read_lock(next);
+ }
break;
- } while (level < BTRFS_MAX_LEVEL);
+ }
path->slots[level] = slot;
- while(1) {
+ while (1) {
level--;
- c = path->nodes[level];
- free_extent_buffer(c);
path->nodes[level] = next;
path->slots[level] = 0;
- /*
- * Fsck will happily load corrupt blocks in order to fix them,
- * so we need an extra check just to make sure this block isn't
- * marked uptodate but invalid.
- */
- if (check_block(fs_info, path, level))
- return -EIO;
- if (level == path->lowest_level)
+ if (!path->skip_locking)
+ path->locks[level] = BTRFS_READ_LOCK;
+ if (!level)
break;
- if (path->reada)
- reada_for_search(fs_info, path, level, 0, 0);
- next = btrfs_read_node_slot(next, 0);
- if (!extent_buffer_uptodate(next))
- return -EIO;
+
+ ret = read_block_for_search(root, path, &next, level,
+ 0, &key);
+ if (ret == -EAGAIN && !path->nowait)
+ goto again;
+
+ if (ret < 0) {
+ btrfs_release_path(path);
+ goto done;
+ }
+
+ if (!path->skip_locking) {
+ if (path->nowait) {
+ if (!btrfs_try_tree_read_lock(next)) {
+ ret = -EAGAIN;
+ goto done;
+ }
+ } else {
+ btrfs_tree_read_lock(next);
+ }
+ }
}
+ ret = 0;
+done:
+ unlock_up(path, 0, 1, 0, NULL);
+ if (need_commit_sem) {
+ int ret2;
+
+ path->need_commit_sem = 1;
+ ret2 = finish_need_commit_sem_search(path);
+ up_read(&fs_info->commit_root_sem);
+ if (ret2)
+ ret = ret2;
+ }
+
+ return ret;
+}
+
+int btrfs_next_old_item(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq)
+{
+ path->slots[0]++;
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0]))
+ return btrfs_next_old_leaf(root, path, time_seq);
return 0;
}
+/*
+ * this uses btrfs_prev_leaf to walk backwards in the tree, and keeps
+ * searching until it gets past min_objectid or finds an item of 'type'
+ *
+ * returns 0 if something is found, 1 if nothing was found and < 0 on error
+ */
int btrfs_previous_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid,
int type)
@@ -2837,7 +4959,7 @@ int btrfs_previous_item(struct btrfs_root *root,
u32 nritems;
int ret;
- while(1) {
+ while (1) {
if (path->slots[0] == 0) {
ret = btrfs_prev_leaf(root, path);
if (ret != 0)
@@ -2866,7 +4988,7 @@ int btrfs_previous_item(struct btrfs_root *root,
/*
* search in extent tree to find a previous Metadata/Data extent item with
- * min objectid.
+ * min objecitd.
*
* returns 0 if something is found, 1 if nothing was found and < 0 on error
*/
@@ -2905,3 +5027,25 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
}
return 1;
}
+
+/*
+ * MODIFIED:
+ * - This has to be called by open_ctree to make sure we can use stuff.
+ */
+int __init btrfs_ctree_init(void)
+{
+ if (btrfs_path_cachep)
+ return 0;
+
+ btrfs_path_cachep = kmem_cache_create("btrfs_path",
+ sizeof(struct btrfs_path), 0,
+ SLAB_MEM_SPREAD, NULL);
+ if (!btrfs_path_cachep)
+ return -ENOMEM;
+ return 0;
+}
+
+void __cold btrfs_ctree_exit(void)
+{
+ kmem_cache_destroy(btrfs_path_cachep);
+}
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 376b8eca..20280ede 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -30,6 +30,7 @@
#include "accessors.h"
#include "extent-io-tree.h"
#include "locking.h"
+#include "crypto/crc32c.h"
struct btrfs_root;
struct btrfs_trans_handle;
@@ -320,6 +321,9 @@ struct btrfs_fs_info {
struct extent_io_tree extent_ins;
struct extent_io_tree *excluded_extents;
+ spinlock_t trans_lock;
+ struct rw_semaphore commit_root_sem;
+
struct rb_root block_group_cache_tree;
/* logical->physical extent mapping */
struct btrfs_mapping_tree mapping_tree;
@@ -865,8 +869,19 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
return !!(btrfs_super_compat_ro_flags(disk_super) & flag);
}
-u64 btrfs_name_hash(const char *name, int len);
-u64 btrfs_extref_hash(u64 parent_objectid, const char *name, int len);
+static inline u64 btrfs_name_hash(const char *name, int len)
+{
+ return crc32c((u32)~1, name, len);
+}
+
+/*
+ * Figure the key offset of an extended inode ref
+ */
+static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
+ int len)
+{
+ return (u64) crc32c(parent_objectid, name, len);
+}
/* extent-tree.c */
int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
@@ -940,6 +955,8 @@ u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
int btrfs_convert_one_bg(struct btrfs_trans_handle *trans, u64 bytenr);
/* ctree.c */
+int __init btrfs_ctree_init(void);
+struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot);
@@ -953,7 +970,8 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
- struct extent_buffer **cow_ret);
+ struct extent_buffer **cow_ret,
+ enum btrfs_lock_nesting nest);
int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
@@ -963,7 +981,7 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct btrfs_key *new_key,
+ const struct btrfs_key *new_key,
unsigned long split_offset);
int btrfs_search_slot(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const struct btrfs_key *key,
@@ -990,24 +1008,58 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
return btrfs_del_items(trans, root, path, path->slots[0], 1);
}
-int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_key *key, void *data, u32 data_size);
+/*
+ * Describes a batch of items to insert in a btree. This is used by
+ * btrfs_insert_empty_items().
+ */
+struct btrfs_item_batch {
+ /*
+ * Pointer to an array containing the keys of the items to insert (in
+ * sorted order).
+ */
+ const struct btrfs_key *keys;
+ /* Pointer to an array containing the data size for each item to insert. */
+ const u32 *data_sizes;
+ /*
+ * The sum of data sizes for all items. The caller can compute this while
+ * setting up the data_sizes array, so it ends up being more efficient
+ * than having btrfs_insert_empty_items() or setup_item_for_insert()
+ * doing it, as it would avoid an extra loop over a potentially large
+ * array, and in the case of setup_item_for_insert(), we would be doing
+ * it while holding a write lock on a leaf and often on upper level nodes
+ * too, unnecessarily increasing the size of a critical section.
+ */
+ u32 total_data_size;
+ /* Size of the keys and data_sizes arrays (number of items in the batch). */
+ int nr;
+};
+
+int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ const struct btrfs_key *key, void *data, u32 data_size);
int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct btrfs_key *cpu_key, u32 *data_size, int nr);
+ const struct btrfs_item_batch *batch);
static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct btrfs_key *key,
+ const struct btrfs_key *key,
u32 data_size)
{
- return btrfs_insert_empty_items(trans, root, path, key, &data_size, 1);
+ struct btrfs_item_batch batch;
+
+ batch.keys = key;
+ batch.data_sizes = &data_size;
+ batch.total_data_size = data_size;
+ batch.nr = 1;
+
+ return btrfs_insert_empty_items(trans, root, path, &batch);
}
-int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
- struct btrfs_path *path);
+int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
+ u64 time_seq);
+int btrfs_next_old_item(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq);
/*
* Walk up the tree as far as necessary to find the next leaf.
@@ -1018,26 +1070,13 @@ int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
static inline int btrfs_next_leaf(struct btrfs_root *root,
struct btrfs_path *path)
{
- path->lowest_level = 0;
- return btrfs_next_sibling_tree_block(root->fs_info, path);
+ return btrfs_next_old_leaf(root, path, 0);
}
static inline int btrfs_next_item(struct btrfs_root *root,
struct btrfs_path *p)
{
- ++p->slots[0];
- if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) {
- int ret;
- ret = btrfs_next_leaf(root, p);
- /*
- * Revert the increased slot, or the path may point to
- * an invalid item.
- */
- if (ret)
- p->slots[0]--;
- return ret;
- }
- return 0;
+ return btrfs_next_old_item(root, p, 0);
}
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
@@ -1045,8 +1084,10 @@ int btrfs_leaf_free_space(struct extent_buffer *leaf);
void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
const struct btrfs_key *new_key);
+int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
+ struct btrfs_key *key, int level, u64 min_trans);
-u16 btrfs_super_csum_size(const struct btrfs_super_block *s);
+int btrfs_super_csum_size(const struct btrfs_super_block *s);
const char *btrfs_super_csum_name(u16 csum_type);
u16 btrfs_csum_type_size(u16 csum_type);
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index bdf77d50..f9e11d5b 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -898,6 +898,9 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
INIT_LIST_HEAD(&fs_info->space_info);
INIT_LIST_HEAD(&fs_info->recow_ebs);
+ spin_lock_init(&fs_info->trans_lock);
+ init_rwsem(&fs_info->commit_root_sem);
+
if (!writable)
fs_info->readonly = 1;
@@ -1478,6 +1481,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, struct open_ctree_flags *oc
unsigned flags = ocf->flags;
u64 sb_bytenr = ocf->sb_bytenr;
+ btrfs_ctree_init();
+
if (sb_bytenr == 0)
sb_bytenr = BTRFS_SUPER_INFO_OFFSET;
diff --git a/kernel-shared/locking.c b/kernel-shared/locking.c
index c4138e68..42b82afe 100644
--- a/kernel-shared/locking.c
+++ b/kernel-shared/locking.c
@@ -8,15 +8,15 @@
struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
{
- return root->node;
+ return btrfs_root_node(root);
}
struct extent_buffer *btrfs_try_read_lock_root_node(struct btrfs_root *root)
{
- return root->node;
+ return btrfs_root_node(root);
}
struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
{
- return root->node;
+ return btrfs_root_node(root);
}
diff --git a/kernel-shared/transaction.c b/kernel-shared/transaction.c
index 1e1ec85b..5edd19ea 100644
--- a/kernel-shared/transaction.c
+++ b/kernel-shared/transaction.c
@@ -20,6 +20,7 @@
#include "kernel-shared/delayed-ref.h"
#include "kernel-shared/zoned.h"
#include "common/messages.h"
+#include "kernel-lib/bitops.h"
struct btrfs_trans_handle* btrfs_start_transaction(struct btrfs_root *root,
int num_blocks)
@@ -99,7 +100,8 @@ int commit_tree_roots(struct btrfs_trans_handle *trans,
eb = fs_info->tree_root->node;
extent_buffer_get(eb);
- ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
+ ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb,
+ BTRFS_NESTING_NORMAL);
free_extent_buffer(eb);
if (ret)
return ret;
@@ -119,6 +121,7 @@ int commit_tree_roots(struct btrfs_trans_handle *trans,
next = fs_info->dirty_cowonly_roots.next;
list_del_init(next);
root = list_entry(next, struct btrfs_root, dirty_list);
+ clear_bit(BTRFS_ROOT_DIRTY, &root->state);
ret = update_cowonly_root(trans, root);
free_extent_buffer(root->commit_root);
root->commit_root = NULL;
--
2.40.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
` (25 preceding siblings ...)
2023-04-29 20:19 ` [PATCH 26/26] btrfs-progs: sync ctree.c from the kernel Josef Bacik
@ 2023-05-03 14:20 ` David Sterba
26 siblings, 0 replies; 28+ messages in thread
From: David Sterba @ 2023-05-03 14:20 UTC (permalink / raw)
To: Josef Bacik; +Cc: linux-btrfs, kernel-team
On Sat, Apr 29, 2023 at 04:19:31PM -0400, Josef Bacik wrote:
> Hello,
>
> This is a long series, and it depends on the following series
>
> btrfs-progs: prep work for syncing files into kernel-shared
> btrfs-progs: sync basic code from the kernel
> btrfs-progs: prep work for syncing ctree.c
> btrfs-progs: more prep work for syncing ctree.c
>
> This is even more more prep work for syncing ctree.c, and the last patch is the
> actual sync. A lot of these prep patches are updating the callers to match the
> current calling conventions in the kernel to make the syncing straightforward.
Added to devel, thanks. The includes were out of order or without the
prefix and some forward declarations or kerncompat.h includes were
needed to make it compile in the end.
The remaining issues are basically all around messages. There are now
two messages.[ch] and the pV handling is in the userspace side while
only used by kernel. Musl does not have the user defined specifiers so
we'll need to add a workaround with an intermediate string.
Other build tests seem to pass so I'll take it as a base line for
further fixups. Some changes can be done as separate patches to avoid
cascading changes in other commits but at least the printf.h should be
done in place.
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2023-05-03 14:26 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-29 20:19 [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
2023-04-29 20:19 ` [PATCH 01/26] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
2023-04-29 20:19 ` [PATCH 02/26] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
2023-04-29 20:19 ` [PATCH 03/26] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
2023-04-29 20:19 ` [PATCH 04/26] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
2023-04-29 20:19 ` [PATCH 05/26] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
2023-04-29 20:19 ` [PATCH 06/26] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
2023-04-29 20:19 ` [PATCH 07/26] btrfs-progs: update btrfs_bin_search " Josef Bacik
2023-04-29 20:19 ` [PATCH 08/26] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
2023-04-29 20:19 ` [PATCH 09/26] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
2023-04-29 20:19 ` [PATCH 10/26] btrfs-progs: update btrfs_truncate_item " Josef Bacik
2023-04-29 20:19 ` [PATCH 11/26] btrfs-progs: update btrfs_extend_item " Josef Bacik
2023-04-29 20:19 ` [PATCH 12/26] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
2023-04-29 20:19 ` [PATCH 13/26] btrfs-progs: change how we check supported csum type Josef Bacik
2023-04-29 20:19 ` [PATCH 14/26] btrfs-progs: drop btrfs_init_path Josef Bacik
2023-04-29 20:19 ` [PATCH 15/26] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
2023-04-29 20:19 ` [PATCH 16/26] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
2023-04-29 20:19 ` [PATCH 17/26] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
2023-04-29 20:19 ` [PATCH 18/26] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
2023-04-29 20:19 ` [PATCH 19/26] btrfs-progs: remove btrfs_create_root Josef Bacik
2023-04-29 20:19 ` [PATCH 20/26] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
2023-04-29 20:19 ` [PATCH 21/26] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
2023-04-29 20:19 ` [PATCH 22/26] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
2023-04-29 20:19 ` [PATCH 23/26] btrfs-progs: use path->search_for_extension Josef Bacik
2023-04-29 20:19 ` [PATCH 24/26] btrfs-progs: add write_extent_buffer_chunk_tree_uuid helper Josef Bacik
2023-04-29 20:19 ` [PATCH 25/26] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
2023-04-29 20:19 ` [PATCH 26/26] btrfs-progs: sync ctree.c from the kernel Josef Bacik
2023-05-03 14:20 ` [PATCH 00/26] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox