All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block()
@ 2023-09-26 12:45 fdmanana
  2023-09-26 12:45 ` [PATCH 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

This adds some missing error handling for highly unexpected but critical
conditions when COWing a tree block, some cleanups and moving some defrag
specific code out of ctree.c into defrag.c. More details on the changelogs.

Filipe Manana (8):
  btrfs: error out when COWing block using a stale transaction
  btrfs: error when COWing block from a root that is being deleted
  btrfs: error out when reallocating block for defrag using a stale transaction
  btrfs: remove noinline attribute from btrfs_cow_block()
  btrfs: use round_down() to align block offset at btrfs_cow_block()
  btrfs: rename and export __btrfs_cow_block()
  btrfs: export comp_keys() from ctree.c as btrfs_comp_keys()
  btrfs: move btrfs_realloc_node() from ctree.c into defrag.h

 fs/btrfs/ctree.c  | 200 ++++++++++------------------------------------
 fs/btrfs/ctree.h  |  41 +++++++++-
 fs/btrfs/defrag.c | 106 ++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 162 deletions(-)

-- 
2.40.1


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

* [PATCH 1/8] btrfs: error out when COWing block using a stale transaction
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 17:31   ` David Sterba
  2023-09-26 12:45 ` [PATCH 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we have these checks to verify we are not using a
stale transaction (a past transaction with an unblocked state or higher),
and the only thing we do is to trigger a WARN with a message and a stack
trace. This however is a critical problem, highly unexpected and if it
happens it's most likely due to a bug, so we should error out and turn the
fs into error state so that such issue is much more easily noticed if it's
triggered.

The problem is critical because using such stale transaction will lead to
not persisting the extent buffer used for the COW operation, as allocating
a tree block adds the range of the respective extent buffer to the
->dirty_pages iotree of the transaction, and a stale transaction, in the
unlocked state or higher, will not flush dirty extent buffers anymore,
therefore resulting in not persisting the tree block and resource leaks
(not cleaning the dirty_pages iotree for example).

So do the following changes:

1) Return -EUCLEAN if we find a stale transaction;

2) Turn the fs into error state, with error -EUCLEAN, so that no
   transaction can be committed, and generate a stack trace;

3) Combine both conditions into a single if statement, as both are related
   and have the same error message;

4) Mark the check as unlikely, since this is not expected to ever happen.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 56d2360e597c..dff2e07ba437 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		btrfs_err(fs_info,
 			"COW'ing blocks on a fs root that's being dropped");
 
-	if (trans->transaction != fs_info->running_transaction)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid,
-		       fs_info->running_transaction->transid);
-
-	if (trans->transid != fs_info->generation)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid, fs_info->generation);
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_handle_fs_error(fs_info, -EUCLEAN,
+"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
+				      buf->start, btrfs_root_id(root),
+				      trans->transid,
+				      fs_info->running_transaction->transid,
+				      fs_info->generation);
+		return -EUCLEAN;
+	}
 
 	if (!should_cow_block(trans, root, buf)) {
 		*cow_ret = buf;
-- 
2.40.1


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

* [PATCH 2/8] btrfs: error when COWing block from a root that is being deleted
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  2023-09-26 12:45 ` [PATCH 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 12:45 ` [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we check if the block being COWed belongs to a root
that is being deleted and if so we log an error message. However this is
an unexpected case and it indicates a bug somewhere, so we should return
an error and abort the transaction. So change this in the following ways:

1) Move the check after the checks for a stale transaction, so that if
   those checks pass, we can abort the transaction;

2) Abort the transaction with -EUCLEAN, so that if the issue ever happens
   it can easily be noticed;

3) Change the logged message level from error to critical, and change the
   message itself to print the block's logical address and the ID of the
   root;

4) Return -EUCLEAN to the caller;

5) As this is an unexpected scenario, that should never happen, mark the
   check as unlikely, allowing the compiler to potentially generate better
   code.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index dff2e07ba437..4eef1a7d1db6 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -682,10 +682,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 	u64 search_start;
 	int ret;
 
-	if (test_bit(BTRFS_ROOT_DELETING, &root->state))
-		btrfs_err(fs_info,
-			"COW'ing blocks on a fs root that's being dropped");
-
 	/*
 	 * COWing must happen through a running transaction, which always
 	 * matches the current fs generation (it's a transaction with a state
@@ -703,6 +699,14 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		return -EUCLEAN;
 	}
 
+	if (unlikely(test_bit(BTRFS_ROOT_DELETING, &root->state))) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+		   "attempt to COW block %llu on root %llu that is being deleted",
+			   buf->start, btrfs_root_id(root));
+		return -EUCLEAN;
+	}
+
 	if (!should_cow_block(trans, root, buf)) {
 		*cow_ret = buf;
 		return 0;
-- 
2.40.1


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

* [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  2023-09-26 12:45 ` [PATCH 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
  2023-09-26 12:45 ` [PATCH 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 17:41   ` David Sterba
  2023-09-26 12:45 ` [PATCH 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_realloc_node() we have these checks to verify we are not using a
stale transaction (a past transaction with an unblocked state or higher),
and the only thing we do is to trigger two WARN_ON(). This however is a
critical problem, highly unexpected and if it happens it's most likely due
to a bug, so we should error out and turn the fs into error state so that
such issue is much more easily noticed if it's triggered.

The problem is critical because in btrfs_realloc_node() we COW tree blocks,
and using such stale transaction will lead to not persisting the extent
buffers used for the COW operations, as allocating tree block adds the
range of the respective extent buffers to the ->dirty_pages iotree of the
transaction, and a stale transaction, in the unlocked state or higher,
will not flush dirty extent buffers anymore, therefore resulting in not
persisting the tree block and resource leaks (not cleaning the dirty_pages
iotree for example).

So do the following changes:

1) Return -EUCLEAN if we find a stale transaction;

2) Turn the fs into error state, with error -EUCLEAN, so that no
   transaction can be committed, and generate a stack trace;

3) Combine both conditions into a single if statement, as both are related
   and have the same error message;

4) Mark the check as unlikely, since this is not expected to ever happen.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 4eef1a7d1db6..8619172bcba1 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -817,8 +817,22 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 	int progress_passed = 0;
 	struct btrfs_disk_key disk_key;
 
-	WARN_ON(trans->transaction != fs_info->running_transaction);
-	WARN_ON(trans->transid != fs_info->generation);
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_handle_fs_error(fs_info, -EUCLEAN,
+"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
+				      parent->start, btrfs_root_id(root),
+				      trans->transid,
+				      fs_info->running_transaction->transid,
+				      fs_info->generation);
+		return -EUCLEAN;
+	}
 
 	parent_nritems = btrfs_header_nritems(parent);
 	blocksize = fs_info->nodesize;
-- 
2.40.1


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

* [PATCH 4/8] btrfs: remove noinline attribute from btrfs_cow_block()
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (2 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 12:45 ` [PATCH 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

It's pointless to have the noiline attribute for btrfs_cow_block(), as the
function is exported and widely used. So remove it.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 8619172bcba1..602da318ba11 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -672,7 +672,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
  * 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,
+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,
-- 
2.40.1


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

* [PATCH 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block()
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (3 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 12:45 ` [PATCH 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we can use round_down() to align the extent buffer's
logical offset to the start offset of a metadata block group, instead of
the less easy to read set of bitwise operations (two plus one subtraction).
So replace the bitwise operations with a round_down() call.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 602da318ba11..9849477c5e19 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -712,7 +712,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		return 0;
 	}
 
-	search_start = buf->start & ~((u64)SZ_1G - 1);
+	search_start = round_down(buf->start, SZ_1G);
 
 	/*
 	 * Before CoWing this block for later modification, check if it's
-- 
2.40.1


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

* [PATCH 6/8] btrfs: rename and export __btrfs_cow_block()
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (4 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 12:45 ` [PATCH 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

Rename and export __btrfs_cow_block() as btrfs_force_cow_block(). This is
to allow to move defrag specific code out of ctree.c and into defrag.c in
one of the next patches.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 30 +++++++++++++++---------------
 fs/btrfs/ctree.h |  7 +++++++
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 9849477c5e19..fddf700cc1a7 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -507,13 +507,13 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
  * bytes the allocator should try to find free next to the block it returns.
  * This is just a hint and may be ignored by the allocator.
  */
-static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *root,
-			     struct extent_buffer *buf,
-			     struct extent_buffer *parent, int parent_slot,
-			     struct extent_buffer **cow_ret,
-			     u64 search_start, u64 empty_size,
-			     enum btrfs_lock_nesting nest)
+int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
+			  struct btrfs_root *root,
+			  struct extent_buffer *buf,
+			  struct extent_buffer *parent, int parent_slot,
+			  struct extent_buffer **cow_ret,
+			  u64 search_start, u64 empty_size,
+			  enum btrfs_lock_nesting nest)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct btrfs_disk_key disk_key;
@@ -668,7 +668,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
 }
 
 /*
- * cows a single block, see __btrfs_cow_block for the real work.
+ * COWs a single block, see btrfs_force_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
  */
@@ -721,8 +721,8 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 	 * 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, nest);
+	ret = btrfs_force_cow_block(trans, root, buf, parent, parent_slot,
+				    cow_ret, search_start, 0, nest);
 
 	trace_btrfs_cow_block(root, buf, *cow_ret);
 
@@ -873,11 +873,11 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 			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);
+		err = btrfs_force_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);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 0c059f20533d..c685952a544c 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -484,6 +484,13 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		    struct extent_buffer *parent, int parent_slot,
 		    struct extent_buffer **cow_ret,
 		    enum btrfs_lock_nesting nest);
