diff mbox series

[v9,19/41] btrfs: redirty released extent buffers in ZONED mode

Message ID b2c1ee9a3c4067b9f8823604e4c4c5c96d3abc61.1604065695.git.naohiro.aota@wdc.com (mailing list archive)
State New, archived
Headers show
Series btrfs: zoned block device support | expand

Commit Message

Naohiro Aota Oct. 30, 2020, 1:51 p.m. UTC
Tree manipulating operations like merging nodes often release
once-allocated tree nodes. Btrfs cleans such nodes so that pages in the
node are not uselessly written out. On ZONED volumes, however, such
optimization blocks the following IOs as the cancellation of the write out
of the freed blocks breaks the sequential write sequence expected by the
device.

This patch introduces a list of clean and unwritten extent buffers that
have been released in a transaction. Btrfs redirty the buffer so that
btree_write_cache_pages() can send proper bios to the devices.

Besides it clears the entire content of the extent buffer not to confuse
raw block scanners e.g. btrfsck. By clearing the content,
csum_dirty_buffer() complains about bytenr mismatch, so avoid the checking
and checksum using newly introduced buffer flag EXTENT_BUFFER_NO_CHECK.

Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
---
 fs/btrfs/disk-io.c     |  8 ++++++++
 fs/btrfs/extent-tree.c | 12 +++++++++++-
 fs/btrfs/extent_io.c   |  4 ++++
 fs/btrfs/extent_io.h   |  2 ++
 fs/btrfs/transaction.c | 10 ++++++++++
 fs/btrfs/transaction.h |  3 +++
 fs/btrfs/tree-log.c    |  6 ++++++
 fs/btrfs/zoned.c       | 37 +++++++++++++++++++++++++++++++++++++
 fs/btrfs/zoned.h       |  6 ++++++
 9 files changed, 87 insertions(+), 1 deletion(-)

Comments

Josef Bacik Nov. 3, 2020, 2:41 p.m. UTC | #1
On 10/30/20 9:51 AM, Naohiro Aota wrote:
> Tree manipulating operations like merging nodes often release
> once-allocated tree nodes. Btrfs cleans such nodes so that pages in the
> node are not uselessly written out. On ZONED volumes, however, such
> optimization blocks the following IOs as the cancellation of the write out
> of the freed blocks breaks the sequential write sequence expected by the
> device.
> 
> This patch introduces a list of clean and unwritten extent buffers that
> have been released in a transaction. Btrfs redirty the buffer so that
> btree_write_cache_pages() can send proper bios to the devices.
> 
> Besides it clears the entire content of the extent buffer not to confuse
> raw block scanners e.g. btrfsck. By clearing the content,
> csum_dirty_buffer() complains about bytenr mismatch, so avoid the checking
> and checksum using newly introduced buffer flag EXTENT_BUFFER_NO_CHECK.
> 
> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>

This is a lot of work when you could just add

if (btrfs_is_zoned(fs_info))
	return;

to btrfs_clean_tree_block().  The dirty secret is we don't actually unset the 
bits in the transaction io tree because it would require memory allocation 
sometimes, so you don't even need to mess with ->dirty_pages in the first place. 
  The only thing you need is to keep from clearing the EB dirty.  In fact you 
could just do

if (btrfs_is_zoned(fs_info)) {
	memzero_extent_buffer(eb, 0, eb->len);
	set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
}

to btrfs_clean_tree_block() and then in btrfs_free_tree_block() make sure we 
always pin the extent if we're zoned.  Thanks,

Josef
Johannes Thumshirn Nov. 6, 2020, 9:11 a.m. UTC | #2
On 03/11/2020 15:43, Josef Bacik wrote:
> This is a lot of work when you could just add
> 
> if (btrfs_is_zoned(fs_info))
> 	return;
> 
> to btrfs_clean_tree_block().  The dirty secret is we don't actually unset the 
> bits in the transaction io tree because it would require memory allocation 
> sometimes, so you don't even need to mess with ->dirty_pages in the first place. 
>   The only thing you need is to keep from clearing the EB dirty.  In fact you 
> could just do
> 
> if (btrfs_is_zoned(fs_info)) {
> 	memzero_extent_buffer(eb, 0, eb->len);
> 	set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
> }
> 
> to btrfs_clean_tree_block() and then in btrfs_free_tree_block() make sure we 
> always pin the extent if we're zoned.  Thanks,

