All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs
@ 2023-08-23 14:32 Josef Bacik
  2023-08-23 14:32 ` [PATCH 01/38] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
                   ` (39 more replies)
  0 siblings, 40 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

Hello,

I started back up my extent tree v2 work and noticed not all my ctree.c sync
patches made it in the last submission as I missed some comments.

This patchset is much larger than what was left, as I broke up the changes more
discreetly.  In my original submission I had ignored some of the tree wide
changes in favor of expediency, and had modified ctree.c more to match what we
had in btrfs-progs.

This time I've updated everything that was different in ctree.c in the rest of
btrfs-progs to make the actual sync'ing of ctree.c more straightforward.  I had
to modify a few things in ctree.c, but they are very small and specific, no more
updates of any of the global functions we depend on.

The downside is this patchset is massive.  The upside is the patches are small
and self contained, with the obvious exception of the actual ctree.c sync.

This also will make subsequent sync'ing of other source files much easier, as
I've changed a good deal of the very common helpers to match what exists in the
kernel.

This passes all the tests.  There are a few behavior changes, but for the most
part it's just updating helpers to match kernel definitions and moving code
around.  Thanks,

Josef

Josef Bacik (38):
  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: 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: init new tree blocks in btrfs_alloc_tree_block
  btrfs-progs: add dwarves to the package list for ci
  btrfs-progs: add kerncompat helpers for ctree.c sync
  btrfs-progs: add trans_lock to fs_info
  btrfs-progs: add commit_root_sem to btrfs_fs_info
  btrfs-progs: update btrfs_cow_block to match the in-kernel definition
  btrfs-progs: update btrfs_insert_empty_items to match the kernel
  btrfs-progs: update btrfs_insert_empty_item to match the kernel
  btrfs-progs: update btrfs_del_ptr to match the kernel
  btrfs-progs: update btrfs_insert_item to match the kernel
  btrfs-progs: update btrfs_leaf_free_space to match the kernel
  btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer
  btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check
  btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash
  btrfs-progs: update btrfs_split_item to match the in-kernel definition
  btrfs-progs: sync ctree.c from kernel

 Makefile                                      |    1 +
 btrfs-corrupt-block.c                         |   17 +-
 btrfs-find-root.c                             |    5 +-
 btrfs-map-logical.c                           |    1 +
 check/clear-cache.c                           |   12 +-
 check/main.c                                  |  135 +-
 check/mode-common.c                           |   42 +-
 check/mode-lowmem.c                           |  109 +-
 check/qgroup-verify.c                         |   21 +-
 check/repair.c                                |   66 +-
 check/repair.h                                |    5 +
 ci/images/ci-centos-7-x86_64/Dockerfile       |    2 +-
 ci/images/ci-centos-8-x86_64/Dockerfile       |    2 +-
 ci/images/ci-musl-x86_64/Dockerfile           |    2 +-
 .../ci-openSUSE-Leap-15.3-x86_64/Dockerfile   |    2 +-
 .../ci-openSUSE-Leap-15.4-x86_64/Dockerfile   |    2 +-
 .../ci-openSUSE-tumbleweed-x86_64/Dockerfile  |    2 +-
 cmds/inspect-dump-tree.c                      |   25 +-
 cmds/inspect-tree-stats.c                     |   14 +-
 cmds/rescue-chunk-recover.c                   |   16 +-
 cmds/rescue.c                                 |    2 +-
 cmds/restore.c                                |   39 +-
 common/extent-tree-utils.c                    |  282 +
 common/extent-tree-utils.h                    |   28 +
 convert/main.c                                |   10 +-
 convert/source-fs.c                           |    5 +-
 convert/source-reiserfs.c                     |    1 +
 image/common.c                                |    3 +-
 image/image-create.c                          |   14 +-
 image/image-restore.c                         |   12 +-
 image/main.c                                  |    1 +
 include/kerncompat.h                          |   76 +
 kernel-lib/trace.h                            |    6 +
 kernel-shared/backref.c                       |   17 +-
 kernel-shared/ctree.c                         | 4658 ++++++++++++-----
 kernel-shared/ctree.h                         |  162 +-
 kernel-shared/dir-item.c                      |    4 +-
 kernel-shared/disk-io.c                       |   41 +-
 kernel-shared/disk-io.h                       |    9 +-
 kernel-shared/extent-tree.c                   |  281 +-
 kernel-shared/extent_io.c                     |    9 +-
 kernel-shared/extent_io.h                     |    7 +-
 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/print-tree.c                    |   72 +-
 kernel-shared/print-tree.h                    |    7 +-
 kernel-shared/transaction.c                   |    7 +-
 kernel-shared/volumes.c                       |    6 +-
 mkfs/main.c                                   |   89 +-
 mkfs/rootdir.c                                |   11 +-
 quick-test.c                                  |    6 +-
 tune/change-csum.c                            |   13 +-
 tune/change-uuid.c                            |   10 +-
 tune/convert-bgt.c                            |   13 +-
 58 files changed, 4276 insertions(+), 2139 deletions(-)
 create mode 100644 common/extent-tree-utils.c
 create mode 100644 common/extent-tree-utils.h

-- 
2.41.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 01/38] btrfs-progs: stop using add_root_to_dirty_list in check
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
                   ` (38 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 4565b367..d992b9f8 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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
  2023-08-23 14:32 ` [PATCH 01/38] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-29  6:32   ` Qu Wenruo
  2023-08-23 14:32 ` [PATCH 03/38] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
                   ` (37 subsequent siblings)
  39 siblings, 1 reply; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 1c5d668e..1b917f55 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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 03/38] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
  2023-08-23 14:32 ` [PATCH 01/38] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
  2023-08-23 14:32 ` [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 04/38] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
                   ` (36 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 a2a3663d..34a19464 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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 04/38] btrfs-progs: make add_root_to_dirty_list static and unexport it
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (2 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 03/38] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 05/38] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
                   ` (35 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 51b126c6..6e88b4a9 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -262,7 +262,7 @@ bool __cold abort_should_print_stack(int errno)
 	return true;
 }
 
-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 59533879..15ac310e 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,
 		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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 05/38] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (3 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 04/38] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 06/38] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
                   ` (34 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 e244d1af..cf39edd3 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 6e88b4a9..a87a79b2 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -571,7 +571,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;
 }
@@ -917,7 +917,7 @@ static noinline 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);
 
@@ -971,7 +971,7 @@ static noinline 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);
@@ -1018,7 +1018,7 @@ static noinline 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);
@@ -2982,7 +2982,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)
@@ -3018,7 +3018,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 6a3178a8..35b6cde9 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2289,7 +2289,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 91dd7ca1..8c7dab3f 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1898,7 +1898,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 c653d7c3..503b63e2 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 520ccd78..243ffe74 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;
@@ -128,7 +129,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, const void *buf, u64 offset,
diff --git a/kernel-shared/transaction.c b/kernel-shared/transaction.c
index 49b435f6..87d86fcd 100644
--- a/kernel-shared/transaction.c
+++ b/kernel-shared/transaction.c
@@ -163,7 +163,7 @@ again:
 				goto cleanup;
 			}
 			start += eb->len;
-			btrfs_clear_buffer_dirty(eb);
+			btrfs_clear_buffer_dirty(trans, eb);
 			free_extent_buffer(eb);
 		}
 	}
@@ -186,7 +186,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 06/38] btrfs-progs: update read_node_slot to match the kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (4 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 05/38] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 07/38] btrfs-progs: update btrfs_bin_search " Josef Bacik
                   ` (33 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 7a360645..ba085f94 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 a87a79b2..3b703f7c 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -833,9 +833,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);
 
@@ -909,7 +910,7 @@ static noinline 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);
@@ -933,7 +934,7 @@ static noinline 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);
@@ -942,7 +943,7 @@ static noinline 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);
@@ -1097,7 +1098,7 @@ static noinline int 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)) {
@@ -1137,7 +1138,7 @@ static noinline int 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
@@ -1389,7 +1390,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 {
@@ -1941,7 +1942,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;
@@ -1962,7 +1962,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);
@@ -2090,7 +2090,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;
@@ -2114,7 +2113,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);
@@ -3046,7 +3045,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])
@@ -3062,7 +3060,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);
@@ -3082,7 +3080,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);
@@ -3125,7 +3123,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;
@@ -3148,7 +3146,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 15ac310e..dc11b246 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -949,8 +949,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 d7ffeccd..38524971 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1494,7 +1494,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 07/38] btrfs-progs: update btrfs_bin_search to match the kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (5 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 06/38] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 08/38] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
                   ` (32 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 d992b9f8..481fe11e 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 3b703f7c..4d269e45 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -816,8 +816,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,
@@ -1355,7 +1355,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 dc11b246..66c05a69 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -983,8 +983,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 08/38] btrfs-progs: update btrfs_set_item_key_safe to match kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (6 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 07/38] btrfs-progs: update btrfs_bin_search " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 09/38] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
                   ` (31 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 +--
 tune/change-csum.c        |  8 +-------
 4 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 4d269e45..f94d3ef1 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1514,8 +1514,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;
@@ -1525,13 +1526,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);
@@ -1539,7 +1538,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 66c05a69..bf5dde14 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1056,8 +1056,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 1a2f5f14..30a89094 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -379,8 +379,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();
 	}
diff --git a/tune/change-csum.c b/tune/change-csum.c
index 17372890..9edddb05 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -459,13 +459,7 @@ static int change_csum_objectids(struct btrfs_fs_info *fs_info)
 			btrfs_item_key_to_cpu(path.nodes[0], &found_key, i);
 			found_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
 			path.slots[0] = i;
-			ret = btrfs_set_item_key_safe(csum_root, &path, &found_key);
-			if (ret < 0) {
-				errno = -ret;
-				error("failed to set item key for data csum at logical %llu: %m",
-				      found_key.offset);
-				goto out;
-			}
+			btrfs_set_item_key_safe(fs_info, &path, &found_key);
 		}
 		btrfs_release_path(&path);
 	}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 09/38] btrfs-progs: update btrfs_print_leaf to match the kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (7 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 08/38] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 10/38] btrfs-progs: update btrfs_truncate_item " Josef Bacik
                   ` (30 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 501b90a1..9726bef5 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 f94d3ef1..2f96d701 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2566,7 +2566,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);
@@ -2658,7 +2658,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;
@@ -2682,7 +2682,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];
@@ -2690,7 +2690,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);
 	}
@@ -2717,7 +2717,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;
@@ -2765,7 +2765,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();
@@ -2778,7 +2778,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);
@@ -2824,7 +2824,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 8c7dab3f..f23c28af 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -936,7 +936,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;
 	}
 