+int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
+			  struct btrfs_root *root,
+			  struct extent_buffer *buf,
+			  struct extent_buffer *parent, int parent_slot,
+			  struct extent_buffer **cow_ret,
+			  u64 search_start, u64 empty_size,
+			  enum btrfs_lock_nesting nest);
 int btrfs_copy_root(struct btrfs_trans_handle *trans,
 		      struct btrfs_root *root,
 		      struct extent_buffer *buf,
-- 
2.40.1


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

* [PATCH 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys()
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (5 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-26 12:45 ` [PATCH 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.h fdmanana
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

Export comp_keys() out of ctree.c, as btrfs_comp_keys(), so that in a
later patch we can move out defrag specific code from ctree.c into
defrag.c.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 44 +++++++-------------------------------------
 fs/btrfs/ctree.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index fddf700cc1a7..f584e79c29e9 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -743,36 +743,6 @@ static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
 	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
  */
@@ -845,7 +815,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 		int close = 1;
 
 		btrfs_node_key(parent, &disk_key, i);
-		if (!progress_passed && comp_keys(&disk_key, progress) < 0)
+		if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0)
 			continue;
 
 		progress_passed = 1;
@@ -958,7 +928,7 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
 			tmp = &unaligned;
 		}
 
-		ret = comp_keys(tmp, key);
+		ret = btrfs_comp_keys(tmp, key);
 
 		if (ret < 0)
 			low = mid + 1;
@@ -1995,7 +1965,7 @@ static int search_leaf(struct btrfs_trans_handle *trans,
 			 * the extent buffer's header and we have recently accessed
 			 * the header's level field.
 			 */
-			ret = comp_keys(&first_key, key);
+			ret = btrfs_comp_keys(&first_key, key);
 			if (ret < 0) {
 				/*
 				 * The first key is smaller than the key we want
@@ -2504,7 +2474,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 	 */
 	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);
+		ret = btrfs_comp_keys(&found_key, &orig_key);
 		if (ret == 0) {
 			if (path->slots[0] > 0) {
 				path->slots[0]--;
@@ -2519,7 +2489,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 	}
 
 	btrfs_item_key(path->nodes[0], &found_key, 0);
-	ret = comp_keys(&found_key, &key);
+	ret = btrfs_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
@@ -2710,7 +2680,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
 	slot = path->slots[0];
 	if (slot > 0) {
 		btrfs_item_key(eb, &disk_key, slot - 1);
-		if (unlikely(comp_keys(&disk_key, new_key) >= 0)) {
+		if (unlikely(btrfs_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)",
@@ -2724,7 +2694,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
 	}
 	if (slot < btrfs_header_nritems(eb) - 1) {
 		btrfs_item_key(eb, &disk_key, slot + 1);
-		if (unlikely(comp_keys(&disk_key, new_key) <= 0)) {
+		if (unlikely(btrfs_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)",
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index c685952a544c..e6d982c3ea11 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -461,6 +461,36 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
 		     const struct btrfs_key *key, int *slot);
 
 int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
+
+#ifdef __LITTLE_ENDIAN
+
+/*
+ * Compare two keys, on little-endian the disk order is same as CPU order and
+ * we can avoid the conversion.
+ */
+static inline int btrfs_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 inline int btrfs_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
+
 int btrfs_previous_item(struct btrfs_root *root,
 			struct btrfs_path *path, u64 min_objectid,
 			int type);
-- 
2.40.1


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

* [PATCH 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.h
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (6 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
@ 2023-09-26 12:45 ` fdmanana
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-26 12:45 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

btrfs_realloc_node() is only used by the defrag code. Nowadays we have a
defrag.c file, so move it, and its helper close_blocks(), into defrag.c.

During the move also do a few minor cosmetic changes:

1) Change the return value of close_blocks() from int to bool;

2) Use SZ_32K instead of 32768 at close_blocks();

3) Make some variables const in btrfs_realloc_node(), 'blocksize' and
   'end_slot';

4) Get rid of 'parent_nritems' variable, in both places where it was
   used it could be replaced by calling btrfs_header_nritems(parent);

5) Change the type of a couple variables from int to bool;

6) Rename variable 'err' to 'ret', as that's the most common name we
   use to track the return value of a function;

