@@ -4324,6 +4324,67 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
return ret;
}
+/*
+ * A helper to submit one subpage btree page.
+ *
+ * The main difference between submit_btree_page() is:
+ * - Page locking sequence
+ * Page are locked first, then lock extent buffers
+ *
+ * - Flush write bio
+ * We only flush bio if we may be unable to fit current extent buffers into
+ * current bio.
+ *
+ * Return >=0 for the number of submitted extent buffers.
+ * Return <0 for fatal error.
+ */
+static int submit_btree_subpage(struct page *page,
+ struct writeback_control *wbc,
+ struct extent_page_data *epd)
+{
+ struct btrfs_fs_info *fs_info = page_to_fs_info(page);
+ int submitted = 0;
+ u64 page_start = page_offset(page);
+ u64 page_end = page_start + PAGE_SIZE - 1;
+ u64 cur = page_start;
+ int ret;
+
+ /* Lock and write each extent buffers in the range */
+ while (cur <= page_end) {
+ struct extent_buffer *eb;
+
+ ret = btrfs_find_first_subpage_eb(fs_info, &eb, cur, page_end,
+ EXTENT_DIRTY);
+ if (ret > 0)
+ break;
+ ret = atomic_inc_not_zero(&eb->refs);
+ if (!ret)
+ continue;
+
+ cur = eb->start + eb->len;
+ ret = lock_extent_buffer_for_io(eb, epd);
+ if (ret == 0) {
+ free_extent_buffer(eb);
+ continue;
+ }
+ if (ret < 0) {
+ free_extent_buffer(eb);
+ goto cleanup;
+ }
+ ret = write_one_eb(eb, wbc, epd);
+ free_extent_buffer(eb);
+ if (ret < 0)
+ goto cleanup;
+ submitted++;
+ }
+ return submitted;
+
+cleanup:
+ /* We hit error, end bio for the submitted extent buffers */
+ end_write_bio(epd, ret);
+ return ret;
+}
+
/*
* A helper to submit a btree page.
*
@@ -4349,6 +4410,9 @@ static int submit_btree_page(struct page *page, struct writeback_control *wbc,
if (!PagePrivate(page))
return 0;
+ if (btrfs_is_subpage(page_to_fs_info(page)))
+ return submit_btree_subpage(page, wbc, epd);
+
spin_lock(&mapping->private_lock);
if (!PagePrivate(page)) {
spin_unlock(&mapping->private_lock);
The new function, submit_btree_subpage(), will submit all the dirty extent buffers in the page. The major difference between submit_btree_page() is: - Page locking sequence Now we lock page first then lock extent buffers, thus we don't need to unlock the page just after writting one extent buffer. The page get unlocked after we have submitted all extent buffers. - Bio submission Since one extent buffer is ensured to be contained into one page, we call submit_extent_page() directly. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/extent_io.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)