@@ -1427,7 +1427,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();
@@ -2033,7 +2033,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];
@@ -2047,7 +2047,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 38524971..b7ca8b7e 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1301,7 +1301,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);
@@ -1614,7 +1614,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 10/38] btrfs-progs: update btrfs_truncate_item to match the kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (8 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 09/38] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 11/38] btrfs-progs: update btrfs_extend_item " Josef Bacik
                   ` (29 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 2f96d701..b5d3d12e 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2573,9 +2573,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;
@@ -2590,7 +2589,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);
@@ -2656,12 +2655,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 bf5dde14..81d71d36 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -970,7 +970,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 f23c28af..001cffd1 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1128,7 +1128,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];
@@ -1168,8 +1167,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 30a89094..e23e679e 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -346,7 +346,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;
@@ -362,8 +361,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) {
 		/*
@@ -375,8 +373,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 11/38] btrfs-progs: update btrfs_extend_item to match the kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (9 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 10/38] btrfs-progs: update btrfs_truncate_item " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 12/38] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
                   ` (28 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 ++---
 6 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index b5d3d12e..ed8a7002 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2661,10 +2661,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;
@@ -2712,12 +2710,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;
 }
 
 /*
@@ -3366,7 +3362,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 81d71d36..c7321a40 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -968,8 +968,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 abf7d047..cb70d7c8 100644
--- a/kernel-shared/dir-item.c
+++ b/kernel-shared/dir-item.c
@@ -48,8 +48,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 001cffd1..543a9952 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -1039,7 +1039,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);
@@ -1048,8 +1047,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 e23e679e..7baa5614 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -282,8 +282,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
 		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;
 	}
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 12/38] btrfs-progs: sync memcpy_extent_buffer from the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (10 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 11/38] btrfs-progs: update btrfs_extend_item " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 13/38] btrfs-progs: drop btrfs_init_path Josef Bacik
                   ` (27 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 503b63e2..a085c2e6 100644
--- a/kernel-shared/extent_io.c
+++ b/kernel-shared/extent_io.c
@@ -641,6 +641,12 @@ void copy_extent_buffer(const struct extent_buffer *dst,
 	memcpy((void *)dst->data + dst_offset, src->data + src_offset, 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 243ffe74..59be49ae 100644
--- a/kernel-shared/extent_io.h
+++ b/kernel-shared/extent_io.h
@@ -121,6 +121,9 @@ void copy_extent_buffer(const struct extent_buffer *dst,
 			const struct extent_buffer *src,
 			unsigned long dst_offset, unsigned long src_offset,
 			unsigned long len);
+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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 13/38] btrfs-progs: drop btrfs_init_path
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (11 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 12/38] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 17:25   ` David Sterba
  2023-08-23 14:32 ` [PATCH 14/38] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
                   ` (26 subsequent siblings)
  39 siblings, 1 reply; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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              | 12 ++--
 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/common.c                   |  3 +-
 image/image-create.c             |  4 +-
 image/image-restore.c            |  6 +-
 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-uuid.c               |  6 +-
 27 files changed, 114 insertions(+), 261 deletions(-)

diff --git a/check/clear-cache.c b/check/clear-cache.c
index 9f8819f0..7a6b6002 100644
--- a/check/clear-cache.c
+++ b/check/clear-cache.c
@@ -130,11 +130,9 @@ static int check_free_space_tree(struct btrfs_root *root)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	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;
@@ -450,7 +448,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 };
@@ -468,9 +465,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);
@@ -551,15 +548,14 @@ out:
 int clear_ino_cache_items(struct btrfs_fs_info *fs_info)
 {
 	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, fs_info->tree_root, &key, &path,	0, 0);
+	ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0);
 	if (ret < 0)
 		return ret;
 
diff --git a/check/main.c b/check/main.c
index 481fe11e..b8bcf5c3 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 bool 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;
 	bool found = false;
@@ -4252,7 +4238,6 @@ static bool 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 175e90f7..71e735c4 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)
@@ -1233,7 +1223,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;
@@ -1248,7 +1238,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;
@@ -1340,7 +1329,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;
@@ -1348,7 +1337,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;
@@ -1487,14 +1475,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 d4d6125c..35bca857 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 44fefe3a..eacf4506 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 9726bef5..9c3de7aa 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;
@@ -516,7 +516,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 d720d64a..e1808ec5 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 bf67fadc..e12dc61c 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 ba085f94..b0e04a7e 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 da6d6cf4..a9a1e1d9 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -796,7 +796,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;
@@ -813,7 +813,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);
@@ -1475,7 +1474,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;
@@ -1484,7 +1483,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)
@@ -1640,7 +1638,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;
@@ -1700,7 +1698,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/common.c b/image/common.c
index 36e90fd2..3aa298d5 100644
--- a/image/common.c
+++ b/image/common.c
@@ -120,7 +120,7 @@ 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];
@@ -134,7 +134,6 @@ 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/image/image-create.c b/image/image-create.c
index baaeba4e..894969ed 100644
--- a/image/image-create.c
+++ b/image/image-create.c
@@ -753,7 +753,7 @@ 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;
@@ -781,8 +781,6 @@ 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);
diff --git a/image/image-restore.c b/image/image-restore.c
index 771e169b..36cdc554 100644
--- a/image/image-restore.c
+++ b/image/image-restore.c
@@ -1426,7 +1426,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;
@@ -1435,7 +1435,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) {
@@ -1574,7 +1573,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;
@@ -1585,7 +1584,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;
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index ed8a7002..bbbb2cc3 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -201,11 +201,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)
 {
 	might_sleep();
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index c7321a40..0d9b75bf 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -990,7 +990,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 543a9952..55fdf881 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -3462,7 +3462,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);
@@ -3484,7 +3484,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 b7ca8b7e..a32c9a2a 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1508,7 +1508,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;
@@ -1520,7 +1520,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 946c2e7a..831359be 100644
--- a/kernel-shared/volumes.c
+++ b/kernel-shared/volumes.c
@@ -2680,7 +2680,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;
@@ -2691,7 +2691,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;
@@ -2730,7 +2729,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;
@@ -2753,7 +2752,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 1b917f55..4de57c8a 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 a04d27af..bb2666ee 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -444,7 +444,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;
@@ -465,8 +465,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;
@@ -800,7 +798,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;
 
@@ -808,7 +806,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);
@@ -852,7 +849,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;
 
@@ -861,7 +858,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-uuid.c b/tune/change-uuid.c
index 30cfb145..54184811 100644
--- a/tune/change-uuid.c
+++ b/tune/change-uuid.c
@@ -82,11 +82,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
@@ -162,11 +161,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 14/38] btrfs-progs: move btrfs_set_item_key_unsafe to check/
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (12 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 13/38] btrfs-progs: drop btrfs_init_path Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 15/38] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
                   ` (25 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 3c742cc8..3e741c08 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 eacf4506..d8900c41 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 3c44a498..81440a87 100644
--- a/check/repair.h
+++ b/check/repair.h
@@ -45,5 +45,10 @@ 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 bbbb2cc3..8eba7812 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1485,8 +1485,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;
@@ -1532,29 +1532,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);
 }
 
 /*
@@ -2213,7 +2191,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) {
@@ -2439,7 +2417,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;
@@ -2644,7 +2622,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);
@@ -2808,7 +2786,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) {
@@ -2881,7 +2859,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;
@@ -2979,7 +2957,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 0d9b75bf..3e00d69b 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1052,14 +1052,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);
 
 int btrfs_super_csum_size(const struct btrfs_super_block *sb);
 const char *btrfs_super_csum_name(u16 csum_type);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 15/38] btrfs-progs: move btrfs_record_file_extent and code into a new file
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (13 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 14/38] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 16/38] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
                   ` (24 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 +
 convert/source-reiserfs.c   |   1 +
 kernel-shared/ctree.c       |  24 ---
 kernel-shared/ctree.h       |   7 -
 kernel-shared/extent-tree.c | 234 ------------------------------
 mkfs/rootdir.c              |   1 +
 tune/change-csum.c          |   1 +
 12 files changed, 317 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 e6afe272..8c0f78f9 100644
--- a/Makefile
+++ b/Makefile
@@ -201,6 +201,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 d85b4be4..2a6c6785 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 a9a1e1d9..84d5913f 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -115,6 +115,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 "check/clear-cache.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/convert/source-reiserfs.c b/convert/source-reiserfs.c
index 35fd0105..3edc72ed 100644
--- a/convert/source-reiserfs.c
+++ b/convert/source-reiserfs.c
@@ -35,6 +35,7 @@
 #include "common/extent-cache.h"
 #include "common/internal.h"
 #include "common/messages.h"
+#include "common/extent-tree-utils.h"
 #include "convert/common.h"
 #include "convert/source-reiserfs.h"
 
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 8eba7812..eae233b9 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -3195,30 +3195,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 3e00d69b..c7d5167d 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -929,11 +929,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,
@@ -956,8 +951,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 55fdf881..433cf4fc 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -3519,240 +3519,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 bb2666ee..c42c7a20 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -40,6 +40,7 @@
 #include "common/messages.h"
 #include "common/path-utils.h"
 #include "common/utils.h"
+#include "common/extent-tree-utils.h"
 #include "mkfs/rootdir.h"
 
 static u32 fs_block_size;
diff --git a/tune/change-csum.c b/tune/change-csum.c
index 9edddb05..cf895df7 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -28,6 +28,7 @@
 #include "common/internal.h"
 #include "common/utils.h"
 #include "common/inject-error.h"
+#include "common/extent-tree-utils.h"
 #include "tune/tune.h"
 
 static int check_csum_change_requreiment(struct btrfs_fs_info *fs_info, u16 new_csum_type)
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 16/38] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (14 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 15/38] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 17/38] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
                   ` (23 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 a32c9a2a..9796085d 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -1505,6 +1505,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.
+ */
+static 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;
@@ -1535,7 +1586,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 17/38] btrfs-progs: don't set the ->commit_root in btrfs_create_tree
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (15 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 16/38] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 18/38] btrfs-progs: remove btrfs_create_root Josef Bacik
                   ` (22 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 35b6cde9..c98addd2 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2340,7 +2340,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 18/38] btrfs-progs: remove btrfs_create_root
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (16 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 17/38] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 19/38] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
                   ` (21 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 | 117 ------------------------------------------
 kernel-shared/ctree.h |   2 -
 mkfs/main.c           |  14 +++--
 tune/convert-bgt.c    |  13 +++--
 4 files changed, 20 insertions(+), 126 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index eae233b9..1e45f756 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -341,123 +341,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_fsid(node, fs_info->fs_devices->metadata_uuid);
-	write_extent_buffer_chunk_tree_uuid(node, fs_info->chunk_tree_uuid);
-	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;
-
-	/*
-	 * 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 c7d5167d..26cdae92 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -959,8 +959,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 4de57c8a..5d98ab69 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/convert-bgt.c b/tune/convert-bgt.c
index a2915376..15ec1042 100644
--- a/tune/convert-bgt.c
+++ b/tune/convert-bgt.c
@@ -31,7 +31,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;
 
@@ -51,12 +56,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 19/38] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (17 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 18/38] btrfs-progs: remove btrfs_create_root Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 20/38] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
                   ` (20 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 1e45f756..ae6c03f9 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -3077,136 +3077,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 26cdae92..ec81a46c 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1133,8 +1133,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 5d98ab69..9f824727 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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 20/38] btrfs-progs: make btrfs_del_ptr a void
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (18 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 19/38] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 21/38] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
                   ` (19 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 b8bcf5c3..a33a300a 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 ae6c03f9..91127933 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -853,9 +853,7 @@ static noinline 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,
@@ -900,9 +898,7 @@ static noinline 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,
@@ -2716,12 +2712,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) {
@@ -2745,7 +2740,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;
 }
 
 /*
@@ -2766,9 +2760,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 ec81a46c..a1c09d97 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -942,7 +942,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 21/38] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (19 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 20/38] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 22/38] btrfs-progs: use path->search_for_extension Josef Bacik
                   ` (18 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 a33a300a..08c49f7a 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 e12dc61c..89b778d5 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 91127933..e3b29a3a 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -307,9 +307,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 	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);
@@ -489,9 +488,8 @@ static noinline 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);
@@ -1566,9 +1564,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))
@@ -1688,10 +1685,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);
 
@@ -2251,10 +2247,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 a1c09d97..0b440b1a 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -886,7 +886,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 c98addd2..286eb9cb 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -2319,9 +2319,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 433cf4fc..439ac530 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -2479,7 +2479,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,
@@ -2490,6 +2490,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);
 
@@ -2536,7 +2537,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;
@@ -2548,7 +2549,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)
@@ -2557,7 +2558,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 22/38] btrfs-progs: use path->search_for_extension
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (20 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 21/38] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 23/38] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
                   ` (17 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 439ac530..10482652 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -881,10 +881,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;
@@ -1022,6 +1024,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 7baa5614..54d7c094 100644
--- a/kernel-shared/file-item.c
+++ b/kernel-shared/file-item.c
@@ -257,8 +257,10 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
 	 * 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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 23/38] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (21 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 22/38] btrfs-progs: use path->search_for_extension Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 24/38] btrfs-progs: add dwarves to the package list for ci Josef Bacik
                   ` (16 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 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 10482652..4ddf5222 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -2558,6 +2558,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;
@@ -2578,6 +2579,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.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 24/38] btrfs-progs: add dwarves to the package list for ci
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (22 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 23/38] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 25/38] btrfs-progs: add kerncompat helpers for ctree.c sync Josef Bacik
                   ` (15 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

We run pahole for the ioctl-test, which requires the dwarves package.
Add that to the docker images.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 ci/images/ci-centos-7-x86_64/Dockerfile            | 2 +-
 ci/images/ci-centos-8-x86_64/Dockerfile            | 2 +-
 ci/images/ci-musl-x86_64/Dockerfile                | 2 +-
 ci/images/ci-openSUSE-Leap-15.3-x86_64/Dockerfile  | 2 +-
 ci/images/ci-openSUSE-Leap-15.4-x86_64/Dockerfile  | 2 +-
 ci/images/ci-openSUSE-tumbleweed-x86_64/Dockerfile | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/ci/images/ci-centos-7-x86_64/Dockerfile b/ci/images/ci-centos-7-x86_64/Dockerfile
index ccf0bc2d..89beef70 100644
--- a/ci/images/ci-centos-7-x86_64/Dockerfile
+++ b/ci/images/ci-centos-7-x86_64/Dockerfile
@@ -10,7 +10,7 @@ RUN yum -y install autoconf automake pkg-config
 RUN yum -y install libattr-devel libblkid-devel libuuid-devel
 RUN yum -y install e2fsprogs-libs e2fsprogs-devel reiserfs-utils
 RUN yum -y install zlib-devel lzo-devel libzstd-devel zstd-devel zstd
-RUN yum -y install make gcc tar gzip clang
+RUN yum -y install make gcc tar gzip clang dwarves
 RUN yum -y install python3 python3-devel python3-setuptools
 
 # For downloading fresh sources
diff --git a/ci/images/ci-centos-8-x86_64/Dockerfile b/ci/images/ci-centos-8-x86_64/Dockerfile
index edc9ed90..e8ef1c8b 100644
--- a/ci/images/ci-centos-8-x86_64/Dockerfile
+++ b/ci/images/ci-centos-8-x86_64/Dockerfile
@@ -13,7 +13,7 @@ RUN yum -y install autoconf automake pkg-config
 RUN yum -y install libattr-devel libblkid-devel libuuid-devel
 RUN yum -y install e2fsprogs-libs e2fsprogs-devel
 RUN yum -y install zlib-devel lzo-devel libzstd-devel zstd
-RUN yum -y install make gcc tar gzip clang
+RUN yum -y install make gcc tar gzip clang dwarves
 RUN yum -y install python3 python3-devel python3-setuptools
 
 # For downloading fresh sources
diff --git a/ci/images/ci-musl-x86_64/Dockerfile b/ci/images/ci-musl-x86_64/Dockerfile
index 16c1a123..43455365 100644
--- a/ci/images/ci-musl-x86_64/Dockerfile
+++ b/ci/images/ci-musl-x86_64/Dockerfile
@@ -7,7 +7,7 @@ RUN apk add linux-headers musl-dev util-linux-dev bash
 RUN apk add attr-dev acl-dev e2fsprogs-dev zlib-dev lzo-dev zstd-dev
 RUN apk add autoconf automake make gcc tar gzip clang
 RUN apk add python3 py3-setuptools python3-dev
-RUN apk add libgcrypt-dev libsodium-dev libkcapi-dev
+RUN apk add libgcrypt-dev libsodium-dev libkcapi-dev dwarves
 
 # For downloading fresh sources
 RUN apk add wget
diff --git a/ci/images/ci-openSUSE-Leap-15.3-x86_64/Dockerfile b/ci/images/ci-openSUSE-Leap-15.3-x86_64/Dockerfile
index 11cf0dde..aafd210a 100644
--- a/ci/images/ci-openSUSE-Leap-15.3-x86_64/Dockerfile
+++ b/ci/images/ci-openSUSE-Leap-15.3-x86_64/Dockerfile
@@ -8,7 +8,7 @@ RUN zypper install -y --no-recommends libext2fs-devel libreiserfscore-devel
 RUN zypper install -y --no-recommends zlib-devel lzo-devel libzstd-devel
 RUN zypper install -y --no-recommends make gcc tar gzip clang
 RUN zypper install -y --no-recommends python3 python3-devel python3-setuptools
-RUN zypper install -y --no-recommends libudev-devel
+RUN zypper install -y --no-recommends libudev-devel dwarves
 
 # For downloading fresh sources
 RUN zypper install -y --no-recommends wget
diff --git a/ci/images/ci-openSUSE-Leap-15.4-x86_64/Dockerfile b/ci/images/ci-openSUSE-Leap-15.4-x86_64/Dockerfile
index 0b0f584a..7d3c7a6d 100644
--- a/ci/images/ci-openSUSE-Leap-15.4-x86_64/Dockerfile
+++ b/ci/images/ci-openSUSE-Leap-15.4-x86_64/Dockerfile
@@ -8,7 +8,7 @@ RUN zypper install -y --no-recommends libext2fs-devel libreiserfscore-devel
 RUN zypper install -y --no-recommends zlib-devel lzo-devel libzstd-devel
 RUN zypper install -y --no-recommends make gcc tar gzip clang
 RUN zypper install -y --no-recommends python3 python3-devel python3-setuptools
-RUN zypper install -y --no-recommends libudev-devel
+RUN zypper install -y --no-recommends libudev-devel dwarves
 
 # For downloading fresh sources
 RUN zypper install -y --no-recommends wget
diff --git a/ci/images/ci-openSUSE-tumbleweed-x86_64/Dockerfile b/ci/images/ci-openSUSE-tumbleweed-x86_64/Dockerfile
index 6487957e..fe543314 100644
--- a/ci/images/ci-openSUSE-tumbleweed-x86_64/Dockerfile
+++ b/ci/images/ci-openSUSE-tumbleweed-x86_64/Dockerfile
@@ -9,7 +9,7 @@ RUN zypper install -y --no-recommends libext2fs-devel
 RUN zypper install -y --no-recommends zlib-devel lzo-devel libzstd-devel
 RUN zypper install -y --no-recommends autoconf automake pkg-config
 RUN zypper install -y --no-recommends python3 python3-devel python3-setuptools
-RUN zypper install -y --no-recommends libudev-devel
+RUN zypper install -y --no-recommends libudev-devel dwarves
 
 # For downloading fresh sources
 RUN zypper install -y --no-recommends wget
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 25/38] btrfs-progs: add kerncompat helpers for ctree.c sync
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (23 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 24/38] btrfs-progs: add dwarves to the package list for ci Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 26/38] btrfs-progs: add trans_lock to fs_info Josef Bacik
                   ` (14 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

Here are the helpers and stubbed out functions to be able to sync in
ctree.c into btrfs-progs.  These are various utilities the kernel
provides, 1 relocation and qgroup related function, and a trace point we
have in ctree.c.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 include/kerncompat.h | 76 ++++++++++++++++++++++++++++++++++++++++++++
 kernel-lib/trace.h   |  6 ++++
 2 files changed, 82 insertions(+)

diff --git a/include/kerncompat.h b/include/kerncompat.h
index 0f73efcd..4ba6b3dc 100644
--- a/include/kerncompat.h
+++ b/include/kerncompat.h
@@ -201,6 +201,10 @@ typedef struct spinlock_struct {
 	unsigned long lock;
 } spinlock_t;
 
+struct rw_semaphore {
+	long lock;
+};
+
 #define mutex_init(m)						\
 do {								\
 	(m)->lock = 1;						\
@@ -243,6 +247,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,26 @@ static inline void schedule(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 +892,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 588429e0..2542f9ea 100644
--- a/kernel-lib/trace.h
+++ b/kernel-lib/trace.h
@@ -57,4 +57,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__ */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 26/38] btrfs-progs: add trans_lock to fs_info
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (24 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 25/38] btrfs-progs: add kerncompat helpers for ctree.c sync Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 27/38] btrfs-progs: add commit_root_sem to btrfs_fs_info Josef Bacik
                   ` (13 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

This exists in the kernel, and is touched by ctree.c, add it to the
btrfs_fs_info to make sync'ing ctree.c more straightforward.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.h   | 2 ++
 kernel-shared/disk-io.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 0b440b1a..6ceae3e9 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -324,6 +324,8 @@ struct btrfs_fs_info {
 	struct extent_io_tree extent_ins;
 	struct extent_io_tree *excluded_extents;
 
+	spinlock_t trans_lock;
+
 	struct rb_root block_group_cache_tree;
 	/* logical->physical extent mapping */
 	struct btrfs_mapping_tree mapping_tree;
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index 286eb9cb..4f87b6fb 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -870,6 +870,8 @@ 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);
+
 	if (!writable)
 		fs_info->readonly = 1;
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 27/38] btrfs-progs: add commit_root_sem to btrfs_fs_info
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (25 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 26/38] btrfs-progs: add trans_lock to fs_info Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 28/38] btrfs-progs: update btrfs_cow_block to match the in-kernel definition Josef Bacik
                   ` (12 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

This is used in ctree.c around getting the old root, add this to our
btrfs_fs_info to make it more straightforward to sync ctree.c into
btrfs-progs.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.h   | 1 +
 kernel-shared/disk-io.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 6ceae3e9..2f6a0cab 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -325,6 +325,7 @@ struct btrfs_fs_info {
 	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 */
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index 4f87b6fb..092b54af 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -871,6 +871,7 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
 	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;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 28/38] btrfs-progs: update btrfs_cow_block to match the in-kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (26 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 27/38] btrfs-progs: add commit_root_sem to btrfs_fs_info Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 29/38] btrfs-progs: update btrfs_insert_empty_items to match the kernel Josef Bacik
                   ` (11 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

btrfs_cow_block takes the lockdep nesting enum in the kernel.  Update
the definition to match the kernel version to make sync'ing ctree.c into
btrfs-progs more straightforward.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c       | 24 +++++++++++++++---------
 kernel-shared/ctree.h       |  3 ++-
 kernel-shared/transaction.c |  3 ++-
 3 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index e3b29a3a..13f8a437 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -557,7 +557,8 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
 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)
 {
 	u64 search_start;
 	int ret;
@@ -788,7 +789,8 @@ static noinline 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);
+		ret = btrfs_cow_block(trans, root, child, mid, 0, &child,
+				      BTRFS_NESTING_NORMAL);
 		BUG_ON(ret);
 
 		root->node = child;
@@ -813,7 +815,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 	left = btrfs_read_node_slot(parent, pslot - 1);
 	if (extent_buffer_uptodate(left)) {
 		wret = btrfs_cow_block(trans, root, left,
-				       parent, pslot - 1, &left);
+				       parent, pslot - 1, &left,
+				       BTRFS_NESTING_NORMAL);
 		if (wret) {
 			ret = wret;
 			goto enospc;
@@ -822,7 +825,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 	right = btrfs_read_node_slot(parent, pslot + 1);
 	if (extent_buffer_uptodate(right)) {
 		wret = btrfs_cow_block(trans, root, right,
-				       parent, pslot + 1, &right);
+				       parent, pslot + 1, &right,
+				       BTRFS_NESTING_NORMAL);
 		if (wret) {
 			ret = wret;
 			goto enospc;
@@ -980,7 +984,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 			wret = 1;
 		} else {
 			ret = btrfs_cow_block(trans, root, left, parent,
-					      pslot - 1, &left);
+					      pslot - 1, &left,
+					      BTRFS_NESTING_NORMAL);
 			if (ret)
 				wret = 1;
 			else {
@@ -1023,7 +1028,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 		} else {
 			ret = btrfs_cow_block(trans, root, right,
 					      parent, pslot + 1,
-					      &right);
+					      &right, BTRFS_NESTING_NORMAL);
 			if (ret)
 				wret = 1;
 			else {
@@ -1213,7 +1218,7 @@ again:
 			wret = btrfs_cow_block(trans, root, b,
 					       p->nodes[level + 1],
 					       p->slots[level + 1],
-					       &b);
+					       &b, BTRFS_NESTING_NORMAL);
 			if (wret) {
 				free_extent_buffer(b);
 				return wret;
@@ -1822,7 +1827,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
 
 	/* cow and double check */
 	ret = btrfs_cow_block(trans, root, right, upper,
-			      slot + 1, &right);
+			      slot + 1, &right, BTRFS_NESTING_NORMAL);
 	if (ret) {
 		free_extent_buffer(right);
 		return 1;
@@ -1968,7 +1973,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
 
 	/* 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_NORMAL);
 	if (ret) {
 		/* we hit -ENOSPC, but it isn't fatal here */
 		free_extent_buffer(left);
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 2f6a0cab..07a5992c 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -957,7 +957,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,
diff --git a/kernel-shared/transaction.c b/kernel-shared/transaction.c
index 87d86fcd..48947d10 100644
--- a/kernel-shared/transaction.c
+++ b/kernel-shared/transaction.c
@@ -100,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;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 29/38] btrfs-progs: update btrfs_insert_empty_items to match the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (27 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 28/38] btrfs-progs: update btrfs_cow_block to match the in-kernel definition Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 30/38] btrfs-progs: update btrfs_insert_empty_item " Josef Bacik
                   ` (10 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel we have a control struct called btrfs_item_batch that
encodes all of the information for bulk inserting a bunch of items.
Update btrfs_insert_empty_times to match the in-kernel implementation to
make sync'ing ctree.c more straightforward.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 36 +++++++++++++++++-------------------
 kernel-shared/ctree.h | 37 +++++++++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 13f8a437..c3b86e2e 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2576,8 +2576,7 @@ void btrfs_extend_item(struct btrfs_path *path, 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)
 {
 	struct extent_buffer *leaf;
 	int ret = 0;
@@ -2585,20 +2584,16 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
 	int i;
 	u32 nritems;
 	u32 total_size = 0;
-	u32 total_data = 0;
 	unsigned int data_end;
 	struct btrfs_disk_key disk_key;
 
-	for (i = 0; i < nr; i++) {
-		total_data += data_size[i];
-	}
-
 	/* 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);
+	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;
 	}
@@ -2637,35 +2632,38 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
 			u32 ioff;
 
 			ioff = btrfs_item_offset(leaf, i);
-			btrfs_set_item_offset(leaf, i, ioff - total_data);
+			btrfs_set_item_offset(leaf, i,
+					      ioff - batch->total_data_size);
 		}
 
 		/* shift the items */
-		memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot + nr),
+		memmove_extent_buffer(leaf,
+			      btrfs_item_nr_offset(leaf, slot + batch->nr),
 			      btrfs_item_nr_offset(leaf, slot),
 			      (nritems - slot) * sizeof(struct btrfs_item));
 
 		/* 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 - batch->total_data_size,
+			      btrfs_item_nr_offset(leaf, 0) +
 			      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_item_offset(leaf, slot + i, data_end);
+		btrfs_set_item_size(leaf, slot + i, batch->data_sizes[i]);
 	}
-	btrfs_set_header_nritems(leaf, nritems + nr);
+	btrfs_set_header_nritems(leaf, nritems + batch->nr);
 	btrfs_mark_buffer_dirty(leaf);
 
 	ret = 0;
 	if (slot == 0) {
-		btrfs_cpu_key_to_disk(&disk_key, cpu_key);
+		btrfs_cpu_key_to_disk(&disk_key, &batch->keys[0]);
 		fixup_low_keys(path, &disk_key, 1);
 	}
 
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 07a5992c..d2b1b421 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -995,12 +995,38 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
 	return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
+/*
+ * 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, 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,
@@ -1008,7 +1034,14 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 					  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,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 30/38] btrfs-progs: update btrfs_insert_empty_item to match the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (28 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 29/38] btrfs-progs: update btrfs_insert_empty_items to match the kernel Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 31/38] btrfs-progs: update btrfs_del_ptr " Josef Bacik
                   ` (9 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel the key for btrfs_insert_empty_item is a const, update the
helper to match the in-kernel version.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index d2b1b421..ce2122d7 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1031,7 +1031,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
 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)
 {
 	struct btrfs_item_batch batch;
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 31/38] btrfs-progs: update btrfs_del_ptr to match the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (29 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 30/38] btrfs-progs: update btrfs_insert_empty_item " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 32/38] btrfs-progs: update btrfs_insert_item " Josef Bacik
                   ` (8 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

The kernel version of btrfs_del_ptr takes a trans handle as an argument
and returns an error in the case of tree-mod-log, update our version to
match to make syncing ctree.c more straightforward.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 check/main.c          |  4 ++--
 kernel-shared/ctree.c | 12 +++++++-----
 kernel-shared/ctree.h |  4 ++--
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/check/main.c b/check/main.c
index 08c49f7a..04c965ab 100644
--- a/check/main.c
+++ b/check/main.c
@@ -3569,7 +3569,7 @@ static int repair_btree(struct btrfs_root *root,
 					     path.slots[level]);
 
 		/* Remove the ptr */
-		btrfs_del_ptr(root, &path, level, path.slots[level]);
+		btrfs_del_ptr(trans, root, &path, level, path.slots[level]);
 
 		/*
 		 * Remove the corresponding extent
@@ -7828,7 +7828,7 @@ again:
 
 del_ptr:
 	printk("deleting pointer to block %llu\n", corrupt->cache.start);
-	btrfs_del_ptr(extent_root, &path, level, slot);
+	btrfs_del_ptr(trans, extent_root, &path, level, slot);
 
 out:
 	btrfs_release_path(&path);
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index c3b86e2e..47938f01 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -855,7 +855,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 			btrfs_clear_buffer_dirty(trans, right);
 			free_extent_buffer(right);
 			right = NULL;
-			btrfs_del_ptr(root, path, level + 1, pslot + 1);
+			btrfs_del_ptr(trans, root, path, level + 1, pslot + 1);
 
 			root_sub_used(root, blocksize);
 			wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
@@ -900,7 +900,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 		btrfs_clear_buffer_dirty(trans, mid);
 		free_extent_buffer(mid);
 		mid = NULL;
-		btrfs_del_ptr(root, path, level + 1, pslot);
+		btrfs_del_ptr(trans, root, path, level + 1, pslot);
 
 		root_sub_used(root, blocksize);
 		wret = btrfs_free_extent(trans, bytenr, blocksize, 0,
@@ -2711,8 +2711,8 @@ 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.
  */
-void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
-		int level, int slot)
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+		  struct btrfs_path *path, int level, int slot)
 {
 	struct extent_buffer *parent = path->nodes[level];
 	u32 nritems;
@@ -2739,6 +2739,8 @@ void 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 0;
 }
 
 /*
@@ -2759,7 +2761,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
 	int ret;
 
 	WARN_ON(btrfs_header_generation(leaf) != trans->transid);
-	btrfs_del_ptr(root, path, 1, path->slots[1]);
+	btrfs_del_ptr(trans, 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 ce2122d7..d15c16c0 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -945,8 +945,8 @@ 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);
-void btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
-		int level, int slot);
+int btrfs_del_ptr(struct btrfs_trans_handle *trans, 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);
 int btrfs_previous_item(struct btrfs_root *root,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 32/38] btrfs-progs: update btrfs_insert_item to match the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (30 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 31/38] btrfs-progs: update btrfs_del_ptr " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:32 ` [PATCH 33/38] btrfs-progs: update btrfs_leaf_free_space " Josef Bacik
                   ` (7 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

This has const struct btrfs_key instead of just struct btrfs_key, update
this to make it more straightforward to sync ctree.c.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 6 +++---
 kernel-shared/ctree.h | 5 +++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 47938f01..5355d385 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2680,9 +2680,9 @@ out:
  * 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;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index d15c16c0..5551d256 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1021,8 +1021,9 @@ struct btrfs_item_batch {
 	int nr;
 };
 
-int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_key *key, void *data, u32 data_size);
+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,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 33/38] btrfs-progs: update btrfs_leaf_free_space to match the kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (31 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 32/38] btrfs-progs: update btrfs_insert_item " Josef Bacik
@ 2023-08-23 14:32 ` Josef Bacik
  2023-08-23 14:33 ` [PATCH 34/38] btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer Josef Bacik
                   ` (6 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:32 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel we have const struct extent_buffer instead of struct
extent_buffer, update this to make it more straightforward to sync
ctree.c.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 4 ++--
 kernel-shared/ctree.h | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 5355d385..e95839bd 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1740,7 +1740,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
  * and nr indicate which items in the leaf to check.  This totals up the
  * space used both by the item structs and the item data
  */