7) Move some variables from the top scope to the scope of the for loop
   where they are used.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c  | 112 ----------------------------------------------
 fs/btrfs/ctree.h  |   4 --
 fs/btrfs/defrag.c | 106 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+), 116 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index f584e79c29e9..6cbebe8c416d 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -730,19 +730,6 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 }
 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 int close_blocks(u64 blocknr, u64 other, u32 blocksize)
-{
-	if (blocknr < other && other - (blocknr + blocksize) < 32768)
-		return 1;
-	if (blocknr > other && blocknr - (other + blocksize) < 32768)
-		return 1;
-	return 0;
-}
-
 /*
  * same as comp_keys only with two btrfs_key's
  */
@@ -763,105 +750,6 @@ int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_ke
 	return 0;
 }
 
-/*
- * 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
- */
-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_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;
-
-	/*
-	 * COWing must happen through a running transaction, which always
-	 * matches the current fs generation (it's a transaction with a state
-	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
-	 * into error state to prevent the commit of any transaction.
-	 */
-	if (unlikely(trans->transaction != fs_info->running_transaction ||
-		     trans->transid != fs_info->generation)) {
-		btrfs_handle_fs_error(fs_info, -EUCLEAN,
-"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
-				      parent->start, btrfs_root_id(root),
-				      trans->transid,
-				      fs_info->running_transaction->transid,
-				      fs_info->generation);
-		return -EUCLEAN;
-	}
-
-	parent_nritems = btrfs_header_nritems(parent);
-	blocksize = fs_info->nodesize;
-	end_slot = parent_nritems - 1;
-
-	if (parent_nritems <= 1)
-		return 0;
-
-	for (i = start_slot; i <= end_slot; i++) {
-		int close = 1;
-
-		btrfs_node_key(parent, &disk_key, i);
-		if (!progress_passed && btrfs_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_force_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 a key in the given extent_buffer.
  *
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index e6d982c3ea11..353ba4821f25 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -553,10 +553,6 @@ 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_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);
 void btrfs_release_path(struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index 53544787c348..ad084c295378 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -337,6 +337,112 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
 	return 0;
 }
 
+/*
+ * Helper function for defrag to decide if two blocks pointed to by a node are
+ * actually close by.
+ */
+static bool close_blocks(u64 blocknr, u64 other, u32 blocksize)
+{
+	if (blocknr < other && other - (blocknr + blocksize) < SZ_32K)
+		return true;
+	if (blocknr > other && blocknr - (other + blocksize) < SZ_32K)
+		return true;
+	return false;
+}
+
+/*
+ * 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_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_fs_info *fs_info = root->fs_info;
+	const u32 blocksize = fs_info->nodesize;
+	const int end_slot = btrfs_header_nritems(parent) - 1;
+	u64 search_start = *last_ret;
+	u64 last_block = 0;
+	int ret = 0;
+	bool progress_passed = false;
+
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_handle_fs_error(fs_info, -EUCLEAN,
+"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
+				      parent->start, btrfs_root_id(root),
+				      trans->transid,
+				      fs_info->running_transaction->transid,
+				      fs_info->generation);
+		return -EUCLEAN;
+	}
+
+	if (btrfs_header_nritems(parent) <= 1)
+		return 0;
+
+	for (int i = start_slot; i <= end_slot; i++) {
+		struct extent_buffer *cur;
+		struct btrfs_disk_key disk_key;
+		u64 blocknr;
+		u64 other;
+		bool close = true;
+
+		btrfs_node_key(parent, &disk_key, i);
+		if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0)
+			continue;
+
+		progress_passed = true;
+		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);
+		ret = btrfs_force_cow_block(trans, root, cur, parent, i,
+					    &cur, search_start,
+					    min(16 * blocksize,
+						(end_slot - i) * blocksize),
+					    BTRFS_NESTING_COW);
+		if (ret) {
+			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 ret;
+}
+
 /*
  * Defrag all the leaves in a given btree.
  * Read all the leaves and try to get key order to
-- 
2.40.1


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

* Re: [PATCH 1/8] btrfs: error out when COWing block using a stale transaction
  2023-09-26 12:45 ` [PATCH 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
@ 2023-09-26 17:31   ` David Sterba
  2023-09-26 17:57     ` Filipe Manana
  0 siblings, 1 reply; 24+ messages in thread
From: David Sterba @ 2023-09-26 17:31 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Tue, Sep 26, 2023 at 01:45:13PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> At btrfs_cow_block() we have these checks to verify we are not using a
> stale transaction (a past transaction with an unblocked state or higher),
> and the only thing we do is to trigger a WARN with a message and a stack
> trace. This however is a critical problem, highly unexpected and if it
> happens it's most likely due to a bug, so we should error out and turn the
> fs into error state so that such issue is much more easily noticed if it's
> triggered.
> 
> The problem is critical because using such stale transaction will lead to
> not persisting the extent buffer used for the COW operation, as allocating
> a tree block adds the range of the respective extent buffer to the
> ->dirty_pages iotree of the transaction, and a stale transaction, in the
> unlocked state or higher, will not flush dirty extent buffers anymore,
> therefore resulting in not persisting the tree block and resource leaks
> (not cleaning the dirty_pages iotree for example).
> 
> So do the following changes:
> 
> 1) Return -EUCLEAN if we find a stale transaction;
> 
> 2) Turn the fs into error state, with error -EUCLEAN, so that no
>    transaction can be committed, and generate a stack trace;
> 
> 3) Combine both conditions into a single if statement, as both are related
>    and have the same error message;
> 
> 4) Mark the check as unlikely, since this is not expected to ever happen.
> 
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>  fs/btrfs/ctree.c | 24 ++++++++++++++++--------
>  1 file changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 56d2360e597c..dff2e07ba437 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
>  		btrfs_err(fs_info,
>  			"COW'ing blocks on a fs root that's being dropped");
>  
> -	if (trans->transaction != fs_info->running_transaction)
> -		WARN(1, KERN_CRIT "trans %llu running %llu\n",
> -		       trans->transid,
> -		       fs_info->running_transaction->transid);
> -
> -	if (trans->transid != fs_info->generation)
> -		WARN(1, KERN_CRIT "trans %llu running %llu\n",
> -		       trans->transid, fs_info->generation);
> +	/*
> +	 * COWing must happen through a running transaction, which always
> +	 * matches the current fs generation (it's a transaction with a state
> +	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
> +	 * into error state to prevent the commit of any transaction.
> +	 */
> +	if (unlikely(trans->transaction != fs_info->running_transaction ||
> +		     trans->transid != fs_info->generation)) {
> +		btrfs_handle_fs_error(fs_info, -EUCLEAN,

Can this be a transaction abort? The helper btrfs_handle_fs_error() is
from times before we had the abort mechanism and should not be used in
new code when the abort can be done. There are cases where transaction
is not available (like superblock commit), but these are exceptions.

> +"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
> +				      buf->start, btrfs_root_id(root),
> +				      trans->transid,
> +				      fs_info->running_transaction->transid,
> +				      fs_info->generation);
> +		return -EUCLEAN;
> +	}
>  
>  	if (!should_cow_block(trans, root, buf)) {
>  		*cow_ret = buf;
> -- 
> 2.40.1

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

* Re: [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction
  2023-09-26 12:45 ` [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
@ 2023-09-26 17:41   ` David Sterba
  0 siblings, 0 replies; 24+ messages in thread
From: David Sterba @ 2023-09-26 17:41 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Tue, Sep 26, 2023 at 01:45:15PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> At btrfs_realloc_node() we have these checks to verify we are not using a
> stale transaction (a past transaction with an unblocked state or higher),
> and the only thing we do is to trigger two WARN_ON(). This however is a
> critical problem, highly unexpected and if it happens it's most likely due
> to a bug, so we should error out and turn the fs into error state so that
> such issue is much more easily noticed if it's triggered.
> 
> The problem is critical because in btrfs_realloc_node() we COW tree blocks,
> and using such stale transaction will lead to not persisting the extent
> buffers used for the COW operations, as allocating tree block adds the
> range of the respective extent buffers to the ->dirty_pages iotree of the
> transaction, and a stale transaction, in the unlocked state or higher,
> will not flush dirty extent buffers anymore, therefore resulting in not
> persisting the tree block and resource leaks (not cleaning the dirty_pages
> iotree for example).
> 
> So do the following changes:
> 
> 1) Return -EUCLEAN if we find a stale transaction;
> 
> 2) Turn the fs into error state, with error -EUCLEAN, so that no
>    transaction can be committed, and generate a stack trace;
> 
> 3) Combine both conditions into a single if statement, as both are related
>    and have the same error message;
> 
> 4) Mark the check as unlikely, since this is not expected to ever happen.
> 
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>  fs/btrfs/ctree.c | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 4eef1a7d1db6..8619172bcba1 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -817,8 +817,22 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
>  	int progress_passed = 0;
>  	struct btrfs_disk_key disk_key;
>  
> -	WARN_ON(trans->transaction != fs_info->running_transaction);
> -	WARN_ON(trans->transid != fs_info->generation);
> +	/*
> +	 * COWing must happen through a running transaction, which always
> +	 * matches the current fs generation (it's a transaction with a state
> +	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
> +	 * into error state to prevent the commit of any transaction.
> +	 */
> +	if (unlikely(trans->transaction != fs_info->running_transaction ||
> +		     trans->transid != fs_info->generation)) {
> +		btrfs_handle_fs_error(fs_info, -EUCLEAN,

Same question as in patch 1, could this be btrfs_abort_transaction()?

> +"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
> +				      parent->start, btrfs_root_id(root),
> +				      trans->transid,
> +				      fs_info->running_transaction->transid,
> +				      fs_info->generation);
> +		return -EUCLEAN;
> +	}
>  
>  	parent_nritems = btrfs_header_nritems(parent);
>  	blocksize = fs_info->nodesize;
> -- 
> 2.40.1

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