As much as I'd love the simple solution you described it unfortunately didn't work
in our testing [1]. So unless I did something completely stupid [2] (which always
is an option) I don't think we can go with the easy solution here, unfortunately.

[1]
btrfs/001       [   16.212869] BTRFS error (device nullb1): unable to find ref byte nr 805388288 parent 805388288 root 5  owner 0 offset 0
[   16.214314] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry
[   16.215270] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry                                                                                    
[   16.266987] BTRFS error (device nullb1): unable to find ref byte nr 805388288 parent 805388288 root 5  owner 0 offset 0                                
[   16.268788] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry                                           
[   16.269973] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry
[   16.271210] BTRFS: error (device nullb1) in cleanup_transaction:1904: errno=-2 No such entry                                                  
[   16.297358] BTRFS error (device nullb1): unable to find ref byte nr 805502976 parent 805502976 root 1  owner 0 offset 0                       
[   16.299128] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry   
[   16.300324] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry
[   16.335600] BTRFS error (device nullb1): unable to find ref byte nr 805388288 parent 805388288 root 5  owner 0 offset 0
[   16.337600] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry
[   16.338785] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry                                                                                    
[   16.340026] BTRFS: error (device nullb1) in cleanup_transaction:1904: errno=-2 No such entry            
[   16.366461] BTRFS error (device nullb0): unable to find ref byte nr 805502976 parent 805502976 root 1  owner 0 offset 0
[   16.368304] BTRFS: error (device nullb0) in __btrfs_free_extent:3196: errno=-2 No such entry
[   16.369480] BTRFS: error (device nullb0) in btrfs_run_delayed_refs:2215: errno=-2 No such entry
[   16.370689] BTRFS: error (device nullb0) in cleanup_transaction:1904: errno=-2 No such entry
[   16.392890] BTRFS error (device nullb1): unable to find ref byte nr 805388288 parent 805388288 root 5  owner 0 offset 0
[   16.394531] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry
[   16.395612] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry                                                        
[   16.396648] BTRFS: error (device nullb1) in cleanup_transaction:1904: errno=-2 No such entry
[   16.422315] BTRFS error (device nullb1): unable to find ref byte nr 805502976 parent 805502976 root 1  owner 0 offset 0                
[   16.424147] BTRFS: error (device nullb1) in __btrfs_free_extent:3196: errno=-2 No such entry
[   16.425320] BTRFS: error (device nullb1) in btrfs_run_delayed_refs:2215: errno=-2 No such entry
[   16.426532] BTRFS: error (device nullb1) in cleanup_transaction:1904: errno=-2 No such entry
_check_dmesg: something found in dmesg (see /home/johannes/src/xfstests-dev/results//btrfs/001.dmesg)
- output mismatch (see /home/johannes/src/xfstests-dev/results//btrfs/001.out.bad)
    --- tests/btrfs/001.out     2020-01-07 15:49:53.000000000 +0000
    +++ /home/johannes/src/xfstests-dev/results//btrfs/001.out.bad      2020-11-05 16:17:37.266632915 +0000
    @@ -3,38 +3,29 @@
     List root dir
     foo
     Creating snapshot of root dir
    +ERROR: cannot snapshot '/mnt/scratch': No such file or directory
     Create a snapshot of 'SCRATCH_MNT' in 'SCRATCH_MNT/snap'
     List root dir after snapshot
    -foo
    ...
    (Run 'diff -u /home/johannes/src/xfstests-dev/tests/btrfs/001.out /home/johannes/src/xfstests-dev/results//btrfs/001.out.bad'  to see the entire diff)

[2]
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index e896dd564434..e1bf3b561b45 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1013,7 +1013,11 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
 void btrfs_clean_tree_block(struct extent_buffer *buf)
 {
        struct btrfs_fs_info *fs_info = buf->fs_info;
-       if (btrfs_header_generation(buf) ==
+
+       if (btrfs_is_zoned(fs_info)) {
+               memzero_extent_buffer(buf, 0, buf->len);
+               set_bit(EXTENT_BUFFER_NO_CHECK, &buf->bflags);
+       } else if (btrfs_header_generation(buf) ==
            fs_info->running_transaction->transid) {
                btrfs_assert_tree_locked(buf);
 
@@ -4639,8 +4643,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                     EXTENT_DIRTY);
        btrfs_destroy_pinned_extent(fs_info, &cur_trans->pinned_extents);
 
-       btrfs_free_redirty_list(cur_trans);
-
        cur_trans->state =TRANS_STATE_COMPLETED;
        wake_up(&cur_trans->commit_wait);
 }
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index bfd7f3082037..f9f9c329fa69 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3432,15 +3432,23 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                pin = old_ref_mod >= 0 && new_ref_mod < 0;
        }
 
+       if (btrfs_is_zoned(fs_info)) {
+               struct btrfs_block_group *cache;
+
+               cache = btrfs_lookup_block_group(fs_info, buf->start);
+               pin_down_extent(trans, cache, buf->start, buf->len, 1);
+               btrfs_put_block_group(cache);
+               pin = 0;
+               goto out;
+       }
+
        if (last_ref && btrfs_header_generation(buf) == trans->transid) {
                struct btrfs_block_group *cache;
 
                if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
                        ret = check_ref_cleanup(trans, buf->start);
-                       if (!ret) {
-                               btrfs_redirty_list_add(trans->transaction, buf);
+                       if (!ret)
                                goto out;
-                       }
                }
 
                pin = 0;
@@ -3452,13 +3460,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                        goto out;
                }
 
-               if (btrfs_is_zoned(fs_info)) {
-                       btrfs_redirty_list_add(trans->transaction, buf);
-                       pin_down_extent(trans, cache, buf->start, buf->len, 1);
-                       btrfs_put_block_group(cache);
-                       goto out;
-               }
-
                WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
 
                btrfs_add_free_space(cache, buf->start, buf->len);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index a8561536cd0d..4acc96969959 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -2348,13 +2348,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
                goto scrub_continue;
        }
 