-static int leaf_space_used(struct extent_buffer *l, int start, int nr)
+static int leaf_space_used(const struct extent_buffer *l, int start, int nr)
 {
 	int data_len;
 	int nritems = btrfs_header_nritems(l);
@@ -1760,7 +1760,7 @@ 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)
+int btrfs_leaf_free_space(const struct extent_buffer *leaf)
 {
 	int nritems = btrfs_header_nritems(leaf);
 	u32 leaf_data_size;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 5551d256..67c5a6f8 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1080,7 +1080,7 @@ 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);
+int btrfs_leaf_free_space(const 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);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 34/38] btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (32 preceding siblings ...)
  2023-08-23 14:32 ` [PATCH 33/38] btrfs-progs: update btrfs_leaf_free_space " Josef Bacik
@ 2023-08-23 14:33 ` Josef Bacik
  2023-08-23 14:33 ` [PATCH 35/38] btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check Josef Bacik
                   ` (5 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:33 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel we have a control structure call btrfs_tree_parent_check
to pass around the various sanity checks we have for extent buffers.
Add this to btrfs_tree_parent_check and then update the callers.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/disk-io.c | 18 ++++++++++++++----
 kernel-shared/disk-io.h |  6 ++++--
 tune/change-csum.c      |  4 +++-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index 092b54af..ef5ea391 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -332,8 +332,8 @@ int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirr
 	return 0;
 }
 