* Re: [PATCH 1/8] btrfs: error out when COWing block using a stale transaction
  2023-09-26 17:31   ` David Sterba
@ 2023-09-26 17:57     ` Filipe Manana
  2023-09-26 18:18       ` Filipe Manana
  0 siblings, 1 reply; 24+ messages in thread
From: Filipe Manana @ 2023-09-26 17:57 UTC (permalink / raw)
  To: dsterba; +Cc: linux-btrfs

On Tue, Sep 26, 2023 at 6:38 PM David Sterba <dsterba@suse.cz> wrote:
>
> On Tue, Sep 26, 2023 at 01:45:13PM +0100, fdmanana@kernel.org wrote:
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > At btrfs_cow_block() we have these checks to verify we are not using a
> > stale transaction (a past transaction with an unblocked state or higher),
> > and the only thing we do is to trigger a WARN with a message and a stack
> > trace. This however is a critical problem, highly unexpected and if it
> > happens it's most likely due to a bug, so we should error out and turn the
> > fs into error state so that such issue is much more easily noticed if it's
> > triggered.
> >
> > The problem is critical because using such stale transaction will lead to
> > not persisting the extent buffer used for the COW operation, as allocating
> > a tree block adds the range of the respective extent buffer to the
> > ->dirty_pages iotree of the transaction, and a stale transaction, in the
> > unlocked state or higher, will not flush dirty extent buffers anymore,
> > therefore resulting in not persisting the tree block and resource leaks
> > (not cleaning the dirty_pages iotree for example).
> >
> > So do the following changes:
> >
> > 1) Return -EUCLEAN if we find a stale transaction;
> >
> > 2) Turn the fs into error state, with error -EUCLEAN, so that no
> >    transaction can be committed, and generate a stack trace;
> >
> > 3) Combine both conditions into a single if statement, as both are related
> >    and have the same error message;
> >
> > 4) Mark the check as unlikely, since this is not expected to ever happen.
> >
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > ---
> >  fs/btrfs/ctree.c | 24 ++++++++++++++++--------
> >  1 file changed, 16 insertions(+), 8 deletions(-)
> >
> > diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> > index 56d2360e597c..dff2e07ba437 100644
> > --- a/fs/btrfs/ctree.c
> > +++ b/fs/btrfs/ctree.c
> > @@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
> >               btrfs_err(fs_info,
> >                       "COW'ing blocks on a fs root that's being dropped");
> >
> > -     if (trans->transaction != fs_info->running_transaction)
> > -             WARN(1, KERN_CRIT "trans %llu running %llu\n",
> > -                    trans->transid,
> > -                    fs_info->running_transaction->transid);
> > -
> > -     if (trans->transid != fs_info->generation)
> > -             WARN(1, KERN_CRIT "trans %llu running %llu\n",
> > -                    trans->transid, fs_info->generation);
> > +     /*
> > +      * COWing must happen through a running transaction, which always
> > +      * matches the current fs generation (it's a transaction with a state
> > +      * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
> > +      * into error state to prevent the commit of any transaction.
> > +      */
> > +     if (unlikely(trans->transaction != fs_info->running_transaction ||
> > +                  trans->transid != fs_info->generation)) {
> > +             btrfs_handle_fs_error(fs_info, -EUCLEAN,
>
> Can this be a transaction abort? The helper btrfs_handle_fs_error() is
> from times before we had the abort mechanism and should not be used in
> new code when the abort can be done. There are cases where transaction
> is not available (like superblock commit), but these are exceptions.

The handle we have here is for a stale transaction - not the one
currently running (if there's any).
That's why the btrfs_handle_fs_error() call instead.

>
> > +"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
> > +                                   buf->start, btrfs_root_id(root),
> > +                                   trans->transid,
> > +                                   fs_info->running_transaction->transid,
> > +                                   fs_info->generation);
> > +             return -EUCLEAN;
> > +     }
> >
> >       if (!should_cow_block(trans, root, buf)) {
> >               *cow_ret = buf;
> > --
> > 2.40.1

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

* Re: [PATCH 1/8] btrfs: error out when COWing block using a stale transaction
  2023-09-26 17:57     ` Filipe Manana
