diff --git a/fs/btrfs/extent-io-tree.h b/fs/btrfs/extent-io-tree.h
index 5c0a66146f05..12673bd50378 100644
--- a/fs/btrfs/extent-io-tree.h
+++ b/fs/btrfs/extent-io-tree.h
@@ -26,6 +26,9 @@ struct io_failure_record;
 /* For subpage btree io tree, indicates there is an in-tree extent buffer */
 #define EXTENT_HAS_TREE_BLOCK	(1U << 15)
 
+/* For subpage btree io tree, indicates the range is under writeback */
+#define EXTENT_WRITEBACK	(1U << 16)
+
 #define EXTENT_DO_ACCOUNTING    (EXTENT_CLEAR_META_RESV | \
 				 EXTENT_CLEAR_DATA_RESV)
 #define EXTENT_CTLBITS		(EXTENT_DO_ACCOUNTING)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index f80ba4c13fe6..736bc33a0e64 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3124,6 +3124,7 @@ static int submit_extent_page(unsigned int opf,
 	ASSERT(bio_ret);
 
 	if (*bio_ret) {
+		bool force_merge = false;
 		bool contig;
 		bool can_merge = true;
 
@@ -3149,6 +3150,7 @@ static int submit_extent_page(unsigned int opf,
 		if (prev_bio_flags != bio_flags || !contig || !can_merge ||
 		    force_bio_submit ||
 		    bio_add_page(bio, page, io_size, pg_offset) < io_size) {
+			ASSERT(!force_merge);
 			ret = submit_one_bio(bio, mirror_num, prev_bio_flags);
 			if (ret < 0) {
 				*bio_ret = NULL;
@@ -4007,6 +4009,76 @@ static void end_bio_extent_buffer_writepage(struct bio *bio)
 	bio_put(bio);
 }
 
+/*
+ * Unlike the work in write_one_eb(), we won't unlock the page even we
+ * succeeded submitting the extent buffer.
+ * It's callers responsibility to unlock the page after all extent
+ *
+ * Caller should still call write_one_eb() other than this function directly.
+ * As write_one_eb() has extra prepration before submitting the extent buffer.
+ */
+static int write_one_subpage_eb(struct extent_buffer *eb,
+				      struct writeback_control *wbc,
+				      struct extent_page_data *epd)
+{
+	struct btrfs_fs_info *fs_info = eb->fs_info;
+	struct extent_state *cached = NULL;
+	struct extent_io_tree *io_tree = info_to_btree_io_tree(fs_info);
+	struct page *page = eb->pages[0];
+	u64 page_start = page_offset(page);
+	u64 page_end = page_start + PAGE_SIZE - 1;
+	unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META;
+	bool no_dirty_ebs = false;
+	int ret;
+
+	ASSERT(PageLocked(page));
+
+	/* Convert the EXTENT_DIRTY to EXTENT_WRITEBACK for this eb */
+	ret = convert_extent_bit(io_tree, eb->start, eb->start + eb->len - 1,
+				 EXTENT_WRITEBACK, EXTENT_DIRTY, &cached);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Only clear page dirty if there is no dirty extent buffer in the
+	 * page range
+	 */
+	if (!test_range_bit(io_tree, page_start, page_end, EXTENT_DIRTY, 0,
+			    cached)) {
+		clear_page_dirty_for_io(page);
+		no_dirty_ebs = true;
+	}
+	/* Any extent buffer writeback will mark the full page writeback */
+	set_page_writeback(page);
+
+	ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc, page,
+			eb->start, eb->len, eb->start - page_offset(page),
+			&epd->bio, end_bio_extent_buffer_writepage, 0, 0, 0,
+			false);
+	if (ret) {
+		clear_extent_bit(io_tree, eb->start, eb->start + eb->len - 1,
+				 EXTENT_WRITEBACK, 0, 0, &cached);
+		set_btree_ioerr(page, eb);
+		if (PageWriteback(page) &&
+		    !test_range_bit(io_tree, page_start, page_end,
+				    EXTENT_WRITEBACK, 0, cached))
+			end_page_writeback(page);
+
+		if (atomic_dec_and_test(&eb->io_pages))
+			end_extent_buffer_writeback(eb);
+		free_extent_state(cached);
+		return -EIO;
+	}
+	free_extent_state(cached);
+	/*
+	 * Submission finishes without problem, if no eb is dirty anymore, we
+	 * have submitted a page.
+	 * Update the nr_written in wbc.
+	 */
+	if (no_dirty_ebs)
+		update_nr_written(wbc, 1);
+	return ret;
+}
+
 static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 			struct writeback_control *wbc,
 			struct extent_page_data *epd)
@@ -4038,6 +4110,9 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 		memzero_extent_buffer(eb, start, end - start);
 	}
 
+	if (btrfs_is_subpage(eb->fs_info))
+		return write_one_subpage_eb(eb, wbc, epd);
+
 	for (i = 0; i < num_pages; i++) {
 		struct page *p = eb->pages[i];
 