-int btrfs_read_extent_buffer(struct extent_buffer *eb, u64 parent_transid,
-			     int level, struct btrfs_key *first_key)
+int btrfs_read_extent_buffer(struct extent_buffer *eb,
+			     struct btrfs_tree_parent_check *check)
 {
 	struct btrfs_fs_info *fs_info = eb->fs_info;
 	int ret;
@@ -349,7 +349,7 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb, u64 parent_transid,
 		ret = read_whole_eb(fs_info, eb, mirror_num);
 		if (ret == 0 && csum_tree_block(fs_info, eb, 1) == 0 &&
 		    check_tree_block(fs_info, eb) == 0 &&
-		    verify_parent_transid(eb, parent_transid, ignore) == 0) {
+		    verify_parent_transid(eb, check->transid, ignore) == 0) {
 			if (eb->flags & EXTENT_BUFFER_BAD_TRANSID &&
 			    list_empty(&eb->recow)) {
 				list_add_tail(&eb->recow,
@@ -420,10 +420,20 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
 				      u64 owner_root, u64 parent_transid,
 				      int level, struct btrfs_key *first_key)
 {
+	struct btrfs_tree_parent_check check = {
+		.owner_root = owner_root,
+		.transid = parent_transid,
+		.level = level,
+	};
 	int ret;
 	struct extent_buffer *eb;
 	u32 sectorsize = fs_info->sectorsize;
 
+	if (first_key) {
+		check.has_first_key = true;
+		memcpy(&check.first_key, first_key, sizeof(*first_key));
+	}
+
 	/*
 	 * Don't even try to create tree block for unaligned tree block
 	 * bytenr.
@@ -443,7 +453,7 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
 	if (btrfs_buffer_uptodate(eb, parent_transid, 0))
 		return eb;
 
-	ret = btrfs_read_extent_buffer(eb, parent_transid, level, first_key);
+	ret = btrfs_read_extent_buffer(eb, &check);
 	if (ret) {
 		/*
 		 * We failed to read this tree block, it be should deleted right
diff --git a/kernel-shared/disk-io.h b/kernel-shared/disk-io.h
index 424b953e..78c6e8c7 100644
--- a/kernel-shared/disk-io.h
+++ b/kernel-shared/disk-io.h
@@ -23,6 +23,8 @@
 #include "kernel-shared/ctree.h"
 #include "kernel-lib/sizes.h"
 
+struct btrfs_tree_parent_check;
+
 #define BTRFS_SUPER_MIRROR_MAX	 3
 #define BTRFS_SUPER_MIRROR_SHIFT 12
 
@@ -238,8 +240,8 @@ int btrfs_global_root_insert(struct btrfs_fs_info *fs_info,
 int btrfs_find_and_setup_root(struct btrfs_root *tree_root,
 			      struct btrfs_fs_info *fs_info,
 			      u64 objectid, struct btrfs_root *root);
-int btrfs_read_extent_buffer(struct extent_buffer *eb, u64 parent_transid,
-			     int level, struct btrfs_key *first_key);
+int btrfs_read_extent_buffer(struct extent_buffer *eb,
+			     struct btrfs_tree_parent_check *check);
 
 static inline struct btrfs_root *btrfs_block_group_root(
 						struct btrfs_fs_info *fs_info)
diff --git a/tune/change-csum.c b/tune/change-csum.c
index cf895df7..f12a2832 100644
--- a/tune/change-csum.c
+++ b/tune/change-csum.c
@@ -24,6 +24,7 @@
 #include "kernel-shared/file-item.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/transaction.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/messages.h"
 #include "common/internal.h"
 #include "common/utils.h"
@@ -494,6 +495,7 @@ static int rewrite_tree_block_csum(struct btrfs_fs_info *fs_info, u64 logical,
 				   u16 new_csum_type)
 {
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 	u8 result_old[BTRFS_CSUM_SIZE];
 	u8 result_new[BTRFS_CSUM_SIZE];
 	int ret;
@@ -502,7 +504,7 @@ static int rewrite_tree_block_csum(struct btrfs_fs_info *fs_info, u64 logical,
 	if (!eb)
 		return -ENOMEM;
 
-	ret = btrfs_read_extent_buffer(eb, 0, 0, NULL);
+	ret = btrfs_read_extent_buffer(eb, &check);
 	if (ret < 0) {
 		errno = -ret;
 		error("failed to read tree block at logical %llu: %m", logical);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 35/38] btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (33 preceding siblings ...)
  2023-08-23 14:33 ` [PATCH 34/38] btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer Josef Bacik
@ 2023-08-23 14:33 ` Josef Bacik
  2023-08-23 14:33 ` [PATCH 36/38] btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash Josef Bacik
                   ` (4 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:33 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel we've added a control struct to handle the different
checks we want to do on extent buffers when we read them.  Update our
copy of read_tree_block to take this as an argument, then update all of
the callers to use the new structure.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 btrfs-corrupt-block.c      | 16 +++++++++++-----
 btrfs-find-root.c          |  5 ++++-
 check/main.c               | 21 +++++++++++++++------
 check/mode-common.c        |  7 +++++--
 check/mode-lowmem.c        | 25 ++++++++++++++++++-------
 check/qgroup-verify.c      |  7 +++++--
 check/repair.c             | 16 ++++++++++------
 cmds/inspect-dump-tree.c   | 20 ++++++++++++++------
 cmds/inspect-tree-stats.c  | 11 +++++++----
 cmds/restore.c             | 13 ++++++++-----
 image/image-create.c       | 10 ++++++----
 image/image-restore.c      |  6 ++++--
 image/main.c               |  1 +
 kernel-shared/backref.c    | 17 +++++++++++++----
 kernel-shared/ctree.c      |  9 ++++++---
 kernel-shared/disk-io.c    | 26 ++++++++++----------------
 kernel-shared/disk-io.h    |  3 +--
 kernel-shared/print-tree.c | 10 +++++++---
 tune/change-uuid.c         |  4 +++-
 19 files changed, 148 insertions(+), 79 deletions(-)

diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 3e741c08..432dc859 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -29,6 +29,7 @@
 #include "kernel-shared/transaction.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/utils.h"
 #include "common/help.h"
 #include "common/extent-cache.h"
@@ -172,8 +173,9 @@ static void corrupt_keys(struct btrfs_trans_handle *trans,
 static int corrupt_keys_in_block(struct btrfs_fs_info *fs_info, u64 bytenr)
 {
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 
-	eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+	eb = read_tree_block(fs_info, bytenr, &check);
 	if (!extent_buffer_uptodate(eb))
 		return -EIO;;
 
@@ -301,11 +303,14 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
 
 	for (i = 0; i < btrfs_header_nritems(eb); i++) {
 		struct extent_buffer *next;
+		struct btrfs_tree_parent_check check = {
+			.owner_root = btrfs_header_owner(eb),
+			.transid = btrfs_node_ptr_generation(eb, i),
+			.level = btrfs_header_level(eb) - 1,
+		};
 
 		next = read_tree_block(fs_info, btrfs_node_blockptr(eb, i),
-				       btrfs_header_owner(eb),
-				       btrfs_node_ptr_generation(eb, i),
-				       btrfs_header_level(eb) - 1, NULL);
+				       &check);
 		if (!extent_buffer_uptodate(next))
 			continue;
 		btrfs_corrupt_extent_tree(trans, root, next);
@@ -860,6 +865,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
 				  char *field)
 {
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 	enum btrfs_metadata_block_field corrupt_field;
 	int ret;
 
@@ -869,7 +875,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
 		return -EINVAL;
 	}
 
-	eb = read_tree_block(fs_info, block, 0, 0, 0, NULL);
+	eb = read_tree_block(fs_info, block, &check);
 	if (!extent_buffer_uptodate(eb)) {
 		error("couldn't read in tree block %s", field);
 		return -EINVAL;
diff --git a/btrfs-find-root.c b/btrfs-find-root.c
index 6e32859f..32d32429 100644
--- a/btrfs-find-root.c
+++ b/btrfs-find-root.c
@@ -25,6 +25,7 @@
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/volumes.h"
 #include "kernel-shared/extent_io.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/box.h"
 #include "common/utils.h"
 #include "common/extent-cache.h"
@@ -200,7 +201,9 @@ int btrfs_find_root_search(struct btrfs_fs_info *fs_info,
 		for (offset = chunk_offset;
 		     offset < chunk_offset + chunk_size;
 		     offset += nodesize) {
-			eb = read_tree_block(fs_info, offset, 0, 0, 0, NULL);
+			struct btrfs_tree_parent_check check = { 0 };
+
+			eb = read_tree_block(fs_info, offset, &check);
 			if (!eb || IS_ERR(eb))
 				continue;
 			ret = add_eb_to_result(eb, result, nodesize, filter,
diff --git a/check/main.c b/check/main.c
index 04c965ab..08e6a94b 100644
--- a/check/main.c
+++ b/check/main.c
@@ -1894,11 +1894,15 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
 
 		next = btrfs_find_tree_block(gfs_info, bytenr, gfs_info->nodesize);
 		if (!next || !btrfs_buffer_uptodate(next, ptr_gen, 0)) {
+			struct btrfs_tree_parent_check check = {
+				.owner_root = btrfs_header_owner(cur),
+				.transid = ptr_gen,
+				.level = *level - 1,
+			};
+
 			free_extent_buffer(next);
 			reada_walk_down(root, cur, path->slots[*level]);
-			next = read_tree_block(gfs_info, bytenr,
-					       btrfs_header_owner(cur), ptr_gen,
-					       *level - 1, NULL);
+			next = read_tree_block(gfs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(next)) {
 				struct btrfs_key node_key;
 
@@ -6196,6 +6200,7 @@ static int run_next_block(struct btrfs_root *root,
 {
 	struct extent_buffer *buf;
 	struct extent_record *rec = NULL;
+	struct btrfs_tree_parent_check check = { 0 };
 	u64 bytenr;
 	u32 size;
 	u64 parent;
@@ -6252,7 +6257,8 @@ static int run_next_block(struct btrfs_root *root,
 	}
 
 	/* fixme, get the real parent transid */
-	buf = read_tree_block(gfs_info, bytenr, 0, gen, 0, NULL);
+	check.transid = gen;
+	buf = read_tree_block(gfs_info, bytenr, &check);
 	if (!extent_buffer_uptodate(buf)) {
 		record_bad_block_io(extent_cache, bytenr, size);
 		goto out;
@@ -8586,12 +8592,15 @@ static int deal_root_from_list(struct list_head *list,
 	while (!list_empty(list)) {
 		struct root_item_record *rec;
 		struct extent_buffer *buf;
+		struct btrfs_tree_parent_check check = { 0 };
 
 		rec = list_entry(list->next,
 				 struct root_item_record, list);
 		last = 0;
-		buf = read_tree_block(gfs_info, rec->bytenr, rec->objectid, 0,
-				      rec->level, NULL);
+
+		check.owner_root = rec->objectid;
+		check.level = rec->level;
+		buf = read_tree_block(gfs_info, rec->bytenr, &check);
 		if (!extent_buffer_uptodate(buf)) {
 			free_extent_buffer(buf);
 			ret = -EIO;
diff --git a/check/mode-common.c b/check/mode-common.c
index 71e735c4..f6cdcee3 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -29,6 +29,7 @@
 #include "kernel-shared/backref.h"
 #include "kernel-shared/compression.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/internal.h"
 #include "common/messages.h"
 #include "common/utils.h"
@@ -127,11 +128,12 @@ next:
 static int check_prealloc_shared_data_ref(u64 parent, u64 disk_bytenr)
 {
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 	u32 nr;
 	int i;
 	int ret = 0;
 
-	eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
+	eb = read_tree_block(gfs_info, parent, &check);
 	if (!extent_buffer_uptodate(eb)) {
 		ret = -EIO;
 		goto out;
@@ -1116,8 +1118,9 @@ int get_extent_item_generation(u64 bytenr, u64 *gen_ret)
 	if (btrfs_extent_flags(path.nodes[0], ei) &
 	    BTRFS_EXTENT_FLAG_TREE_BLOCK) {
 		struct extent_buffer *eb;
+		struct btrfs_tree_parent_check check = { 0 };
 
-		eb = read_tree_block(gfs_info, bytenr, 0, 0, 0, NULL);
+		eb = read_tree_block(gfs_info, bytenr, &check);
 		if (extent_buffer_uptodate(eb)) {
 			*gen_ret = btrfs_header_generation(eb);
 			ret = 0;
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
index 35bca857..0189a656 100644
--- a/check/mode-lowmem.c
+++ b/check/mode-lowmem.c
@@ -3684,6 +3684,7 @@ static int query_tree_block_level(u64 bytenr)
 	struct btrfs_path path = {};
 	struct btrfs_key key;
 	struct btrfs_extent_item *ei;
+	struct btrfs_tree_parent_check check = { 0 };
 	u64 flags;
 	u64 transid;
 	u8 backref_level;
@@ -3731,7 +3732,8 @@ static int query_tree_block_level(u64 bytenr)
 	btrfs_release_path(&path);
 
 	/* Get level from tree block as an alternative source */
-	eb = read_tree_block(gfs_info, bytenr, 0, transid, 0, NULL);
+	check.transid = transid;
+	eb = read_tree_block(gfs_info, bytenr, &check);
 	if (!extent_buffer_uptodate(eb)) {
 		free_extent_buffer(eb);
 		return -EIO;
@@ -3760,6 +3762,9 @@ static int check_tree_block_backref(u64 root_id, u64 bytenr, int level)
 	struct btrfs_path path = {};
 	struct extent_buffer *eb;
 	struct extent_buffer *node;
+	struct btrfs_tree_parent_check check = {
+		.owner_root = root_id,
+	};
 	u32 nodesize = btrfs_super_nodesize(gfs_info->super_copy);
 	int err = 0;
 	int ret;
@@ -3783,7 +3788,7 @@ static int check_tree_block_backref(u64 root_id, u64 bytenr, int level)
 	}
 
 	/* Read out the tree block to get item/node key */
-	eb = read_tree_block(gfs_info, bytenr, root_id, 0, 0, NULL);
+	eb = read_tree_block(gfs_info, bytenr, &check);
 	if (!extent_buffer_uptodate(eb)) {
 		err |= REFERENCER_MISSING;
 		free_extent_buffer(eb);
@@ -3877,11 +3882,12 @@ static int is_tree_reloc_root(struct extent_buffer *eb)
 static int check_shared_block_backref(u64 parent, u64 bytenr, int level)
 {
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 	u32 nr;
 	int found_parent = 0;
 	int i;
 
-	eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
+	eb = read_tree_block(gfs_info, parent, &check);
 	if (!extent_buffer_uptodate(eb))
 		goto out;
 
@@ -4048,11 +4054,12 @@ static int check_shared_data_backref(u64 parent, u64 bytenr)
 	struct extent_buffer *eb;
 	struct btrfs_key key;
 	struct btrfs_file_extent_item *fi;
+	struct btrfs_tree_parent_check check = { 0 };
 	u32 nr;
 	int found_parent = 0;
 	int i;
 
-	eb = read_tree_block(gfs_info, parent, 0, 0, 0, NULL);
+	eb = read_tree_block(gfs_info, parent, &check);
 	if (!extent_buffer_uptodate(eb))
 		goto out;
 
@@ -5018,11 +5025,15 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
 
 		next = btrfs_find_tree_block(gfs_info, bytenr, gfs_info->nodesize);
 		if (!next || !btrfs_buffer_uptodate(next, ptr_gen, 0)) {
+			struct btrfs_tree_parent_check check = {
+				.owner_root = btrfs_header_owner(cur),
+				.transid = ptr_gen,
+				.level = *level - 1,
+			};
+
 			free_extent_buffer(next);
 			reada_walk_down(root, cur, path->slots[*level]);
-			next = read_tree_block(gfs_info, bytenr,
-					       btrfs_header_owner(cur),
-					       ptr_gen, *level - 1, NULL);
+			next = read_tree_block(gfs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(next)) {
 				struct btrfs_key node_key;
 
diff --git a/check/qgroup-verify.c b/check/qgroup-verify.c
index 0c08eae8..0491d6a3 100644
--- a/check/qgroup-verify.c
+++ b/check/qgroup-verify.c
@@ -30,6 +30,7 @@
 #include "kernel-shared/ulist.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/transaction.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/messages.h"
 #include "common/rbtree-utils.h"
 #include "check/repair.h"
@@ -714,14 +715,16 @@ static int travel_tree(struct btrfs_fs_info *info, struct btrfs_root *root,
 {
 	int ret, nr, i;
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = {
+		.owner_root = btrfs_root_id(root),
+	};
 	u64 new_bytenr;
 	u64 new_num_bytes;
 
 //	printf("travel_tree: bytenr: %llu\tnum_bytes: %llu\tref_parent: %llu\n",
 //	       bytenr, num_bytes, ref_parent);
 
-	eb = read_tree_block(info, bytenr, btrfs_root_id(root), 0,
-			     0, NULL);
+	eb = read_tree_block(info, bytenr, &check);
 	if (!extent_buffer_uptodate(eb))
 		return -EIO;
 
diff --git a/check/repair.c b/check/repair.c
index d8900c41..240ac7fb 100644
--- a/check/repair.c
+++ b/check/repair.c
@@ -137,6 +137,8 @@ static int traverse_tree_blocks(struct extent_io_tree *tree,
 
 	nritems = btrfs_header_nritems(eb);
 	for (i = 0; i < nritems; i++) {
+		struct btrfs_tree_parent_check check = { 0 };
+
 		if (level == 0) {
 			bool is_extent_root;
 			btrfs_item_key_to_cpu(eb, &key, i);
@@ -150,15 +152,16 @@ static int traverse_tree_blocks(struct extent_io_tree *tree,
 			ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
 			bytenr = btrfs_disk_root_bytenr(eb, ri);
 
+			check.owner_root = key.objectid;
+			check.level = btrfs_disk_root_level(eb, ri);
+
 			/*
 			 * If at any point we start needing the real root we
 			 * will have to build a stump root for the root we are
 			 * in, but for now this doesn't actually use the root so
 			 * just pass in extent_root.
 			 */
-			tmp = read_tree_block(fs_info, bytenr, key.objectid, 0,
-					      btrfs_disk_root_level(eb, ri),
-					      NULL);
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				fprintf(stderr, "Error reading root block\n");
 				return -EIO;
@@ -183,9 +186,10 @@ static int traverse_tree_blocks(struct extent_io_tree *tree,
 				continue;
 			}
 
-			tmp = read_tree_block(fs_info, bytenr,
-					      btrfs_header_owner(eb), 0,
-					      level - 1, NULL);
+			check.owner_root = btrfs_header_owner(eb);
+			check.level = level - 1;
+
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				fprintf(stderr, "Error reading tree block\n");
 				return -EIO;
diff --git a/cmds/inspect-dump-tree.c b/cmds/inspect-dump-tree.c
index 9c3de7aa..c16d3aa2 100644
--- a/cmds/inspect-dump-tree.c
+++ b/cmds/inspect-dump-tree.c
@@ -32,6 +32,7 @@
 #include "kernel-shared/print-tree.h"
 #include "kernel-shared/volumes.h"
 #include "kernel-shared/extent_io.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/defs.h"
 #include "common/extent-cache.h"
 #include "common/messages.h"
@@ -58,10 +59,14 @@ static void print_extents(struct extent_buffer *eb)
 
 	nr = btrfs_header_nritems(eb);
 	for (i = 0; i < nr; i++) {
+		struct btrfs_tree_parent_check check = {
+			.owner_root = btrfs_header_owner(eb),
+			.transid = btrfs_node_ptr_generation(eb, i),
+			.level = btrfs_header_level(eb) - 1,
+		};
+
 		next = read_tree_block(fs_info, btrfs_node_blockptr(eb, i),
-				       btrfs_header_owner(eb),
-				       btrfs_node_ptr_generation(eb, i),
-				       btrfs_header_level(eb) - 1, NULL);
+				       &check);
 		if (!extent_buffer_uptodate(next))
 			continue;
 		if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
@@ -269,6 +274,7 @@ static int dump_print_tree_blocks(struct btrfs_fs_info *fs_info,
 {
 	struct cache_extent *ce;
 	struct extent_buffer *eb;
+	struct btrfs_tree_parent_check check = { 0 };
 	u64 bytenr;
 	int ret = 0;
 
@@ -289,7 +295,7 @@ static int dump_print_tree_blocks(struct btrfs_fs_info *fs_info,
 			goto next;
 		}
 
-		eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+		eb = read_tree_block(fs_info, bytenr, &check);
 		if (!extent_buffer_uptodate(eb)) {
 			error("failed to read tree block %llu", bytenr);
 			ret = -EIO;
@@ -592,12 +598,14 @@ again:
 		if (found_key.type == BTRFS_ROOT_ITEM_KEY) {
 			unsigned long offset;
 			struct extent_buffer *buf;
+			struct btrfs_tree_parent_check check = {
+				.owner_root = key.objectid,
+			};
 			bool skip = (extent_only || device_only || uuid_tree_only);
 
 			offset = btrfs_item_ptr_offset(leaf, slot);
 			read_extent_buffer(leaf, &ri, offset, sizeof(ri));
-			buf = read_tree_block(info, btrfs_root_bytenr(&ri),
-					      key.objectid, 0, 0, NULL);
+			buf = read_tree_block(info, btrfs_root_bytenr(&ri), &check);
 			if (!extent_buffer_uptodate(buf))
 				goto next;
 			if (tree_id && found_key.objectid != tree_id) {
diff --git a/cmds/inspect-tree-stats.c b/cmds/inspect-tree-stats.c
index e1808ec5..0d6db150 100644
--- a/cmds/inspect-tree-stats.c
+++ b/cmds/inspect-tree-stats.c
@@ -29,6 +29,7 @@
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/utils.h"
 #include "common/help.h"
 #include "common/messages.h"
@@ -152,10 +153,12 @@ static int walk_nodes(struct btrfs_root *root, struct btrfs_path *path,
 
 		path->slots[level] = i;
 		if ((level - 1) > 0 || find_inline) {
-			tmp = read_tree_block(root->fs_info, cur_blocknr,
-					      btrfs_header_owner(b),
-					      btrfs_node_ptr_generation(b, i),
-					      level - 1, NULL);
+			struct btrfs_tree_parent_check check = {
+				.owner_root = btrfs_header_owner(b),
+				.transid = btrfs_node_ptr_generation(b, i),
+				.level = level - 1,
+			};
+			tmp = read_tree_block(root->fs_info, cur_blocknr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				error("failed to read blocknr %llu",
 					btrfs_node_blockptr(b, i));
diff --git a/cmds/restore.c b/cmds/restore.c
index b0e04a7e..74462bca 100644
--- a/cmds/restore.c
+++ b/cmds/restore.c
@@ -45,6 +45,7 @@
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/compression.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/utils.h"
 #include "common/help.h"
 #include "common/open-utils.h"
@@ -1241,15 +1242,17 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
 	 * the fs_root.
 	 */
 	if (!extent_buffer_uptodate(fs_info->tree_root->node)) {
+		struct btrfs_tree_parent_check check = { 0 };
 		u64 generation;
 
 		root = fs_info->tree_root;
 		if (!root_location)
 			root_location = btrfs_super_root(fs_info->super_copy);
 		generation = btrfs_super_generation(fs_info->super_copy);
-		root->node = read_tree_block(fs_info, root_location,
-					     btrfs_root_id(root), generation,
-					     0, NULL);
+
+		check.owner_root = btrfs_root_id(root);
+		check.transid = generation;
+		root->node = read_tree_block(fs_info, root_location, &check);
 		if (!extent_buffer_uptodate(root->node)) {
 			error("opening tree root failed");
 			close_ctree(root);
@@ -1514,9 +1517,9 @@ static int cmd_restore(const struct cmd_struct *cmd, int argc, char **argv)
 		goto out;
 
 	if (fs_location != 0) {
+		struct btrfs_tree_parent_check check = { 0 };
 		free_extent_buffer(root->node);
-		root->node = read_tree_block(root->fs_info, fs_location, 0, 0,
-					     0, NULL);
+		root->node = read_tree_block(root->fs_info, fs_location, &check);
 		if (!extent_buffer_uptodate(root->node)) {
 			error("failed to read fs location");
 			ret = 1;
diff --git a/image/image-create.c b/image/image-create.c
index 894969ed..c802ba14 100644
--- a/image/image-create.c
+++ b/image/image-create.c
@@ -21,6 +21,7 @@
 #include "kernel-shared/file-item.h"
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/volumes.h"
+#include "kernel-shared/tree-checker.h"
 #include "crypto/crc32c.h"
 #include "common/internal.h"
 #include "common/messages.h"
@@ -437,11 +438,11 @@ static int flush_pending(struct metadump_struct *md, int done)
 		}
 
 		while (!md->data && size > 0) {
+			struct btrfs_tree_parent_check check = { 0 };
 			u64 this_read = min((u64)md->root->fs_info->nodesize,
 					size);
 
-			eb = read_tree_block(md->root->fs_info, start, 0, 0, 0,
-					     NULL);
+			eb = read_tree_block(md->root->fs_info, start, &check);
 			if (!extent_buffer_uptodate(eb)) {
 				free(async->buffer);
 				free(async);
@@ -510,6 +511,7 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
 	struct btrfs_root_item *ri;
 	struct btrfs_key key;
 	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct btrfs_tree_parent_check check = { 0 };
 	u64 bytenr;
 	int level;
 	int nritems = 0;
@@ -545,7 +547,7 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
 				continue;
 			ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
 			bytenr = btrfs_disk_root_bytenr(eb, ri);
-			tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				error("unable to read log root block");
 				return -EIO;
@@ -556,7 +558,7 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
 				return ret;
 		} else {
 			bytenr = btrfs_node_blockptr(eb, i);
-			tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				error("unable to read log root block");
 				return -EIO;
diff --git a/image/image-restore.c b/image/image-restore.c
index 36cdc554..5ac254cf 100644
--- a/image/image-restore.c
+++ b/image/image-restore.c
@@ -20,6 +20,7 @@
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/volumes.h"
 #include "kernel-shared/transaction.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/internal.h"
 #include "common/messages.h"
 #include "common/open-utils.h"
@@ -1366,6 +1367,7 @@ static int iter_tree_blocks(struct btrfs_fs_info *fs_info,
 			    struct extent_buffer *eb, bool pin)
 {
 	void (*func)(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
+	struct btrfs_tree_parent_check check = { 0 };
 	int nritems;
 	int level;
 	int i;
@@ -1396,7 +1398,7 @@ static int iter_tree_blocks(struct btrfs_fs_info *fs_info,
 				continue;
 			ri = btrfs_item_ptr(eb, i, struct btrfs_root_item);
 			bytenr = btrfs_disk_root_bytenr(eb, ri);
-			tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				error("unable to read log root block");
 				return -EIO;
@@ -1407,7 +1409,7 @@ static int iter_tree_blocks(struct btrfs_fs_info *fs_info,
 				return ret;
 		} else {
 			bytenr = btrfs_node_blockptr(eb, i);
-			tmp = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+			tmp = read_tree_block(fs_info, bytenr, &check);
 			if (!extent_buffer_uptodate(tmp)) {
 				error("unable to read log root block");
 				return -EIO;
diff --git a/image/main.c b/image/main.c
index fcec725d..52b46588 100644
--- a/image/main.c
+++ b/image/main.c
@@ -41,6 +41,7 @@
 #include "kernel-shared/volumes.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "crypto/crc32c.h"
 #include "crypto/hash.h"
 #include "common/internal.h"
diff --git a/kernel-shared/backref.c b/kernel-shared/backref.c
index c4e76823..14f045d7 100644
--- a/kernel-shared/backref.c
+++ b/kernel-shared/backref.c
@@ -23,6 +23,7 @@
 #include "kernel-shared/ulist.h"
 #include "kernel-shared/transaction.h"
 #include "kernel-shared/messages.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/internal.h"
 
 #define pr_debug(...) do { } while (0)
@@ -454,6 +455,7 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
 
 	while (!list_empty(&prefstate->pending_missing_keys)) {
 		struct __prelim_ref *ref;
+		struct btrfs_tree_parent_check check;
 
 		ref = list_first_pref(&prefstate->pending_missing_keys);
 
@@ -461,8 +463,13 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
 		ASSERT(!ref->parent);
 		ASSERT(!ref->key_for_search.type);
 		BUG_ON(!ref->wanted_disk_byte);
-		eb = read_tree_block(fs_info, ref->wanted_disk_byte,
-				     ref->root_id, 0, ref->level - 1, NULL);
+
+		check.owner_root = ref->root_id;
+		check.transid = 0;
+		check.has_first_key = false;
+		check.level = ref->level - 1;
+
+		eb = read_tree_block(fs_info, ref->wanted_disk_byte, &check);
 		if (!extent_buffer_uptodate(eb)) {
 			free_extent_buffer(eb);
 			return -EIO;
@@ -823,9 +830,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
 			if (extent_item_pos && !ref->inode_list &&
 			    ref->level == 0) {
 				struct extent_buffer *eb;
+				struct btrfs_tree_parent_check check = {
+					.level = ref->level,
+				};
 
-				eb = read_tree_block(fs_info, ref->parent, 0,
-						     0, ref->level, NULL);
+				eb = read_tree_block(fs_info, ref->parent, &check);
 				if (!extent_buffer_uptodate(eb)) {
 					free_extent_buffer(eb);
 					ret = -EIO;
diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index e95839bd..fb3b9899 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -715,6 +715,7 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
 {
 	struct btrfs_fs_info *fs_info = parent->fs_info;
 	struct extent_buffer *ret;
+	struct btrfs_tree_parent_check check = { 0 };
 	int level = btrfs_header_level(parent);
 
 	if (slot < 0)
@@ -725,10 +726,12 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
 	if (level == 0)
 		return NULL;
 
+	check.owner_root = btrfs_header_owner(parent);
+	check.transid = btrfs_node_ptr_generation(parent, slot);
+	check.level = level - 1;
+
 	ret = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
-			      btrfs_header_owner(parent),
-			      btrfs_node_ptr_generation(parent, slot),
-			      level - 1, NULL);
+			      &check);
 	if (!extent_buffer_uptodate(ret))
 		return ERR_PTR(-EIO);
 
diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c
index ef5ea391..b2fdc48d 100644
--- a/kernel-shared/disk-io.c
+++ b/kernel-shared/disk-io.c
@@ -417,23 +417,12 @@ int btrfs_read_extent_buffer(struct extent_buffer *eb,
 }
 
 struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
-				      u64 owner_root, u64 parent_transid,
-				      int level, struct btrfs_key *first_key)
+				      struct btrfs_tree_parent_check *check)
 {
-	struct btrfs_tree_parent_check check = {
-		.owner_root = owner_root,
-		.transid = parent_transid,
-		.level = level,
-	};
 	int ret;
 	struct extent_buffer *eb;
 	u32 sectorsize = fs_info->sectorsize;
 
-	if (first_key) {
-		check.has_first_key = true;
-		memcpy(&check.first_key, first_key, sizeof(*first_key));
-	}
-
 	/*
 	 * Don't even try to create tree block for unaligned tree block
 	 * bytenr.
@@ -450,10 +439,10 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
 	if (!eb)
 		return ERR_PTR(-ENOMEM);
 
-	if (btrfs_buffer_uptodate(eb, parent_transid, 0))
+	if (btrfs_buffer_uptodate(eb, check->transid, 0))
 		return eb;
 
-	ret = btrfs_read_extent_buffer(eb, &check);
+	ret = btrfs_read_extent_buffer(eb, check);
 	if (ret) {
 		/*
 		 * We failed to read this tree block, it be should deleted right
@@ -508,8 +497,13 @@ static int read_root_node(struct btrfs_fs_info *fs_info,
 			  struct btrfs_root *root, u64 bytenr, u64 gen,
 			  int level)
 {
-	root->node = read_tree_block(fs_info, bytenr, btrfs_root_id(root),
-				     gen, level, NULL);
+	struct btrfs_tree_parent_check check = {
+		.owner_root = btrfs_root_id(root),
+		.transid = gen,
+		.level = level,
+	};
+
+	root->node = read_tree_block(fs_info, bytenr, &check);
 	if (!extent_buffer_uptodate(root->node))
 		goto err;
 	if (btrfs_header_level(root->node) != level) {
diff --git a/kernel-shared/disk-io.h b/kernel-shared/disk-io.h
index 78c6e8c7..20dfb01c 100644
--- a/kernel-shared/disk-io.h
+++ b/kernel-shared/disk-io.h
@@ -147,8 +147,7 @@ struct btrfs_device;
 
 int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror);
 struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
-				      u64 owner_root, u64 parent_transid,
-				      int level, struct btrfs_key *first_key);
+				      struct btrfs_tree_parent_check *check);
 
 void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
 			  u64 parent_transid);
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 9796085d..a5ca51e3 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -28,6 +28,7 @@
 #include "kernel-shared/compression.h"
 #include "kernel-shared/accessors.h"
 #include "kernel-shared/file-item.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/utils.h"
 
 static void print_dir_item_type(struct extent_buffer *eb,
@@ -1613,10 +1614,13 @@ static void dfs_print_children(struct extent_buffer *root_eb, unsigned int mode)
 	mode &= ~(BTRFS_PRINT_TREE_BFS);
 
 	for (i = 0; i < nr; i++) {
+		struct btrfs_tree_parent_check check = {
+			.owner_root = btrfs_header_owner(root_eb),
+			.transid = btrfs_node_ptr_generation(root_eb, i),
+			.level = root_eb_level,
+		};
 		next = read_tree_block(fs_info, btrfs_node_blockptr(root_eb, i),
-				       btrfs_header_owner(root_eb),
-				       btrfs_node_ptr_generation(root_eb, i),
-				       root_eb_level, NULL);
+				       &check);
 		if (!extent_buffer_uptodate(next)) {
 			fprintf(stderr, "failed to read %llu in tree %llu\n",
 				btrfs_node_blockptr(root_eb, i),
diff --git a/tune/change-uuid.c b/tune/change-uuid.c
index 54184811..a9e5385e 100644
--- a/tune/change-uuid.c
+++ b/tune/change-uuid.c
@@ -24,6 +24,7 @@
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/extent_io.h"
 #include "kernel-shared/volumes.h"
+#include "kernel-shared/tree-checker.h"
 #include "common/defs.h"
 #include "common/messages.h"
 #include "tune/tune.h"
@@ -97,6 +98,7 @@ static int change_extent_tree_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsi
 	while (1) {
 		struct btrfs_extent_item *ei;
 		struct extent_buffer *eb;
+		struct btrfs_tree_parent_check check = { 0 };
 		u64 flags;
 		u64 bytenr;
 
@@ -111,7 +113,7 @@ static int change_extent_tree_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsi
 			goto next;
 
 		bytenr = key.objectid;
-		eb = read_tree_block(fs_info, bytenr, 0, 0, 0, NULL);
+		eb = read_tree_block(fs_info, bytenr, &check);
 		if (IS_ERR(eb)) {
 			error("failed to read tree block: %llu", bytenr);
 			ret = PTR_ERR(eb);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 36/38] btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (34 preceding siblings ...)
  2023-08-23 14:33 ` [PATCH 35/38] btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check Josef Bacik
@ 2023-08-23 14:33 ` Josef Bacik
  2023-08-23 14:33 ` [PATCH 37/38] btrfs-progs: update btrfs_split_item to match the in-kernel definition Josef Bacik
                   ` (3 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:33 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

This is the opposite of what we do in the kernel, however in the kernel
we put the helpers in dir-item.h and inode-item.h respectively.  Those
do not exist in btrfs-progs right now, so instead of doing all that work
right now simply inline them in ctree.h to make it easier to sync
ctree.c from the kernel.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 14 --------------
 kernel-shared/ctree.h | 16 ++++++++++++++--
 2 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index fb3b9899..0bfebdc2 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -24,7 +24,6 @@
 #include "kernel-shared/print-tree.h"
 #include "kernel-shared/tree-checker.h"
 #include "kernel-shared/volumes.h"
-#include "crypto/crc32c.h"
 #include "common/internal.h"
 #include "common/messages.h"
 #include "common/utils.h"
@@ -188,19 +187,6 @@ 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
- */
-u64 btrfs_extref_hash(u64 parent_objectid, const char *name, int len)
-{
-	return (u64)crc32c(parent_objectid, name, len);
-}
-
 struct btrfs_path *btrfs_alloc_path(void)
 {
 	might_sleep();
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 67c5a6f8..7ffef9fa 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -25,6 +25,7 @@
 #include "kernel-lib/rbtree.h"
 #include "kerncompat.h"
 #include "common/extent-cache.h"
+#include "crypto/crc32c.h"
 #include "kernel-shared/uapi/btrfs.h"
 #include "kernel-shared/uapi/btrfs_tree.h"
 #include "kernel-shared/extent_io.h"
@@ -869,8 +870,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,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 37/38] btrfs-progs: update btrfs_split_item to match the in-kernel definition
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (35 preceding siblings ...)
  2023-08-23 14:33 ` [PATCH 36/38] btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash Josef Bacik
@ 2023-08-23 14:33 ` Josef Bacik
  2023-08-23 14:33 ` [PATCH 38/38] btrfs-progs: sync ctree.c from kernel Josef Bacik
                   ` (2 subsequent siblings)
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:33 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

In the kernel new_key is const, update the definition in btrfs-progs to
match the in-kernel definition.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 2 +-
 kernel-shared/ctree.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 0bfebdc2..866a748f 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -2322,7 +2322,7 @@ 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;
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 7ffef9fa..fbdf3aef 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -980,7 +980,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,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 38/38] btrfs-progs: sync ctree.c from kernel
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (36 preceding siblings ...)
  2023-08-23 14:33 ` [PATCH 37/38] btrfs-progs: update btrfs_split_item to match the in-kernel definition Josef Bacik
@ 2023-08-23 14:33 ` Josef Bacik
  2023-08-23 17:41 ` [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
  2023-08-25 21:35 ` David Sterba
  39 siblings, 0 replies; 44+ messages in thread
From: Josef Bacik @ 2023-08-23 14:33 UTC (permalink / raw)
  To: linux-btrfs, kernel-team

This copies the current copy of ctree.c into btrfs-progs.  There are a
few modifications, they are all hi-lighted by a "MODIFIED" tag in the
code.

- The btrfs_path_cachep is a static struct to avoid needing to call
  btrfs_ctree_init to be able to use stuff.
- There is a single page optimization in the search that is not relevant
  in btrfs-progs.
- We have a few warnings around trans->transaction, but we don't have
  this distinction in btrfs-progs yet.
- Obvious include cleanups

The rest is a straight copy, the only "modifications" that I didn't note
were in ctree.h to clean up some of the inline helpers that use
different functions.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 kernel-shared/ctree.c | 4258 ++++++++++++++++++++++++++++++-----------
 kernel-shared/ctree.h |   50 +-
 2 files changed, 3219 insertions(+), 1089 deletions(-)

diff --git a/kernel-shared/ctree.c b/kernel-shared/ctree.c
index 866a748f..5333c071 100644
--- a/kernel-shared/ctree.c
+++ b/kernel-shared/ctree.c
@@ -1,33 +1,28 @@
+// 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-lib/bitops.h"
-#include "kernel-lib/sizes.h"
-#include "kernel-shared/ctree.h"
-#include "kernel-shared/disk-io.h"
-#include "kernel-shared/transaction.h"
-#include "kernel-shared/print-tree.h"
-#include "kernel-shared/tree-checker.h"
-#include "kernel-shared/volumes.h"
-#include "common/internal.h"
-#include "common/messages.h"
-#include "common/utils.h"
-#include "check/repair.h"
+#include "kernel-lib/trace.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"
+
+/* MODIFIED: use this instead of calling btrfs_ctree_init. */
+static struct kmem_cache btrfs_path_cache_struct = {
+	.size = sizeof(struct btrfs_path),
+};
+
+static struct kmem_cache *btrfs_path_cachep = &btrfs_path_cache_struct;
 
 static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_path *path, int level);
@@ -151,12 +146,19 @@ static inline void copy_leaf_items(const struct extent_buffer *dst,
 			      nr_items * sizeof(struct btrfs_item));
 }
 
-int btrfs_super_csum_size(const struct btrfs_super_block *sb)
+/* This exists for btrfs-progs usages. */
+u16 btrfs_csum_type_size(u16 type)
 {
-	const u16 csum_type = btrfs_super_csum_type(sb);
+	return btrfs_csums[type].size;
+}
 
-	/* csum type is validated at mount time */
-	return btrfs_csums[csum_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)
@@ -182,16 +184,11 @@ size_t __attribute_const__ btrfs_get_num_csums(void)
 	return ARRAY_SIZE(btrfs_csums);
 }
 
-u16 btrfs_csum_type_size(u16 csum_type)
-{
-	return btrfs_csums[csum_type].size;
-}
-
 struct btrfs_path *btrfs_alloc_path(void)
 {
 	might_sleep();
 
-	return kzalloc(sizeof(struct btrfs_path), GFP_NOFS);
+	return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
 }
 
 /* this also releases the path */
@@ -200,7 +197,7 @@ void btrfs_free_path(struct btrfs_path *p)
 	if (!p)
 		return;
 	btrfs_release_path(p);
-	kfree(p);
+	kmem_cache_free(btrfs_path_cachep, p);
 }
 
 /*
@@ -224,7 +221,6 @@ noinline void btrfs_release_path(struct btrfs_path *p)
 		free_extent_buffer(p->nodes[i]);
 		p->nodes[i] = NULL;
 	}
-	memset(p, 0, sizeof(*p));
 }
 
 /*
@@ -243,47 +239,84 @@ bool __cold abort_should_print_stack(int errno)
 	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);
 
@@ -293,13 +326,11 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 	else
 		btrfs_node_key(buf, &disk_key, 0);
 
-	cow = btrfs_alloc_tree_block(trans, new_root, 0, new_root_objectid,
+	cow = btrfs_alloc_tree_block(trans, root, 0, new_root_objectid,
 				     &disk_key, level, buf->start, 0,
-				     BTRFS_NESTING_NORMAL);
-	if (IS_ERR(cow)) {
-		kfree(new_root);
+				     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);
@@ -312,14 +343,19 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 	else
 		btrfs_set_header_owner(cow, new_root_objectid);
 
-	write_extent_buffer_fsid(cow, root->fs_info->fs_devices->metadata_uuid);
+	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;
@@ -329,8 +365,8 @@ 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 shareable trees and tree roots are never shared.
@@ -350,8 +386,10 @@ static int btrfs_block_can_be_shared(struct btrfs_root *root,
 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;
@@ -376,12 +414,20 @@ 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 (unlikely(refs == 0)) {
+			btrfs_crit(fs_info,
+		"found 0 references for tree block at bytenr %llu level %d root %llu",
+				   buf->start, btrfs_header_level(buf),
+				   btrfs_root_id(root));
+			ret = -EUCLEAN;
+			btrfs_abort_transaction(trans, ret);
+			return ret;
+		}
 	} else {
 		refs = 1;
 		if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
@@ -392,22 +438,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 {
@@ -417,11 +466,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) {
@@ -430,11 +481,14 @@ 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;
 }
@@ -456,14 +510,24 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 			     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);
 
@@ -474,12 +538,17 @@ static noinline 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);
 
+	/* 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);
@@ -491,38 +560,76 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 	else
 		btrfs_set_header_owner(cow, root->root_key.objectid);
 
-	write_extent_buffer_fsid(cow, root->fs_info->fs_devices->metadata_uuid);
+	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);
+		ret = btrfs_tree_mod_log_insert_root(root->node, cow, true);
+		if (ret < 0) {
+			btrfs_tree_unlock(cow);
+			free_extent_buffer(cow);
+			btrfs_abort_transaction(trans, ret);
+			return ret;
+		}
+		atomic_inc(&cow->refs);
+		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));
+		ret = btrfs_tree_mod_log_insert_key(parent, parent_slot,
+						    BTRFS_MOD_LOG_KEY_REPLACE);
+		if (ret) {
+			btrfs_tree_unlock(cow);
+			free_extent_buffer(cow);
+			btrfs_abort_transaction(trans, ret);
+			return ret;
+		}
 		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;
@@ -532,51 +639,91 @@ 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,
 		    enum btrfs_lock_nesting nest)
 {
+	struct btrfs_fs_info *fs_info = root->fs_info;
 	u64 search_start;
 	int ret;
-	/*
-	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);
-	}
-	*/
-	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 (test_bit(BTRFS_ROOT_DELETING, &root->state))
+		btrfs_err(fs_info,
+			"COW'ing blocks on a fs root that's being dropped");
+
+	/* MODIFIED: We don't have trans->transaction. */
+#if 0
+	if (trans->transaction != fs_info->running_transaction)
+		WARN(1, KERN_CRIT "trans %llu running %llu\n",
+		       trans->transid,
+		       fs_info->running_transaction->transid);
+#endif
+
+	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);
 
 /*
  * helper function for defrag to decide if two blocks pointed to by a
  * node are actually close by
  */
-static __attribute__((unused)) int close_blocks(u64 blocknr, u64 other, u32 blocksize)
+static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
 {
 	if (blocknr < other && other - (blocknr + blocksize) < 32768)
 		return 1;
@@ -585,6 +732,35 @@ static __attribute__((unused)) int close_blocks(u64 blocknr, u64 other, u32 bloc
 	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
@@ -607,60 +783,151 @@ int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_ke
 }
 
 /*
- * 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 trans->transaction.
+	WARN_ON(trans->transaction != fs_info->running_transaction);
+	*/
+	WARN_ON(trans->transid != fs_info->generation);
 
-static int noinline check_block(struct btrfs_fs_info *fs_info,
-				struct btrfs_path *path, int level)
-{
-	enum btrfs_tree_block_status ret;
+	parent_nritems = btrfs_header_nritems(parent);
+	blocksize = fs_info->nodesize;
+	end_slot = parent_nritems - 1;
 
-	if (path->skip_check_block)
+	if (parent_nritems <= 1)
 		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;
+
+	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;
 }
 
 /*
- * 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.
+ *
+ * MODIFIED: Removed the in page optimization.
  */
-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);
+	}
+
+	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;
@@ -675,61 +942,53 @@ 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).
+ */
 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;
-	struct btrfs_tree_parent_check check = { 0 };
 	int level = btrfs_header_level(parent);
+	struct btrfs_tree_parent_check check = { 0 };
+	struct extent_buffer *eb;
 
-	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);
 
-	check.owner_root = btrfs_header_owner(parent);
-	check.transid = btrfs_node_ptr_generation(parent, slot);
 	check.level = level - 1;
+	check.transid = btrfs_node_ptr_generation(parent, slot);
+	check.owner_root = btrfs_header_owner(parent);
+	check.has_first_key = true;
+	btrfs_node_key_to_cpu(parent, &check.first_key, slot);
 
-	ret = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
-			      &check);
-	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),
+			     &check);
+	if (IS_ERR(eb))
+		return eb;
+	if (!extent_buffer_uptodate(eb)) {
+		free_extent_buffer(eb);
 		return ERR_PTR(-EIO);
 	}
-	return ret;
+
+	return eb;
 }
 
 /*
@@ -752,10 +1011,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 	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);
@@ -777,48 +1037,82 @@ static noinline 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,
-				      BTRFS_NESTING_NORMAL);
-		BUG_ON(ret);
+		if (IS_ERR(child)) {
+			ret = PTR_ERR(child);
+			goto out;
+		}
+
+		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 out;
+		}
+
+		ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
+		if (ret < 0) {
+			btrfs_tree_unlock(child);
+			free_extent_buffer(child);
+			btrfs_abort_transaction(trans, ret);
+			goto out;
+		}
+		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 out;
+		}
+
+		__btrfs_tree_lock(left, BTRFS_NESTING_LEFT);
 		wret = btrfs_cow_block(trans, root, left,
 				       parent, pslot - 1, &left,
-				       BTRFS_NESTING_NORMAL);
+				       BTRFS_NESTING_LEFT_COW);
 		if (wret) {
 			ret = wret;
-			goto enospc;
+			goto out;
 		}
 	}
-	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 out;
+		}
+
+		__btrfs_tree_lock(right, BTRFS_NESTING_RIGHT);
 		wret = btrfs_cow_block(trans, root, right,
 				       parent, pslot + 1, &right,
-				       BTRFS_NESTING_NORMAL);
+				       BTRFS_NESTING_RIGHT_COW);
 		if (wret) {
 			ret = wret;
-			goto enospc;
+			goto out;
 		}
 	}
 
@@ -838,23 +1132,28 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 		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);
+			btrfs_tree_unlock(right);
+			ret = btrfs_del_ptr(trans, root, path, level + 1, pslot + 1);
+			if (ret < 0) {
+				free_extent_buffer_stale(right);
+				right = NULL;
+				goto out;
+			}
+			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;
-			btrfs_del_ptr(trans, 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;
 		} 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);
+			if (ret < 0) {
+				btrfs_abort_transaction(trans, ret);
+				goto out;
+			}
 			btrfs_set_node_key(parent, &right_key, pslot + 1);
 			btrfs_mark_buffer_dirty(parent);
 		}
@@ -869,11 +1168,19 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 		 * otherwise we would have pulled some pointers from the
 		 * right
 		 */
-		BUG_ON(!left);
+		if (unlikely(!left)) {
+			btrfs_crit(fs_info,
+"missing left child when middle child only has 1 item, parent bytenr %llu level %d mid bytenr %llu root %llu",
+				   parent->start, btrfs_header_level(parent),
+				   mid->start, btrfs_root_id(root));
+			ret = -EUCLEAN;
+			btrfs_abort_transaction(trans, ret);
+			goto out;
+		}
 		wret = balance_node_right(trans, mid, left);
 		if (wret < 0) {
 			ret = wret;
-			goto enospc;
+			goto out;
 		}
 		if (wret == 1) {
 			wret = push_node_left(trans, left, mid, 1);
@@ -883,23 +1190,28 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 		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);
+		btrfs_tree_unlock(mid);
+		ret = btrfs_del_ptr(trans, root, path, level + 1, pslot);
+		if (ret < 0) {
+			free_extent_buffer_stale(mid);
+			mid = NULL;
+			goto out;
+		}
+		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;
-		btrfs_del_ptr(trans, 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;
 	} 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);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, ret);
+			goto out;
+		}
 		btrfs_set_node_key(parent, &mid_key, pslot);
 		btrfs_mark_buffer_dirty(parent);
 	}
@@ -907,27 +1219,34 @@ static noinline 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)
+out:
+	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;
 }
 
@@ -963,18 +1282,23 @@ static noinline int 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,
-					      BTRFS_NESTING_NORMAL);
+					      BTRFS_NESTING_LEFT_COW);
 			if (ret)
 				wret = 1;
 			else {
@@ -987,37 +1311,54 @@ static noinline int 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);
+			if (ret < 0) {
+				btrfs_tree_unlock(left);
+				free_extent_buffer(left);
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
 			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, BTRFS_NESTING_NORMAL);
+					      &right, BTRFS_NESTING_RIGHT_COW);
 			if (ret)
 				wret = 1;
 			else {
@@ -1030,6 +1371,14 @@ static noinline int 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);
+			if (ret < 0) {
+				btrfs_tree_unlock(right);
+				free_extent_buffer(right);
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
 			btrfs_set_node_key(parent, &disk_key, pslot + 1);
 			btrfs_mark_buffer_dirty(parent);
 
@@ -1038,12 +1387,15 @@ static noinline int 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;
@@ -1061,222 +1413,1101 @@ static void reada_for_search(struct btrfs_fs_info *fs_info,
 	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.
+ */
+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_tree_parent_check check = { 0 };
+	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, &check.first_key, slot);
+	check.has_first_key = true;
+	check.level = parent_level - 1;
+	check.transid = gen;
+	check.owner_root = root->root_key.objectid;
+
+	/*
+	 * 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, &check.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, &check);
+		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, &check);
+	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, BTRFS_NESTING_NORMAL);
-			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);
 		}
 	}
+
+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;
+}
+
+/*
+ * Search the tree again to find a leaf with smaller keys.
+ * Returns 0 if it found something.
+ * Returns 1 if there are no smaller keys.
+ * Returns < 0 on error.
+ *
+ * This may release the path, and so you may lose any locks held at the
+ * time you call it.
+ *
+ * This is exported for use inside btrfs-progs, don't un-export it.
+ */
+int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
+{
+	struct btrfs_key key;
+	struct btrfs_key orig_key;
+	struct btrfs_disk_key found_key;
+	int ret;
+
+	btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
+	orig_key = key;
+
+	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;
+	}
+
+	btrfs_release_path(path);
+	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+	if (ret <= 0)
+		return ret;
+
+	/*
+	 * Previous key not found. Even if we were at slot 0 of the leaf we had
+	 * before releasing the path and calling btrfs_search_slot(), we now may
+	 * be in a slot pointing to the same original key - this can happen if
+	 * after we released the path, one of more items were moved from a
+	 * sibling leaf into the front of the leaf we had due to an insertion
+	 * (see push_leaf_right()).
+	 * If we hit this case and our slot is > 0 and just decrement the slot
+	 * so that the caller does not process the same key again, which may or
+	 * may not break the caller, depending on its logic.
+	 */
+	if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
+		btrfs_item_key(path->nodes[0], &found_key, path->slots[0]);
+		ret = comp_keys(&found_key, &orig_key);
+		if (ret == 0) {
+			if (path->slots[0] > 0) {
+				path->slots[0]--;
+				return 0;
+			}
+			/*
+			 * At slot 0, same key as before, it means orig_key is
+			 * the lowest, leftmost, key in the tree. We're done.
+			 */
+			return 1;
+		}
+	}
+
+	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;
 }
 
 /*
- * 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.
@@ -1288,65 +2519,115 @@ 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)
+{
+	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+		int ret;
+
+		ret = btrfs_next_leaf(root, path);
+		if (ret)
+			return ret;
+	}
+
+	btrfs_item_key_to_cpu(path->nodes[0], key, path->slots[0]);
+	return 0;
 }
 
 /*
@@ -1355,18 +2636,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)
@@ -1392,11 +2679,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_print_leaf(eb);
+			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);
+			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_print_leaf(eb);
+			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);
+			BUG();
+		}
 	}
 
 	btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -1406,6 +2713,62 @@ 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 (unlikely(btrfs_comp_cpu_keys(&left_last, &right_first) >= 0)) {
+		btrfs_crit(left->fs_info, "left extent buffer:");
+		btrfs_print_tree(left, false);
+		btrfs_crit(left->fs_info, "right extent buffer:");
+		btrfs_print_tree(right, false);
+		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.
@@ -1432,9 +2795,8 @@ static int push_node_left(struct btrfs_trans_handle *trans,
 	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);
@@ -1451,12 +2813,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) {
+		/*
+		 * btrfs_tree_mod_log_eb_copy handles logging the move, so we
+		 * don't need to do an explicit tree mod log operation for it.
+		 */
 		memmove_extent_buffer(src, btrfs_node_key_ptr_offset(src, 0),
 				      btrfs_node_key_ptr_offset(src, push_items),
 				      (src_nritems - push_items) *
@@ -1496,32 +2873,46 @@ 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(fs_info) - dst_nritems;
-	if (push_items <= 0) {
+	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;
+	}
+
+	/*
+	 * btrfs_tree_mod_log_eb_copy handles logging the move, so we don't
+	 * need to do an explicit tree mod log operation for it.
+	 */
 	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);
@@ -1539,15 +2930,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);
@@ -1560,23 +2953,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_fsid(c, root->fs_info->fs_devices->metadata_uuid);
-	write_extent_buffer_chunk_tree_uuid(c, root->fs_info->chunk_tree_uuid);
 	btrfs_set_node_key(c, &lower_key, 0);
 	btrfs_set_node_blockptr(c, 0, lower->start);
 	lower_gen = btrfs_header_generation(lower);
@@ -1587,14 +2970,22 @@ 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);
+	if (ret < 0) {
+		btrfs_free_tree_block(trans, btrfs_root_id(root), c, 0, 1);
+		btrfs_tree_unlock(c);
+		free_extent_buffer(c);
+		return ret;
+	}
+	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;
 }
@@ -1605,36 +2996,51 @@ 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 int 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);
+			if (ret < 0) {
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
+		}
 		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);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, ret);
+			return ret;
+		}
+	}
 	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;
 }
 
@@ -1647,21 +3053,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;
@@ -1669,7 +3085,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;
@@ -1681,47 +3097,49 @@ 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_fsid(split, root->fs_info->fs_devices->metadata_uuid);
-	write_extent_buffer_chunk_tree_uuid(split, root->fs_info->chunk_tree_uuid);
-
-	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_tree_unlock(split);
+		free_extent_buffer(split);
+		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;
+	ret = insert_ptr(trans, path, &disk_key, split->start,
+			 path->slots[level + 1] + 1, level + 1);
+	if (ret < 0) {
+		btrfs_tree_unlock(split);
+		free_extent_buffer(split);
+		return ret;
+	}
 
 	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;
 }
 
 /*
@@ -1737,7 +3155,7 @@ static int leaf_space_used(const 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);
@@ -1751,101 +3169,76 @@ static int leaf_space_used(const struct extent_buffer *l, int start, int nr)
  */
 int btrfs_leaf_free_space(const 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, BTRFS_NESTING_NORMAL);
-	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)
@@ -1853,13 +3246,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);
@@ -1869,32 +3259,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;
@@ -1902,6 +3286,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);
@@ -1911,36 +3298,260 @@ 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_abort_transaction(trans, ret);
+		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)
@@ -1949,199 +3560,171 @@ 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,
-			      BTRFS_NESTING_NORMAL);
+			      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;
+		btrfs_abort_transaction(trans, ret);
+		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)
+				   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;
+	int ret;
 	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;
+	ret = insert_ptr(trans, path, &disk_key, right->start, path->slots[1] + 1, 1);
+	if (ret < 0)
+		return ret;
 
 	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;
+	return 0;
+}
+
+/*
+ * 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;
 }
 
 /*
@@ -2162,24 +3745,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;
 		}
@@ -2205,22 +3800,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) {
@@ -2229,9 +3825,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;
 				}
 			}
 		}
@@ -2242,58 +3839,68 @@ 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_fsid(right, root->fs_info->fs_devices->metadata_uuid);
-	write_extent_buffer_chunk_tree_uuid(right, root->fs_info->chunk_tree_uuid);
-
-	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;
-
+			ret = insert_ptr(trans, path, &disk_key,
+					 right->start, path->slots[1] + 1, 1);
+			if (ret < 0) {
+				btrfs_tree_unlock(right);
+				free_extent_buffer(right);
+				return ret;
+			}
+			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;
+			ret = insert_ptr(trans, path, &disk_key,
+					 right->start, path->slots[1], 1);
+			if (ret < 0) {
+				btrfs_tree_unlock(right);
+				free_extent_buffer(right);
+				return ret;
+			}
+			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);
+	ret = copy_for_split(trans, path, l, right, slot, mid, nritems);
+	if (ret < 0) {
+		btrfs_tree_unlock(right);
+		free_extent_buffer(right);
+		return ret;
+	}
 
 	if (split == 2) {
 		BUG_ON(num_doubles != 0);
@@ -2301,9 +3908,148 @@ 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];
+	/*
+	 * Shouldn't happen because the caller must have previously called
+	 * setup_leaf_for_split() to make room for the new item in the leaf.
+	 */
+	if (WARN_ON(btrfs_leaf_free_space(leaf) < sizeof(struct btrfs_item)))
+		return -ENOSPC;
+
+	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
@@ -2325,96 +4071,22 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
 		     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;
@@ -2425,6 +4097,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];
@@ -2447,17 +4120,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;
@@ -2477,15 +4151,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);
@@ -2503,6 +4175,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;
@@ -2512,6 +4187,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];
 