@ 2023-09-26 18:18       ` Filipe Manana
  0 siblings, 0 replies; 24+ messages in thread
From: Filipe Manana @ 2023-09-26 18:18 UTC (permalink / raw)
  To: dsterba; +Cc: linux-btrfs

On Tue, Sep 26, 2023 at 6:57 PM Filipe Manana <fdmanana@kernel.org> wrote:
>
> On Tue, Sep 26, 2023 at 6:38 PM David Sterba <dsterba@suse.cz> wrote:
> >
> > On Tue, Sep 26, 2023 at 01:45:13PM +0100, fdmanana@kernel.org wrote:
> > > From: Filipe Manana <fdmanana@suse.com>
> > >
> > > At btrfs_cow_block() we have these checks to verify we are not using a
> > > stale transaction (a past transaction with an unblocked state or higher),
> > > and the only thing we do is to trigger a WARN with a message and a stack
> > > trace. This however is a critical problem, highly unexpected and if it
> > > happens it's most likely due to a bug, so we should error out and turn the
> > > fs into error state so that such issue is much more easily noticed if it's
> > > triggered.
> > >
> > > The problem is critical because using such stale transaction will lead to
> > > not persisting the extent buffer used for the COW operation, as allocating
> > > a tree block adds the range of the respective extent buffer to the
> > > ->dirty_pages iotree of the transaction, and a stale transaction, in the
> > > unlocked state or higher, will not flush dirty extent buffers anymore,
> > > therefore resulting in not persisting the tree block and resource leaks
> > > (not cleaning the dirty_pages iotree for example).
> > >
> > > So do the following changes:
> > >
> > > 1) Return -EUCLEAN if we find a stale transaction;
> > >
> > > 2) Turn the fs into error state, with error -EUCLEAN, so that no
> > >    transaction can be committed, and generate a stack trace;
> > >
> > > 3) Combine both conditions into a single if statement, as both are related
> > >    and have the same error message;
> > >
> > > 4) Mark the check as unlikely, since this is not expected to ever happen.
> > >
> > > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > > ---
> > >  fs/btrfs/ctree.c | 24 ++++++++++++++++--------
> > >  1 file changed, 16 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> > > index 56d2360e597c..dff2e07ba437 100644
> > > --- a/fs/btrfs/ctree.c
> > > +++ b/fs/btrfs/ctree.c
> > > @@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
> > >               btrfs_err(fs_info,
> > >                       "COW'ing blocks on a fs root that's being dropped");
> > >
> > > -     if (trans->transaction != fs_info->running_transaction)
> > > -             WARN(1, KERN_CRIT "trans %llu running %llu\n",
> > > -                    trans->transid,
> > > -                    fs_info->running_transaction->transid);
> > > -
> > > -     if (trans->transid != fs_info->generation)
> > > -             WARN(1, KERN_CRIT "trans %llu running %llu\n",
> > > -                    trans->transid, fs_info->generation);
> > > +     /*
> > > +      * COWing must happen through a running transaction, which always
> > > +      * matches the current fs generation (it's a transaction with a state
> > > +      * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
> > > +      * into error state to prevent the commit of any transaction.
> > > +      */
> > > +     if (unlikely(trans->transaction != fs_info->running_transaction ||
> > > +                  trans->transid != fs_info->generation)) {
> > > +             btrfs_handle_fs_error(fs_info, -EUCLEAN,
> >
> > Can this be a transaction abort? The helper btrfs_handle_fs_error() is
> > from times before we had the abort mechanism and should not be used in
> > new code when the abort can be done. There are cases where transaction
> > is not available (like superblock commit), but these are exceptions.
>
> The handle we have here is for a stale transaction - not the one
> currently running (if there's any).
> That's why the btrfs_handle_fs_error() call instead.

We can actually btrfs_abort_transaction() even on a stale one. It
still sets the error
at fs_info->fs_error, which is what matters here.

Do you want me to replace it and send a v2, or do you prefer to fixup
it up yourself?

Thanks

>
> >
> > > +"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
> > > +                                   buf->start, btrfs_root_id(root),
> > > +                                   trans->transid,
> > > +                                   fs_info->running_transaction->transid,
> > > +                                   fs_info->generation);
> > > +             return -EUCLEAN;
> > > +     }
> > >
> > >       if (!should_cow_block(trans, root, buf)) {
> > >               *cow_ret = buf;
> > > --
> > > 2.40.1

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

* [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block()
  2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                   ` (7 preceding siblings ...)
  2023-09-26 12:45 ` [PATCH 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.h fdmanana
@ 2023-09-27 11:09 ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
                     ` (8 more replies)
  8 siblings, 9 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

This adds some missing error handling for highly unexpected but critical
conditions when COWing a tree block, some cleanups and moving some defrag
specific code out of ctree.c into defrag.c. More details on the changelogs.

V2: Fix compilation error on big endian systems (patch 7/8).
    Use transaction abort in patches 1/8 and 3/8.

Filipe Manana (8):
  btrfs: error out when COWing block using a stale transaction
  btrfs: error when COWing block from a root that is being deleted
  btrfs: error out when reallocating block for defrag using a stale transaction
  btrfs: remove noinline attribute from btrfs_cow_block()
  btrfs: use round_down() to align block offset at btrfs_cow_block()
  btrfs: rename and export __btrfs_cow_block()
  btrfs: export comp_keys() from ctree.c as btrfs_comp_keys()
  btrfs: move btrfs_realloc_node() from ctree.c into defrag.c

 fs/btrfs/ctree.c  | 198 ++++++++++------------------------------------
 fs/btrfs/ctree.h  |  42 +++++++++-
 fs/btrfs/defrag.c | 106 +++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 161 deletions(-)

-- 
2.40.1


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

* [PATCH v2 1/8] btrfs: error out when COWing block using a stale transaction
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we have these checks to verify we are not using a
stale transaction (a past transaction with an unblocked state or higher),
and the only thing we do is to trigger a WARN with a message and a stack
trace. This however is a critical problem, highly unexpected and if it
happens it's most likely due to a bug, so we should error out and turn the
fs into error state so that such issue is much more easily noticed if it's
triggered.

The problem is critical because using such stale transaction will lead to
not persisting the extent buffer used for the COW operation, as allocating
a tree block adds the range of the respective extent buffer to the
->dirty_pages iotree of the transaction, and a stale transaction, in the
unlocked state or higher, will not flush dirty extent buffers anymore,
therefore resulting in not persisting the tree block and resource leaks
(not cleaning the dirty_pages iotree for example).

So do the following changes:

1) Return -EUCLEAN if we find a stale transaction;

2) Turn the fs into error state, with error -EUCLEAN, so that no
   transaction can be committed, and generate a stack trace;

3) Combine both conditions into a single if statement, as both are related
   and have the same error message;

