if (!*ret)
                return -ENOMEM;
        spin_lock_init(&(*ret)->lock);
-       if (type == BTRFS_SUBPAGE_METADATA)
+       if (type == BTRFS_SUBPAGE_METADATA) {
                atomic_set(&(*ret)->eb_refs, 0);
-       else
+       } else {
                atomic_set(&(*ret)->readers, 0);
+               atomic_set(&(*ret)->writers, 0);
+       }
        return 0;
 }
 
                unlock_page(page);
 }
 
+static void btrfs_subpage_clamp_range(struct page *page, u64 *start, u32 *len)
+{
+       u64 orig_start = *start;
+       u32 orig_len = *len;
+
+       *start = max_t(u64, page_offset(page), orig_start);
+       *len = min_t(u64, page_offset(page) + PAGE_SIZE,
+                    orig_start + orig_len) - *start;
+}
+
+void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const int nbits = (len >> fs_info->sectorsize_bits);
+       int ret;
+
+       btrfs_subpage_assert(fs_info, page, start, len);
+
+       ASSERT(atomic_read(&subpage->readers) == 0);
+       ret = atomic_add_return(nbits, &subpage->writers);
+       ASSERT(ret == nbits);
+}
+
+bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const int nbits = (len >> fs_info->sectorsize_bits);
+
+       btrfs_subpage_assert(fs_info, page, start, len);
+
+       ASSERT(atomic_read(&subpage->writers) >= nbits);
+       return atomic_sub_and_test(nbits, &subpage->writers);
+}
+
+/*
+ * Lock a page for delalloc page writeback.
+ *
+ * Return -EAGAIN if the page is not properly initialized.
+ * Return 0 with the page locked, and writer counter updated.
+ *
+ * Even with 0 returned, the page still need extra check to make sure
+ * it's really the correct page, as the caller is using
+ * find_get_pages_contig(), which can race with page invalidating.
+ */
+int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {
+               lock_page(page);
+               return 0;
+       }
+       lock_page(page);
+       if (!PagePrivate(page) || !page->private) {
+               unlock_page(page);
+               return -EAGAIN;
+       }
+       btrfs_subpage_clamp_range(page, &start, &len);
+       btrfs_subpage_start_writer(fs_info, page, start, len);
+       return 0;
+}
+
+void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)
+               return unlock_page(page);
+       btrfs_subpage_clamp_range(page, &start, &len);
+       if (btrfs_subpage_end_and_test_writer(fs_info, page, start, len))
+               unlock_page(page);
+}
+
 /*
  * Convert the [start, start + len) range into a u16 bitmap
  *
        spin_unlock_irqrestore(&subpage->lock, flags);
 }
 
-static void btrfs_subpage_clamp_range(struct page *page, u64 *start, u32 *len)
-{
-       u64 orig_start = *start;
-       u32 orig_len = *len;
-
-       *start = max_t(u64, page_offset(page), orig_start);
-       *len = min_t(u64, page_offset(page) + PAGE_SIZE,
-                    orig_start + orig_len) - *start;
-}
-
 /*
  * Unlike set/clear which is dependent on each page status, for test all bits
  * are tested in the same way.
 
                /* Structures only used by data */
                struct {
                        atomic_t readers;
+                       atomic_t writers;
                };
        };
 };
 void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
                struct page *page, u64 start, u32 len);
 
+void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+
 /*
  * Template for subpage related operations.
  *