-       /*
-        * At this point, we should have written all the tree blocks
-        * allocated in this transaction. So it's now safe to free the
-        * redirtyied extent buffers.
-        */
-       btrfs_free_redirty_list(cur_trans);
-
        ret = write_all_supers(fs_info, 0);
        /*
         * the super is written, we can safely allow the tree-loggers
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 15f9e8a461ee..e91bdfbb03da 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -2763,8 +2763,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                                free_extent_buffer(next);
                                                return ret;
                                        }
-                                       btrfs_redirty_list_add(
-                                               trans->transaction, next);
                                } else {
                                        if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
                                                clear_extent_buffer_dirty(next);
@@ -3313,8 +3311,6 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
                          EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
        extent_io_tree_release(&log->log_csum_range);
 
-       if (trans && log->node)
-               btrfs_redirty_list_add(trans->transaction, log->node);
        btrfs_put_root(log);
 }
 
diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index 5b61500a0aa9..3140c39d3728 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -42,9 +42,6 @@ int btrfs_reset_device_zone(struct btrfs_device *device, u64 physical,
 int btrfs_ensure_empty_zones(struct btrfs_device *device, u64 start, u64 size);
 int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache);
 void btrfs_calc_zone_unusable(struct btrfs_block_group *cache);
-void btrfs_redirty_list_add(struct btrfs_transaction *trans,
-                           struct extent_buffer *eb);
-void btrfs_free_redirty_list(struct btrfs_transaction *trans);
 void btrfs_record_physical_zoned(struct inode *inode, u64 file_offset,
                                 struct bio *bio);
 void btrfs_rewrite_logical_zoned(struct btrfs_ordered_extent *ordered);
@@ -137,10 +134,6 @@ static inline int btrfs_load_block_group_zone_info(
 
 static inline void btrfs_calc_zone_unusable(struct btrfs_block_group *cache) { }
 
-static inline void btrfs_redirty_list_add(struct btrfs_transaction *trans,
-                                         struct extent_buffer *eb) { }
-static inline void btrfs_free_redirty_list(struct btrfs_transaction *trans) { }
-
 static inline void btrfs_record_physical_zoned(struct inode *inode,
                                               u64 file_offset, struct bio *bio)
 {
Josef Bacik Nov. 6, 2020, 3:01 p.m. UTC | #3
On 11/6/20 4:11 AM, Johannes Thumshirn wrote:
> On 03/11/2020 15:43, Josef Bacik wrote:
>> This is a lot of work when you could just add
>>
>> if (btrfs_is_zoned(fs_info))
>> 	return;
>>
>> to btrfs_clean_tree_block().  The dirty secret is we don't actually unset the
>> bits in the transaction io tree because it would require memory allocation
>> sometimes, so you don't even need to mess with ->dirty_pages in the first place.
>>    The only thing you need is to keep from clearing the EB dirty.  In fact you
>> could just do
>>
>> if (btrfs_is_zoned(fs_info)) {
>> 	memzero_extent_buffer(eb, 0, eb->len);
>> 	set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
>> }
>>
>> to btrfs_clean_tree_block() and then in btrfs_free_tree_block() make sure we
>> always pin the extent if we're zoned.  Thanks,
> 
> As much as I'd love the simple solution you described it unfortunately didn't work
> in our testing [1]. So unless I did something completely stupid [2] (which always
> is an option) I don't think we can go with the easy solution here, unfortunately.
> 

Actually it's because we're calling btrfs_clean_tree_block() in 
btrfs_init_new_buffer(), so any new block is now getting marked as 
BUFFER_NO_CHECk, hence everything blowing up.

I think first you push btrfs_clean_tree_block() into btrfs_free_tree_block() and 
kill all other callers, because we're just marking it no longer dirty.  In fact 
I'd rename it as btrfs_mark_extent_buffer_clean() or something like that.  Then 
your patch should work just fine.  Thanks,

Josef
diff mbox series

Patch

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index fd8b970ee92c..9750b4e6d538 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -462,6 +462,12 @@  static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct page *page)
 		return 0;
 
 	found_start = btrfs_header_bytenr(eb);
+
+	if (test_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags)) {
+		WARN_ON(found_start != 0);
+		return 0;
+	}
+
 	/*
 	 * Please do not consolidate these warnings into a single if.
 	 * It is useful to know what went wrong.
@@ -4616,6 +4622,8 @@  void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
 				     EXTENT_DIRTY);
 	btrfs_destroy_pinned_extent(fs_info, &cur_trans->pinned_extents);
 
+	btrfs_free_redirty_list(cur_trans);
+
 	cur_trans->state =TRANS_STATE_COMPLETED;
 	wake_up(&cur_trans->commit_wait);
 }
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c134746d7417..57454ef4c91e 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3421,8 +3421,10 @@  void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
 
 		if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
 			ret = check_ref_cleanup(trans, buf->start);
-			if (!ret)
+			if (!ret) {
+				btrfs_redirty_list_add(trans->transaction, buf);
 				goto out;
+			}
 		}
 
 		pin = 0;
@@ -3434,6 +3436,13 @@  void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
 			goto out;
 		}
 
+		if (btrfs_is_zoned(fs_info)) {
+			btrfs_redirty_list_add(trans->transaction, buf);
+			pin_down_extent(trans, cache, buf->start, buf->len, 1);
+			btrfs_put_block_group(cache);
+			goto out;
+		}
+
 		WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
 
 		btrfs_add_free_space(cache, buf->start, buf->len);
@@ -4770,6 +4779,7 @@  btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	__btrfs_tree_lock(buf, nest);
 	btrfs_clean_tree_block(buf);
 	clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);
+	clear_bit(EXTENT_BUFFER_NO_CHECK, &buf->bflags);
 
 	btrfs_set_lock_blocking_write(buf);
 	set_extent_buffer_uptodate(buf);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 60f5f68d892d..e91c504fe973 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -24,6 +24,7 @@ 
 #include "rcu-string.h"
 #include "backref.h"
 #include "disk-io.h"
+#include "zoned.h"
 
 static struct kmem_cache *extent_state_cache;
 static struct kmem_cache *extent_buffer_cache;
@@ -4959,6 +4960,7 @@  __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
 
 	btrfs_leak_debug_add(&fs_info->eb_leak_lock, &eb->leak_list,
 			     &fs_info->allocated_ebs);
+	INIT_LIST_HEAD(&eb->release_list);
 
 	spin_lock_init(&eb->refs_lock);
 	atomic_set(&eb->refs, 1);
@@ -5744,6 +5746,8 @@  void write_extent_buffer(const struct extent_buffer *eb, const void *srcv,
 	char *src = (char *)srcv;
 	unsigned long i = start >> PAGE_SHIFT;
 
+	WARN_ON(test_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags));
+
 	if (check_eb_range(eb, start, len))
 		return;
 
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index f39d02e7f7ef..5f2ccfd0205e 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -30,6 +30,7 @@  enum {
 	EXTENT_BUFFER_IN_TREE,
 	/* write IO error */
 	EXTENT_BUFFER_WRITE_ERR,