@@ -2528,24 +4204,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);
@@ -2559,59 +4237,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,
-			    const struct btrfs_item_batch *batch)
+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;
 	unsigned int data_end;
 	struct btrfs_disk_key disk_key;
+	struct extent_buffer *leaf;
+	int slot;
+	struct btrfs_map_token token;
+	u32 total_size;
 
-	/* create a root if there isn't one */
-	if (!root->node)
-		BUG();
-
-	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;
+	/*
+	 * 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);
 	}
-	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
@@ -2620,22 +4302,16 @@ 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 - batch->total_data_size);
+			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 + batch->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 - batch->total_data_size,
-			      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;
 	}
 
@@ -2644,34 +4320,76 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
 		btrfs_cpu_key_to_disk(&disk_key, &batch->keys[i]);
 		btrfs_set_item_key(leaf, &disk_key, slot + i);
 		data_end -= batch->data_sizes[i];
-		btrfs_set_item_offset(leaf, slot + i, data_end);
-		btrfs_set_item_size(leaf, slot + i, 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 + batch->nr);
 	btrfs_mark_buffer_dirty(leaf);
 
-	ret = 0;
-	if (slot == 0) {
-		btrfs_cpu_key_to_disk(&disk_key, &batch->keys[0]);
-		fixup_low_keys(path, &disk_key, 1);
-	}
-
 	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, const 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;
@@ -2681,7 +4399,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans,
 	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];
@@ -2693,28 +4410,79 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans,
 	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.
  */
 int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		  struct btrfs_path *path, 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);