4) Mark the check as unlikely, since this is not expected to ever happen.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 56d2360e597c..29b887ffe682 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -686,14 +686,22 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		btrfs_err(fs_info,
 			"COW'ing blocks on a fs root that's being dropped");
 
-	if (trans->transaction != fs_info->running_transaction)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid,
-		       fs_info->running_transaction->transid);
-
-	if (trans->transid != fs_info->generation)
-		WARN(1, KERN_CRIT "trans %llu running %llu\n",
-		       trans->transid, fs_info->generation);
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+"unexpected transaction when attempting to COW block %llu on root %llu, transaction %llu running transaction %llu fs generation %llu",
+			   buf->start, btrfs_root_id(root), trans->transid,
+			   fs_info->running_transaction->transid,
+			   fs_info->generation);
+		return -EUCLEAN;
+	}
 
 	if (!should_cow_block(trans, root, buf)) {
 		*cow_ret = buf;
-- 
2.40.1


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

* [PATCH v2 2/8] btrfs: error when COWing block from a root that is being deleted
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  2023-09-27 11:09   ` [PATCH v2 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we check if the block being COWed belongs to a root
that is being deleted and if so we log an error message. However this is
an unexpected case and it indicates a bug somewhere, so we should return
an error and abort the transaction. So change this in the following ways:

1) Abort the transaction with -EUCLEAN, so that if the issue ever happens
   it can easily be noticed;

2) Change the logged message level from error to critical, and change the
   message itself to print the block's logical address and the ID of the
   root;

3) Return -EUCLEAN to the caller;

4) As this is an unexpected scenario, that should never happen, mark the
   check as unlikely, allowing the compiler to potentially generate better
   code.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 29b887ffe682..e3382542f642 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -682,9 +682,13 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 	u64 search_start;
 	int ret;
 
-	if (test_bit(BTRFS_ROOT_DELETING, &root->state))
-		btrfs_err(fs_info,
-			"COW'ing blocks on a fs root that's being dropped");
+	if (unlikely(test_bit(BTRFS_ROOT_DELETING, &root->state))) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+		   "attempt to COW block %llu on root %llu that is being deleted",
+			   buf->start, btrfs_root_id(root));
+		return -EUCLEAN;
+	}
 
 	/*
 	 * COWing must happen through a running transaction, which always
-- 
2.40.1


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

* [PATCH v2 3/8] btrfs: error out when reallocating block for defrag using a stale transaction
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
  2023-09-27 11:09   ` [PATCH v2 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
  2023-09-27 11:09   ` [PATCH v2 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_realloc_node() we have these checks to verify we are not using a
stale transaction (a past transaction with an unblocked state or higher),
and the only thing we do is to trigger two WARN_ON(). This however is a
critical problem, highly unexpected and if it happens it's most likely due
to a bug, so we should error out and turn the fs into error state so that
such issue is much more easily noticed if it's triggered.

The problem is critical because in btrfs_realloc_node() we COW tree blocks,
and using such stale transaction will lead to not persisting the extent
buffers used for the COW operations, as allocating tree block adds the
range of the respective extent buffers to the ->dirty_pages iotree of the
transaction, and a stale transaction, in the unlocked state or higher,
will not flush dirty extent buffers anymore, therefore resulting in not
persisting the tree block and resource leaks (not cleaning the dirty_pages
iotree for example).

So do the following changes:

1) Return -EUCLEAN if we find a stale transaction;

2) Turn the fs into error state, with error -EUCLEAN, so that no
   transaction can be committed, and generate a stack trace;

3) Combine both conditions into a single if statement, as both are related
   and have the same error message;

4) Mark the check as unlikely, since this is not expected to ever happen.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index e3382542f642..2a51cac7f21d 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -817,8 +817,22 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 	int progress_passed = 0;
 	struct btrfs_disk_key disk_key;
 
-	WARN_ON(trans->transaction != fs_info->running_transaction);
-	WARN_ON(trans->transid != fs_info->generation);
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
+			   parent->start, btrfs_root_id(root), trans->transid,
+			   fs_info->running_transaction->transid,
+			   fs_info->generation);
+		return -EUCLEAN;
+	}
 
 	parent_nritems = btrfs_header_nritems(parent);
 	blocksize = fs_info->nodesize;
-- 
2.40.1


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

* [PATCH v2 4/8] btrfs: remove noinline attribute from btrfs_cow_block()
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (2 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

It's pointless to have the noiline attribute for btrfs_cow_block(), as the
function is exported and widely used. So remove it.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 2a51cac7f21d..a05c9204928e 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -672,7 +672,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
  * 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,
+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,
-- 
2.40.1


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

* [PATCH v2 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block()
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (3 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

At btrfs_cow_block() we can use round_down() to align the extent buffer's
logical offset to the start offset of a metadata block group, instead of
the less easy to read set of bitwise operations (two plus one subtraction).
So replace the bitwise operations with a round_down() call.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index a05c9204928e..8d29b9e09286 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -712,7 +712,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		return 0;
 	}
 
-	search_start = buf->start & ~((u64)SZ_1G - 1);
+	search_start = round_down(buf->start, SZ_1G);
 
 	/*
 	 * Before CoWing this block for later modification, check if it's
-- 
2.40.1


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

* [PATCH v2 6/8] btrfs: rename and export __btrfs_cow_block()
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (4 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

Rename and export __btrfs_cow_block() as btrfs_force_cow_block(). This is
to allow to move defrag specific code out of ctree.c and into defrag.c in
one of the next patches.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 30 +++++++++++++++---------------
 fs/btrfs/ctree.h |  7 +++++++
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 8d29b9e09286..005f0e1f98b3 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -507,13 +507,13 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
  * bytes the allocator should try to find free next to the block it returns.
  * This is just a hint and may be ignored by the allocator.
  */
-static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *root,
-			     struct extent_buffer *buf,
-			     struct extent_buffer *parent, int parent_slot,
-			     struct extent_buffer **cow_ret,
-			     u64 search_start, u64 empty_size,
-			     enum btrfs_lock_nesting nest)
+int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
+			  struct btrfs_root *root,
+			  struct extent_buffer *buf,
+			  struct extent_buffer *parent, int parent_slot,
+			  struct extent_buffer **cow_ret,
+			  u64 search_start, u64 empty_size,
+			  enum btrfs_lock_nesting nest)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct btrfs_disk_key disk_key;
@@ -668,7 +668,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
 }
 
 /*
- * cows a single block, see __btrfs_cow_block for the real work.
+ * COWs a single block, see btrfs_force_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
  */
@@ -721,8 +721,8 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 	 * 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, nest);
+	ret = btrfs_force_cow_block(trans, root, buf, parent, parent_slot,
+				    cow_ret, search_start, 0, nest);
 
 	trace_btrfs_cow_block(root, buf, *cow_ret);
 
@@ -873,11 +873,11 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 			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);
+		err = btrfs_force_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);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 0c059f20533d..c685952a544c 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -484,6 +484,13 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 		    struct extent_buffer *parent, int parent_slot,
 		    struct extent_buffer **cow_ret,
 		    enum btrfs_lock_nesting nest);
+int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
+			  struct btrfs_root *root,
+			  struct extent_buffer *buf,
+			  struct extent_buffer *parent, int parent_slot,
+			  struct extent_buffer **cow_ret,
+			  u64 search_start, u64 empty_size,
+			  enum btrfs_lock_nesting nest);
 int btrfs_copy_root(struct btrfs_trans_handle *trans,
 		      struct btrfs_root *root,
 		      struct extent_buffer *buf,
-- 
2.40.1


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

* [PATCH v2 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys()
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (5 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-27 11:09   ` [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c fdmanana
  2023-09-29 14:33   ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() David Sterba
  8 siblings, 0 replies; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

Export comp_keys() out of ctree.c, as btrfs_comp_keys(), so that in a
later patch we can move out defrag specific code from ctree.c into
defrag.c.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 44 +++++++-------------------------------------
 fs/btrfs/ctree.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 005f0e1f98b3..b25b42ebcc2b 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -743,36 +743,6 @@ static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
 	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
  */
@@ -845,7 +815,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 		int close = 1;
 
 		btrfs_node_key(parent, &disk_key, i);
-		if (!progress_passed && comp_keys(&disk_key, progress) < 0)
+		if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0)
 			continue;
 
 		progress_passed = 1;
@@ -958,7 +928,7 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
 			tmp = &unaligned;
 		}
 
-		ret = comp_keys(tmp, key);
+		ret = btrfs_comp_keys(tmp, key);
 
 		if (ret < 0)
 			low = mid + 1;
@@ -1995,7 +1965,7 @@ static int search_leaf(struct btrfs_trans_handle *trans,
 			 * the extent buffer's header and we have recently accessed
 			 * the header's level field.
 			 */
-			ret = comp_keys(&first_key, key);
+			ret = btrfs_comp_keys(&first_key, key);
 			if (ret < 0) {
 				/*
 				 * The first key is smaller than the key we want
@@ -2504,7 +2474,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 	 */
 	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);
+		ret = btrfs_comp_keys(&found_key, &orig_key);
 		if (ret == 0) {
 			if (path->slots[0] > 0) {
 				path->slots[0]--;
@@ -2519,7 +2489,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 	}
 
 	btrfs_item_key(path->nodes[0], &found_key, 0);
-	ret = comp_keys(&found_key, &key);
+	ret = btrfs_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
@@ -2710,7 +2680,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
 	slot = path->slots[0];
 	if (slot > 0) {
 		btrfs_item_key(eb, &disk_key, slot - 1);
-		if (unlikely(comp_keys(&disk_key, new_key) >= 0)) {
+		if (unlikely(btrfs_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)",
@@ -2724,7 +2694,7 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
 	}
 	if (slot < btrfs_header_nritems(eb) - 1) {
 		btrfs_item_key(eb, &disk_key, slot + 1);
-		if (unlikely(comp_keys(&disk_key, new_key) <= 0)) {
+		if (unlikely(btrfs_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)",
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index c685952a544c..7b69abb5009c 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -9,6 +9,7 @@
 #include <linux/pagemap.h>
 #include "locking.h"
 #include "fs.h"
+#include "accessors.h"
 
 struct btrfs_trans_handle;
 struct btrfs_transaction;
@@ -461,6 +462,36 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
 		     const struct btrfs_key *key, int *slot);
 
 int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
+
+#ifdef __LITTLE_ENDIAN
+
+/*
+ * Compare two keys, on little-endian the disk order is same as CPU order and
+ * we can avoid the conversion.
+ */
+static inline int btrfs_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 inline int btrfs_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
+
 int btrfs_previous_item(struct btrfs_root *root,
 			struct btrfs_path *path, u64 min_objectid,
 			int type);
-- 
2.40.1


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

* [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (6 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
@ 2023-09-27 11:09   ` fdmanana
  2023-09-29 14:35     ` David Sterba
  2023-09-29 14:33   ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() David Sterba
  8 siblings, 1 reply; 24+ messages in thread
From: fdmanana @ 2023-09-27 11:09 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

btrfs_realloc_node() is only used by the defrag code. Nowadays we have a
defrag.c file, so move it, and its helper close_blocks(), into defrag.c.

During the move also do a few minor cosmetic changes:

1) Change the return value of close_blocks() from int to bool;

2) Use SZ_32K instead of 32768 at close_blocks();

3) Make some variables const in btrfs_realloc_node(), 'blocksize' and
   'end_slot';

4) Get rid of 'parent_nritems' variable, in both places where it was
   used it could be replaced by calling btrfs_header_nritems(parent);

5) Change the type of a couple variables from int to bool;

6) Rename variable 'err' to 'ret', as that's the most common name we
   use to track the return value of a function;

7) Move some variables from the top scope to the scope of the for loop
   where they are used.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c  | 112 ----------------------------------------------
 fs/btrfs/ctree.h  |   4 --
 fs/btrfs/defrag.c | 106 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+), 116 deletions(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index b25b42ebcc2b..954524316281 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -730,19 +730,6 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
 }
 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 int close_blocks(u64 blocknr, u64 other, u32 blocksize)
-{
-	if (blocknr < other && other - (blocknr + blocksize) < 32768)
-		return 1;
-	if (blocknr > other && blocknr - (other + blocksize) < 32768)
-		return 1;
-	return 0;
-}
-
 /*
  * same as comp_keys only with two btrfs_key's
  */
@@ -763,105 +750,6 @@ int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_ke
 	return 0;
 }
 
