diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 76ee1452c57b..954e772f18e8 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -231,6 +231,9 @@ struct btrfs_inode {
 
 	struct rw_semaphore i_mmap_lock;
 	struct inode vfs_inode;
+
+	/* Protects relocation from page writeback on a zoned FS */
+	struct mutex relocation_lock;
 };
 
 static inline u32 btrfs_inode_sectorsize(const struct btrfs_inode *inode)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 96de6e70d06c..59c79eb51612 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -5005,7 +5005,9 @@ static int extent_write_cache_pages(struct address_space *mapping,
 				continue;
 			}
 
+			btrfs_zoned_relocation_io_lock(BTRFS_I(inode));
 			ret = __extent_writepage(page, wbc, epd);
+			btrfs_zoned_relocation_io_unlock(BTRFS_I(inode));
 			if (ret < 0) {
 				done = 1;
 				break;
@@ -5056,7 +5058,9 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 		.sync_io = wbc->sync_mode == WB_SYNC_ALL,
 	};
 
+	btrfs_zoned_relocation_io_lock(BTRFS_I(page->mapping->host));
 	ret = __extent_writepage(page, wbc, &epd);
+	btrfs_zoned_relocation_io_unlock(BTRFS_I(page->mapping->host));
 	ASSERT(ret <= 0);
 	if (ret < 0) {
 		end_write_bio(&epd, ret);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index afe9dcda860b..8e8e56f79a86 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9120,6 +9120,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
 	INIT_LIST_HEAD(&ei->delayed_iput);
 	RB_CLEAR_NODE(&ei->rb_node);
 	init_rwsem(&ei->i_mmap_lock);
+	mutex_init(&ei->relocation_lock);
 
 	return inode;
 }
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 914d403b4415..8630d45e0fca 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -25,6 +25,7 @@
 #include "backref.h"
 #include "misc.h"
 #include "subpage.h"
+#include "zoned.h"
 
 /*
  * Relocation overview
@@ -3069,8 +3070,6 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra,
 	unlock_page(page);
 	put_page(page);
 
-	balance_dirty_pages_ratelimited(inode->i_mapping);
-	btrfs_throttle(fs_info);
 	if (btrfs_should_cancel_balance(fs_info))
 		ret = -ECANCELED;
 	return ret;
@@ -3111,9 +3110,14 @@ static int relocate_file_extent_cluster(struct inode *inode,
 		goto out;
 
 	last_index = (cluster->end - offset) >> PAGE_SHIFT;
+	btrfs_zoned_relocation_io_lock(BTRFS_I(inode));
 	for (index = (cluster->start - offset) >> PAGE_SHIFT;
-	     index <= last_index && !ret; index++)
+	     index <= last_index && !ret; index++) {
 		ret = relocate_one_page(inode, ra, cluster, &cluster_nr, index);
+	}
+	btrfs_zoned_relocation_io_unlock(BTRFS_I(inode));
+	balance_dirty_pages_ratelimited(inode->i_mapping);
+	btrfs_throttle(fs_info);
 	if (btrfs_is_zoned(fs_info) && !ret)
 		ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
 	if (ret == 0)
diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index 4b299705bb12..70d2d65bf5cc 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -8,6 +8,7 @@
 #include "volumes.h"
 #include "disk-io.h"
 #include "block-group.h"
+#include "btrfs_inode.h"
 
 /*
  * Block groups with more than this value (percents) of unusable space will be
@@ -304,6 +305,32 @@ static inline void btrfs_zoned_meta_io_unlock(struct btrfs_fs_info *fs_info)
 	mutex_unlock(&fs_info->zoned_meta_io_lock);
 }
 
+static inline void btrfs_zoned_relocation_io_lock(struct btrfs_inode *inode)
+{
+	struct btrfs_root *root = inode->root;
+
+	if (!btrfs_is_zoned(root->fs_info))
+		return;
+
+	if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID)
+		return;
+
+	mutex_lock(&inode->relocation_lock);
+}
+
+static inline void btrfs_zoned_relocation_io_unlock(struct btrfs_inode *inode)
+{
+	struct btrfs_root *root = inode->root;
+
+	if (!btrfs_is_zoned(root->fs_info))
+		return;
+
+	if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID)
+		return;
+
+	mutex_unlock(&inode->relocation_lock);
+}
+
 static inline void btrfs_clear_treelog_bg(struct btrfs_block_group *bg)
 {
 	struct btrfs_fs_info *fs_info = bg->fs_info;