+	EXTENT_BUFFER_NO_CHECK,
 };
 
 /* these are flags for __process_pages_contig */
@@ -107,6 +108,7 @@  struct extent_buffer {
 	 */
 	wait_queue_head_t read_lock_wq;
 	struct page *pages[INLINE_EXTENT_BUFFER_PAGES];
+	struct list_head release_list;
 #ifdef CONFIG_BTRFS_DEBUG
 	int spinning_writers;
 	atomic_t spinning_readers;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 52ada47aff50..5c561cdcce42 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -22,6 +22,7 @@ 
 #include "qgroup.h"
 #include "block-group.h"
 #include "space-info.h"
+#include "zoned.h"
 
 #define BTRFS_ROOT_TRANS_TAG 0
 
@@ -336,6 +337,8 @@  static noinline int join_transaction(struct btrfs_fs_info *fs_info,
 	spin_lock_init(&cur_trans->dirty_bgs_lock);
 	INIT_LIST_HEAD(&cur_trans->deleted_bgs);
 	spin_lock_init(&cur_trans->dropped_roots_lock);
+	INIT_LIST_HEAD(&cur_trans->releasing_ebs);
+	spin_lock_init(&cur_trans->releasing_ebs_lock);
 	list_add_tail(&cur_trans->list, &fs_info->trans_list);
 	extent_io_tree_init(fs_info, &cur_trans->dirty_pages,
 			IO_TREE_TRANS_DIRTY_PAGES, fs_info->btree_inode);
@@ -2345,6 +2348,13 @@  int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 		goto scrub_continue;
 	}
 
+	/*
+	 * At this point, we should have written the all tree blocks
+	 * allocated in this transaction. So it's now safe to free the
+	 * redirtyied extent buffers.
+	 */
+	btrfs_free_redirty_list(cur_trans);
+
 	ret = write_all_supers(fs_info, 0);
 	/*
 	 * the super is written, we can safely allow the tree-loggers
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 858d9153a1cd..380e0aaa15b3 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -92,6 +92,9 @@  struct btrfs_transaction {
 	 */
 	atomic_t pending_ordered;
 	wait_queue_head_t pending_wait;
+
+	spinlock_t releasing_ebs_lock;
+	struct list_head releasing_ebs;
 };
 
 #define __TRANS_FREEZABLE	(1U << 0)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 56cbc1706b6f..5f585cf57383 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -20,6 +20,7 @@ 
 #include "inode-map.h"
 #include "block-group.h"
 #include "space-info.h"