+			if (ret < 0) {
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
+		}
 		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);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, ret);
+			return ret;
+		}
 	}
+
 	nritems--;
 	btrfs_set_header_nritems(parent, nritems);
 	if (nritems == 0 && parent == root->node) {
@@ -2728,7 +4496,6 @@ int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		fixup_low_keys(path, &disk_key, level + 1);
 	}
 	btrfs_mark_buffer_dirty(parent);
-
 	return 0;
 }
 
@@ -2750,15 +4517,23 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
 	int ret;
 
 	WARN_ON(btrfs_header_generation(leaf) != trans->transid);
-	btrfs_del_ptr(trans, root, path, 1, path->slots[1]);
+	ret = btrfs_del_ptr(trans, root, path, 1, path->slots[1]);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * 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);
+	return 0;
 }
-
 /*
  * delete the item at the leaf level in path.  If that empties
  * the leaf, remove it from the tree
@@ -2766,41 +4541,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;
@@ -2811,10 +4582,9 @@ 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;
+			ret = btrfs_del_leaf(trans, root, path, leaf);
+			if (ret < 0)
+				return ret;
 		}
 	} else {
 		int used = leaf_space_used(leaf, 0, nritems);
@@ -2825,35 +4595,69 @@ 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);
+				if (ret < 0)
+					return ret;
 				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 {
@@ -2864,124 +4668,419 @@ 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.
- * returns 0 if it found something or 1 if there are no lesser leaves.
- * returns < 0 on io errors.
+ * 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
+ *
+ * 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_prev_leaf(struct btrfs_root *root, 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 level = 1;
-	struct extent_buffer *c;
-	struct extent_buffer *next = NULL;
+	int sret;
+	u32 nritems;
+	int level;
+	int ret = 1;
+	int keep_locks = path->keep_locks;
 
-	while(level < BTRFS_MAX_LEVEL) {
-		if (!path->nodes[level])
-			return 1;
+	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;
 
-		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 (btrfs_header_generation(cur) < min_trans) {
+		ret = 1;
+		goto out;
 	}
-	path->slots[level] = slot;
-	while(1) {
-		level--;
-		c = path->nodes[level];
-		free_extent_buffer(c);
-		slot = btrfs_header_nritems(next);
-		if (slot != 0)
+	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--;
-		path->nodes[level] = next;
-		path->slots[level] = slot;
-		if (!level)
+		/*
+		 * 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;
-		next = btrfs_read_node_slot(next, slot);
-		if (!extent_buffer_uptodate(next)) {
-			if (IS_ERR(next))
-				return PTR_ERR(next);
-			return -EIO;
 		}
+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);
 	}
-	return 0;
+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;
 }
 
 /*
- * 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.
+ * 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.
  *
- * returns 0 if it found something or 1 if there are no greater leaves.
- * returns < 0 on io errors.
+ * 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_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
-				  struct btrfs_path *path)
+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)
@@ -2991,7 +5090,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)
@@ -3020,7 +5119,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
  */
