* some fairly slow code that needs optimization. This walks the list
  * of all the inodes with pending delalloc and forces them to disk.
  */
-static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot,
+static int start_delalloc_inodes(struct btrfs_root *root,
+                                struct writeback_control *wbc, bool snapshot,
                                 bool in_reclaim_context)
 {
        struct btrfs_inode *binode;
        struct list_head works;
        struct list_head splice;
        int ret = 0;
+       bool full_flush = wbc->nr_to_write == LONG_MAX;
 
        INIT_LIST_HEAD(&works);
        INIT_LIST_HEAD(&splice);
                if (snapshot)
                        set_bit(BTRFS_INODE_SNAPSHOT_FLUSH,
                                &binode->runtime_flags);
-               work = btrfs_alloc_delalloc_work(inode);
-               if (!work) {
-                       iput(inode);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               list_add_tail(&work->list, &works);
-               btrfs_queue_work(root->fs_info->flush_workers,
-                                &work->work);
-               if (*nr != U64_MAX) {
-                       (*nr)--;
-                       if (*nr == 0)
+               if (full_flush) {
+                       work = btrfs_alloc_delalloc_work(inode);
+                       if (!work) {
+                               iput(inode);
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       list_add_tail(&work->list, &works);
+                       btrfs_queue_work(root->fs_info->flush_workers,
+                                        &work->work);
+               } else {
+                       ret = sync_inode(inode, wbc);
+                       if (!ret &&
+                           test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+                                    &BTRFS_I(inode)->runtime_flags))
+                               ret = sync_inode(inode, wbc);
+                       btrfs_add_delayed_iput(inode);
+                       if (ret || wbc->nr_to_write <= 0)
                                goto out;
                }
                cond_resched();
 
 int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
 {
+       struct writeback_control wbc = {
+               .nr_to_write = LONG_MAX,
+               .sync_mode = WB_SYNC_NONE,
+               .range_start = 0,
+               .range_end = LLONG_MAX,
+       };
        struct btrfs_fs_info *fs_info = root->fs_info;
-       u64 nr = U64_MAX;
 
        if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                return -EROFS;
 
-       return start_delalloc_inodes(root, &nr, true, false);
+       return start_delalloc_inodes(root, &wbc, true, false);
 }
 
 int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
                               bool in_reclaim_context)
 {
+       struct writeback_control wbc = {
+               .nr_to_write = (nr == U64_MAX) ? LONG_MAX : (unsigned long)nr,
+               .sync_mode = WB_SYNC_NONE,
+               .range_start = 0,
+               .range_end = LLONG_MAX,
+       };
        struct btrfs_root *root;
        struct list_head splice;
        int ret;
        spin_lock(&fs_info->delalloc_root_lock);
        list_splice_init(&fs_info->delalloc_roots, &splice);
        while (!list_empty(&splice) && nr) {
+               /*
+                * Reset nr_to_write here so we know that we're doing a full
+                * flush.
+                */
+               if (nr == U64_MAX)
+                       wbc.nr_to_write = LONG_MAX;
+
                root = list_first_entry(&splice, struct btrfs_root,
                                        delalloc_root);
                root = btrfs_grab_root(root);
                               &fs_info->delalloc_roots);
                spin_unlock(&fs_info->delalloc_root_lock);
 
-               ret = start_delalloc_inodes(root, &nr, false, in_reclaim_context);
+               ret = start_delalloc_inodes(root, &wbc, false, in_reclaim_context);
                btrfs_put_root(root);
-               if (ret < 0)
+               if (ret < 0 || wbc.nr_to_write <= 0)
                        goto out;
                spin_lock(&fs_info->delalloc_root_lock);
        }