+#include "zoned.h"
 
 /* magic values for the inode_only field in btrfs_log_inode:
  *
@@ -2742,6 +2743,8 @@  static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
 						free_extent_buffer(next);
 						return ret;
 					}
+					btrfs_redirty_list_add(
+						trans->transaction, next);
 				} else {
 					if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
 						clear_extent_buffer_dirty(next);
@@ -3277,6 +3280,9 @@  static void free_log_tree(struct btrfs_trans_handle *trans,
 	clear_extent_bits(&log->dirty_log_pages, 0, (u64)-1,
 			  EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
 	extent_io_tree_release(&log->log_csum_range);
+
+	if (trans && log->node)
+		btrfs_redirty_list_add(trans->transaction, log->node);
 	btrfs_put_root(log);
 }
 
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index d94a2c363a47..b45ca33282d9 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -10,6 +10,7 @@ 
 #include "rcu-string.h"
 #include "disk-io.h"
 #include "block-group.h"
+#include "transaction.h"
 
 /* Maximum number of zones to report per blkdev_report_zones() call */
 #define BTRFS_REPORT_NR_ZONES   4096
@@ -1015,3 +1016,39 @@  void btrfs_calc_zone_unusable(struct btrfs_block_group *cache)
 	 */
 	btrfs_free_excluded_extents(cache);
 }