-/*
- * 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
- */
-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_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;
-
-	/*
-	 * COWing must happen through a running transaction, which always
-	 * matches the current fs generation (it's a transaction with a state
-	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
-	 * into error state to prevent the commit of any transaction.
-	 */
-	if (unlikely(trans->transaction != fs_info->running_transaction ||
-		     trans->transid != fs_info->generation)) {
-		btrfs_abort_transaction(trans, -EUCLEAN);
-		btrfs_crit(fs_info,
-"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
-			   parent->start, btrfs_root_id(root), trans->transid,
-			   fs_info->running_transaction->transid,
-			   fs_info->generation);
-		return -EUCLEAN;
-	}
-
-	parent_nritems = btrfs_header_nritems(parent);
-	blocksize = fs_info->nodesize;
-	end_slot = parent_nritems - 1;
-
-	if (parent_nritems <= 1)
-		return 0;
-
-	for (i = start_slot; i <= end_slot; i++) {
-		int close = 1;
-
-		btrfs_node_key(parent, &disk_key, i);
-		if (!progress_passed && btrfs_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_force_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 a key in the given extent_buffer.
  *
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 7b69abb5009c..5d1380425185 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -554,10 +554,6 @@ 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_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);
 void btrfs_release_path(struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index 53544787c348..4e062c72ee4c 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -337,6 +337,112 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
 	return 0;
 }
 
+/*
+ * Helper function for defrag to decide if two blocks pointed to by a node are
+ * actually close by.
+ */
+static bool close_blocks(u64 blocknr, u64 other, u32 blocksize)
+{
+	if (blocknr < other && other - (blocknr + blocksize) < SZ_32K)
+		return true;
+	if (blocknr > other && blocknr - (other + blocksize) < SZ_32K)
+		return true;
+	return false;
+}
+
+/*
+ * 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_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_fs_info *fs_info = root->fs_info;
+	const u32 blocksize = fs_info->nodesize;
+	const int end_slot = btrfs_header_nritems(parent) - 1;
+	u64 search_start = *last_ret;
+	u64 last_block = 0;
+	int ret = 0;
+	bool progress_passed = false;
+
+	/*
+	 * COWing must happen through a running transaction, which always
+	 * matches the current fs generation (it's a transaction with a state
+	 * less than TRANS_STATE_UNBLOCKED). If it doesn't, then turn the fs
+	 * into error state to prevent the commit of any transaction.
+	 */
+	if (unlikely(trans->transaction != fs_info->running_transaction ||
+		     trans->transid != fs_info->generation)) {
+		btrfs_abort_transaction(trans, -EUCLEAN);
+		btrfs_crit(fs_info,
+"unexpected transaction when attempting to reallocate parent %llu for root %llu, transaction %llu running transaction %llu fs generation %llu",
+			   parent->start, btrfs_root_id(root), trans->transid,
+			   fs_info->running_transaction->transid,
+			   fs_info->generation);
+		return -EUCLEAN;
+	}
+
+	if (btrfs_header_nritems(parent) <= 1)
+		return 0;
+
+	for (int i = start_slot; i <= end_slot; i++) {
+		struct extent_buffer *cur;
+		struct btrfs_disk_key disk_key;
+		u64 blocknr;
+		u64 other;
+		bool close = true;
+
+		btrfs_node_key(parent, &disk_key, i);
+		if (!progress_passed && btrfs_comp_keys(&disk_key, progress) < 0)
+			continue;
+
+		progress_passed = true;
+		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);
+		ret = btrfs_force_cow_block(trans, root, cur, parent, i,
+					    &cur, search_start,
+					    min(16 * blocksize,
+						(end_slot - i) * blocksize),
+					    BTRFS_NESTING_COW);
+		if (ret) {
+			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 ret;
+}
+
 /*
  * Defrag all the leaves in a given btree.
  * Read all the leaves and try to get key order to
-- 
2.40.1


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

* Re: [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block()
  2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
                     ` (7 preceding siblings ...)
  2023-09-27 11:09   ` [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c fdmanana
@ 2023-09-29 14:33   ` David Sterba
  8 siblings, 0 replies; 24+ messages in thread
From: David Sterba @ 2023-09-29 14:33 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Wed, Sep 27, 2023 at 12:09:20PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> This adds some missing error handling for highly unexpected but critical
> conditions when COWing a tree block, some cleanups and moving some defrag
> specific code out of ctree.c into defrag.c. More details on the changelogs.
> 
> V2: Fix compilation error on big endian systems (patch 7/8).
>     Use transaction abort in patches 1/8 and 3/8.
> 
> Filipe Manana (8):
>   btrfs: error out when COWing block using a stale transaction
>   btrfs: error when COWing block from a root that is being deleted
>   btrfs: error out when reallocating block for defrag using a stale transaction
>   btrfs: remove noinline attribute from btrfs_cow_block()
>   btrfs: use round_down() to align block offset at btrfs_cow_block()
>   btrfs: rename and export __btrfs_cow_block()
>   btrfs: export comp_keys() from ctree.c as btrfs_comp_keys()
>   btrfs: move btrfs_realloc_node() from ctree.c into defrag.c

Added to misc-next, thanks.

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

* Re: [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c
  2023-09-27 11:09   ` [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c fdmanana
@ 2023-09-29 14:35     ` David Sterba
  0 siblings, 0 replies; 24+ messages in thread
From: David Sterba @ 2023-09-29 14:35 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Wed, Sep 27, 2023 at 12:09:28PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> btrfs_realloc_node() is only used by the defrag code. Nowadays we have a
> defrag.c file, so move it, and its helper close_blocks(), into defrag.c.
> 
> During the move also do a few minor cosmetic changes:
> 
> 1) Change the return value of close_blocks() from int to bool;
> 
> 2) Use SZ_32K instead of 32768 at close_blocks();
> 
> 3) Make some variables const in btrfs_realloc_node(), 'blocksize' and
>    'end_slot';
> 
> 4) Get rid of 'parent_nritems' variable, in both places where it was
>    used it could be replaced by calling btrfs_header_nritems(parent);
> 
> 5) Change the type of a couple variables from int to bool;
> 
> 6) Rename variable 'err' to 'ret', as that's the most common name we
>    use to track the return value of a function;
> 
> 7) Move some variables from the top scope to the scope of the for loop
>    where they are used.

Changes like that are prefectly fine when moving code, thanks.

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

end of thread, other threads:[~2023-09-29 14:42 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-26 12:45 [PATCH 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
2023-09-26 12:45 ` [PATCH 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
2023-09-26 17:31   ` David Sterba
2023-09-26 17:57     ` Filipe Manana
2023-09-26 18:18       ` Filipe Manana
2023-09-26 12:45 ` [PATCH 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
2023-09-26 12:45 ` [PATCH 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
2023-09-26 17:41   ` David Sterba
2023-09-26 12:45 ` [PATCH 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
2023-09-26 12:45 ` [PATCH 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
2023-09-26 12:45 ` [PATCH 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
2023-09-26 12:45 ` [PATCH 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
2023-09-26 12:45 ` [PATCH 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.h fdmanana
2023-09-27 11:09 ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() fdmanana
2023-09-27 11:09   ` [PATCH v2 1/8] btrfs: error out when COWing block using a stale transaction fdmanana
2023-09-27 11:09   ` [PATCH v2 2/8] btrfs: error when COWing block from a root that is being deleted fdmanana
2023-09-27 11:09   ` [PATCH v2 3/8] btrfs: error out when reallocating block for defrag using a stale transaction fdmanana
2023-09-27 11:09   ` [PATCH v2 4/8] btrfs: remove noinline attribute from btrfs_cow_block() fdmanana
2023-09-27 11:09   ` [PATCH v2 5/8] btrfs: use round_down() to align block offset at btrfs_cow_block() fdmanana
2023-09-27 11:09   ` [PATCH v2 6/8] btrfs: rename and export __btrfs_cow_block() fdmanana
2023-09-27 11:09   ` [PATCH v2 7/8] btrfs: export comp_keys() from ctree.c as btrfs_comp_keys() fdmanana
2023-09-27 11:09   ` [PATCH v2 8/8] btrfs: move btrfs_realloc_node() from ctree.c into defrag.c fdmanana
2023-09-29 14:35     ` David Sterba
2023-09-29 14:33   ` [PATCH v2 0/8] btrfs: some fixes and cleanups around btrfs_cow_block() 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.