@@ -3059,3 +5158,18 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
 	}
 	return 1;
 }
+
+int __init btrfs_ctree_init(void)
+{
+	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 fbdf3aef..a0a85d92 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -1057,8 +1057,9 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 	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.
@@ -1069,33 +1070,48 @@ 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_block_can_be_shared(struct btrfs_root *root,
+			      struct extent_buffer *buf);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(const 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);
+struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
+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);
+int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key,
+			  struct btrfs_path *p, u64 time_seq);
+int btrfs_search_backwards(struct btrfs_root *root, struct btrfs_key *key,
+			   struct btrfs_path *path);
+int btrfs_get_next_valid_item(struct btrfs_root *root, struct btrfs_key *key,
+			      struct btrfs_path *path);
+void btrfs_setup_item_for_insert(struct btrfs_root *root,
+				 struct btrfs_path *path,
+				 const struct btrfs_key *key,
+				 u32 data_size);
+int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
+			 struct btrfs_root *root,
+			 struct btrfs_path *path,
+			 const struct btrfs_key *new_key);
+int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
+			 struct btrfs_path *path,
+			 u64 min_trans);
+int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
+			struct btrfs_key *key, int level, u64 min_trans);
+int __init btrfs_ctree_init(void);
+void __cold btrfs_ctree_exit(void);
 
 int btrfs_super_csum_size(const struct btrfs_super_block *sb);
 const char *btrfs_super_csum_name(u16 csum_type);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 13/38] btrfs-progs: drop btrfs_init_path
  2023-08-23 14:32 ` [PATCH 13/38] btrfs-progs: drop btrfs_init_path Josef Bacik
@ 2023-08-23 17:25   ` David Sterba
  0 siblings, 0 replies; 44+ messages in thread