+
+void btrfs_redirty_list_add(struct btrfs_transaction *trans,
+			    struct extent_buffer *eb)
+{
+	struct btrfs_fs_info *fs_info = eb->fs_info;
+
+	if (!btrfs_is_zoned(fs_info) ||
+	    btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN) ||
+	    !list_empty(&eb->release_list))
+		return;
+
+	set_extent_buffer_dirty(eb);
+	set_extent_bits_nowait(&trans->dirty_pages, eb->start,
+			       eb->start + eb->len - 1, EXTENT_DIRTY);
+	memzero_extent_buffer(eb, 0, eb->len);
+	set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
+
+	spin_lock(&trans->releasing_ebs_lock);
+	list_add_tail(&eb->release_list, &trans->releasing_ebs);
+	spin_unlock(&trans->releasing_ebs_lock);
+	atomic_inc(&eb->refs);
+}
+
+void btrfs_free_redirty_list(struct btrfs_transaction *trans)
+{
+	spin_lock(&trans->releasing_ebs_lock);
+	while (!list_empty(&trans->releasing_ebs)) {
+		struct extent_buffer *eb;
+
+		eb = list_first_entry(&trans->releasing_ebs,
+				      struct extent_buffer, release_list);
+		list_del_init(&eb->release_list);
+		free_extent_buffer(eb);
+	}
+	spin_unlock(&trans->releasing_ebs_lock);
+}
diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index d13bc6d70ea4..845623932fa5 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -41,6 +41,9 @@  int btrfs_reset_device_zone(struct btrfs_device *device, u64 physical,
 int btrfs_ensure_empty_zones(struct btrfs_device *device, u64 start, u64 size);
 int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache);
 void btrfs_calc_zone_unusable(struct btrfs_block_group *cache);
+void btrfs_redirty_list_add(struct btrfs_transaction *trans,
+			    struct extent_buffer *eb);
+void btrfs_free_redirty_list(struct btrfs_transaction *trans);
 #else /* CONFIG_BLK_DEV_ZONED */
 static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
 				     struct blk_zone *zone)
@@ -107,6 +110,9 @@  static inline int btrfs_load_block_group_zone_info(
 	return 0;
 }
 static inline void btrfs_calc_zone_unusable(struct btrfs_block_group *cache) { }
+static inline void btrfs_redirty_list_add(struct btrfs_transaction *trans,
+					  struct extent_buffer *eb) { }
+static inline void btrfs_free_redirty_list(struct btrfs_transaction *trans) { }
 #endif
 
 static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)