From: David Sterba @ 2023-08-23 17:25 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-btrfs, kernel-team

On Wed, Aug 23, 2023 at 10:32:39AM -0400, Josef Bacik wrote:
> 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.

This also relies that btrfs_release_path() zeroes the path so repeated
uses of the same path don't need to be reinitialized before search.


> --- a/check/clear-cache.c
> +++ b/check/clear-cache.c
> @@ -130,11 +130,9 @@ static int check_free_space_tree(struct btrfs_root *root)
>  {
>  	struct btrfs_fs_info *fs_info = root->fs_info;
>  	struct btrfs_key key = { 0 };
                               ^^^^^
Like here

> -	struct btrfs_path path;
> +	struct btrfs_path path = {};

You should have used { 0 } to initialize the path. I can script the
change in the whole patch, no need to resend.

>  	int ret = 0;
>  
> -	btrfs_init_path(&path);
> -
>  	while (1) {
>  		struct btrfs_block_group *bg;
>  		u64 cur_start = key.objectid;

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (37 preceding siblings ...)
  2023-08-23 14:33 ` [PATCH 38/38] btrfs-progs: sync ctree.c from kernel Josef Bacik
@ 2023-08-23 17:41 ` David Sterba
  2023-08-25 21:35 ` David Sterba
  39 siblings, 0 replies; 44+ messages in thread
From: David Sterba @ 2023-08-23 17:41 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-btrfs, kernel-team

On Wed, Aug 23, 2023 at 10:32:26AM -0400, Josef Bacik wrote:
> Hello,
> 
> I started back up my extent tree v2 work and noticed not all my ctree.c sync
> patches made it in the last submission as I missed some comments.
> 
> This patchset is much larger than what was left, as I broke up the changes more
> discreetly.  In my original submission I had ignored some of the tree wide
> changes in favor of expediency, and had modified ctree.c more to match what we
> had in btrfs-progs.
> 
> This time I've updated everything that was different in ctree.c in the rest of
> btrfs-progs to make the actual sync'ing of ctree.c more straightforward.  I had
> to modify a few things in ctree.c, but they are very small and specific, no more
> updates of any of the global functions we depend on.
> 
> The downside is this patchset is massive.  The upside is the patches are small
> and self contained, with the obvious exception of the actual ctree.c sync.
> 
> This also will make subsequent sync'ing of other source files much easier, as
> I've changed a good deal of the very common helpers to match what exists in the
> kernel.
> 
> This passes all the tests.  There are a few behavior changes, but for the most
> part it's just updating helpers to match kernel definitions and moving code
> around.  Thanks,
> 
> Josef
> 
> Josef Bacik (38):
>   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: 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: init new tree blocks in btrfs_alloc_tree_block
>   btrfs-progs: add dwarves to the package list for ci
>   btrfs-progs: add kerncompat helpers for ctree.c sync
>   btrfs-progs: add trans_lock to fs_info
>   btrfs-progs: add commit_root_sem to btrfs_fs_info
>   btrfs-progs: update btrfs_cow_block to match the in-kernel definition
>   btrfs-progs: update btrfs_insert_empty_items to match the kernel
>   btrfs-progs: update btrfs_insert_empty_item to match the kernel
>   btrfs-progs: update btrfs_del_ptr to match the kernel
>   btrfs-progs: update btrfs_insert_item to match the kernel
>   btrfs-progs: update btrfs_leaf_free_space to match the kernel
>   btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer
>   btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check
>   btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash
>   btrfs-progs: update btrfs_split_item to match the in-kernel definition
>   btrfs-progs: sync ctree.c from kernel

I've skimmed the series, there maybe some minor things to fix up so I'll
apply it soon. The last patch is however too big, I get that you did not
want to split it further but I think it's still better to do it in
smaller batches grouped by functionality or a helper. Also there's the
copyright notice change, this hasn't been decided what to do with that
in userspace. I'll take another look.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs
  2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
                   ` (38 preceding siblings ...)
  2023-08-23 17:41 ` [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
@ 2023-08-25 21:35 ` David Sterba
  39 siblings, 0 replies; 44+ messages in thread
From: David Sterba @ 2023-08-25 21:35 UTC (permalink / raw)
  To: Josef Bacik; +Cc: linux-btrfs, kernel-team

On Wed, Aug 23, 2023 at 10:32:26AM -0400, Josef Bacik wrote:
> Hello,
> 
> I started back up my extent tree v2 work and noticed not all my ctree.c sync
> patches made it in the last submission as I missed some comments.
> 
> This patchset is much larger than what was left, as I broke up the changes more
> discreetly.  In my original submission I had ignored some of the tree wide
> changes in favor of expediency, and had modified ctree.c more to match what we
> had in btrfs-progs.
> 
> This time I've updated everything that was different in ctree.c in the rest of
> btrfs-progs to make the actual sync'ing of ctree.c more straightforward.  I had
> to modify a few things in ctree.c, but they are very small and specific, no more
> updates of any of the global functions we depend on.
> 
> The downside is this patchset is massive.  The upside is the patches are small
> and self contained, with the obvious exception of the actual ctree.c sync.
> 
> This also will make subsequent sync'ing of other source files much easier, as
> I've changed a good deal of the very common helpers to match what exists in the
> kernel.
> 
> This passes all the tests.  There are a few behavior changes, but for the most
> part it's just updating helpers to match kernel definitions and moving code
> around.  Thanks,
> 
> Josef
> 
> Josef Bacik (38):
>   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: 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: init new tree blocks in btrfs_alloc_tree_block
>   btrfs-progs: add dwarves to the package list for ci
>   btrfs-progs: add kerncompat helpers for ctree.c sync
>   btrfs-progs: add trans_lock to fs_info
>   btrfs-progs: add commit_root_sem to btrfs_fs_info
>   btrfs-progs: update btrfs_cow_block to match the in-kernel definition
>   btrfs-progs: update btrfs_insert_empty_items to match the kernel
>   btrfs-progs: update btrfs_insert_empty_item to match the kernel
>   btrfs-progs: update btrfs_del_ptr to match the kernel
>   btrfs-progs: update btrfs_insert_item to match the kernel
>   btrfs-progs: update btrfs_leaf_free_space to match the kernel
>   btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer
>   btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check
>   btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash
>   btrfs-progs: update btrfs_split_item to match the in-kernel definition

1-37 applied, with some minor fixups, thanks. This change granularity is
good.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs
  2023-08-23 14:32 ` [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
@ 2023-08-29  6:32   ` Qu Wenruo
  2023-08-29  6:42     ` Qu Wenruo
  0 siblings, 1 reply; 44+ messages in thread
From: Qu Wenruo @ 2023-08-29  6:32 UTC (permalink / raw)
  To: Josef Bacik, linux-btrfs, kernel-team



On 2023/8/23 22:32, Josef Bacik wrote:
> 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>

Unfortunately this patch is causing extent buffer leakage. (Thanks Anand
for finding it)

The latest devel branch would cause two eb leaks, one for uuid tree
(caused by this one), another eb would be from free space tree.

We can remove this one, but we need to add those dirty trees to dirty
cowonly tree lists at least in btrfs_create_tree().

Unfortunately this means we still need to export
add_root_to_dirty_list(), and would cause conflicts with later patches.

Thanks,
Qu
> ---
>   mkfs/main.c | 1 -
>   1 file changed, 1 deletion(-)
>
> diff --git a/mkfs/main.c b/mkfs/main.c
> index 1c5d668e..1b917f55 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,

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs
  2023-08-29  6:32   ` Qu Wenruo
@ 2023-08-29  6:42     ` Qu Wenruo
  0 siblings, 0 replies; 44+ messages in thread
From: Qu Wenruo @ 2023-08-29  6:42 UTC (permalink / raw)
  To: Josef Bacik, linux-btrfs, kernel-team



On 2023/8/29 14:32, Qu Wenruo wrote:
>
>
> On 2023/8/23 22:32, Josef Bacik wrote:
>> 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>
>
> Unfortunately this patch is causing extent buffer leakage. (Thanks Anand
> for finding it)
>
> The latest devel branch would cause two eb leaks, one for uuid tree
> (caused by this one), another eb would be from free space tree.

My bad, the other one is from data reloc tree, not free space tree.

Thanks,
Qu

>
> We can remove this one, but we need to add those dirty trees to dirty
> cowonly tree lists at least in btrfs_create_tree().
>
> Unfortunately this means we still need to export
> add_root_to_dirty_list(), and would cause conflicts with later patches.
>
> Thanks,
> Qu
>> ---
>>   mkfs/main.c | 1 -
>>   1 file changed, 1 deletion(-)
>>
>> diff --git a/mkfs/main.c b/mkfs/main.c
>> index 1c5d668e..1b917f55 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,

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2023-08-29  6:44 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-23 14:32 [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs Josef Bacik
2023-08-23 14:32 ` [PATCH 01/38] btrfs-progs: stop using add_root_to_dirty_list in check Josef Bacik
2023-08-23 14:32 ` [PATCH 02/38] btrfs-progs: remove useless add_root_to_dirty_list call in mkfs Josef Bacik
2023-08-29  6:32   ` Qu Wenruo
2023-08-29  6:42     ` Qu Wenruo
2023-08-23 14:32 ` [PATCH 03/38] btrfs-progs: remove add_root_to_dirty_list call when creating free space tree Josef Bacik
2023-08-23 14:32 ` [PATCH 04/38] btrfs-progs: make add_root_to_dirty_list static and unexport it Josef Bacik
2023-08-23 14:32 ` [PATCH 05/38] btrfs-progs: pass btrfs_trans_handle through btrfs_clear_buffer_dirty Josef Bacik
2023-08-23 14:32 ` [PATCH 06/38] btrfs-progs: update read_node_slot to match the kernel definition Josef Bacik
2023-08-23 14:32 ` [PATCH 07/38] btrfs-progs: update btrfs_bin_search " Josef Bacik
2023-08-23 14:32 ` [PATCH 08/38] btrfs-progs: update btrfs_set_item_key_safe to match " Josef Bacik
2023-08-23 14:32 ` [PATCH 09/38] btrfs-progs: update btrfs_print_leaf to match the " Josef Bacik
2023-08-23 14:32 ` [PATCH 10/38] btrfs-progs: update btrfs_truncate_item " Josef Bacik
2023-08-23 14:32 ` [PATCH 11/38] btrfs-progs: update btrfs_extend_item " Josef Bacik
2023-08-23 14:32 ` [PATCH 12/38] btrfs-progs: sync memcpy_extent_buffer from the kernel Josef Bacik
2023-08-23 14:32 ` [PATCH 13/38] btrfs-progs: drop btrfs_init_path Josef Bacik
2023-08-23 17:25   ` David Sterba
2023-08-23 14:32 ` [PATCH 14/38] btrfs-progs: move btrfs_set_item_key_unsafe to check/ Josef Bacik
2023-08-23 14:32 ` [PATCH 15/38] btrfs-progs: move btrfs_record_file_extent and code into a new file Josef Bacik
2023-08-23 14:32 ` [PATCH 16/38] btrfs-progs: make a local copy of btrfs_next_sibling_block in print-tree.c Josef Bacik
2023-08-23 14:32 ` [PATCH 17/38] btrfs-progs: don't set the ->commit_root in btrfs_create_tree Josef Bacik
2023-08-23 14:32 ` [PATCH 18/38] btrfs-progs: remove btrfs_create_root Josef Bacik
2023-08-23 14:32 ` [PATCH 19/38] btrfs-progs: move btrfs_uuid_tree_add into mkfs/main.c Josef Bacik
2023-08-23 14:32 ` [PATCH 20/38] btrfs-progs: make btrfs_del_ptr a void Josef Bacik
2023-08-23 14:32 ` [PATCH 21/38] btrfs-progs: replace blocksize with parent argument for btrfs_alloc_tree_block Josef Bacik
2023-08-23 14:32 ` [PATCH 22/38] btrfs-progs: use path->search_for_extension Josef Bacik
2023-08-23 14:32 ` [PATCH 23/38] btrfs-progs: init new tree blocks in btrfs_alloc_tree_block Josef Bacik
2023-08-23 14:32 ` [PATCH 24/38] btrfs-progs: add dwarves to the package list for ci Josef Bacik
2023-08-23 14:32 ` [PATCH 25/38] btrfs-progs: add kerncompat helpers for ctree.c sync Josef Bacik
2023-08-23 14:32 ` [PATCH 26/38] btrfs-progs: add trans_lock to fs_info Josef Bacik
2023-08-23 14:32 ` [PATCH 27/38] btrfs-progs: add commit_root_sem to btrfs_fs_info Josef Bacik
2023-08-23 14:32 ` [PATCH 28/38] btrfs-progs: update btrfs_cow_block to match the in-kernel definition Josef Bacik
2023-08-23 14:32 ` [PATCH 29/38] btrfs-progs: update btrfs_insert_empty_items to match the kernel Josef Bacik
2023-08-23 14:32 ` [PATCH 30/38] btrfs-progs: update btrfs_insert_empty_item " Josef Bacik
2023-08-23 14:32 ` [PATCH 31/38] btrfs-progs: update btrfs_del_ptr " Josef Bacik
2023-08-23 14:32 ` [PATCH 32/38] btrfs-progs: update btrfs_insert_item " Josef Bacik
2023-08-23 14:32 ` [PATCH 33/38] btrfs-progs: update btrfs_leaf_free_space " Josef Bacik
2023-08-23 14:33 ` [PATCH 34/38] btrfs-progs: use btrfs_tree_parent_check for btrfs_read_extent_buffer Josef Bacik
2023-08-23 14:33 ` [PATCH 35/38] btrfs-progs: update read_tree_block to take a btrfs_parent_tree_check Josef Bacik
2023-08-23 14:33 ` [PATCH 36/38] btrfs-progs: inline btrfs_name_hash and btrfs_extref_hash Josef Bacik
2023-08-23 14:33 ` [PATCH 37/38] btrfs-progs: update btrfs_split_item to match the in-kernel definition Josef Bacik
2023-08-23 14:33 ` [PATCH 38/38] btrfs-progs: sync ctree.c from kernel Josef Bacik
2023-08-23 17:41 ` [PATCH 00/38] btrfs-progs: sync ctree.c into btrfs-progs David Sterba
2023-08-25 21:35 ` David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.