Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[deliverable/linux.git] / fs / btrfs / ordered-data.c
index ab2a3c0c540f52a2d125fc14eecb17d8ff9f1069..e5ed56729607a82246cac22a229d105efa562509 100644 (file)
@@ -211,6 +211,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        init_waitqueue_head(&entry->wait);
        INIT_LIST_HEAD(&entry->list);
        INIT_LIST_HEAD(&entry->root_extent_list);
+       INIT_LIST_HEAD(&entry->work_list);
+       init_completion(&entry->completion);
 
        trace_btrfs_ordered_extent_add(inode, entry);
 
@@ -464,18 +466,28 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        wake_up(&entry->wait);
 }
 
+static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
+{
+       struct btrfs_ordered_extent *ordered;
+
+       ordered = container_of(work, struct btrfs_ordered_extent, flush_work);
+       btrfs_start_ordered_extent(ordered->inode, ordered, 1);
+       complete(&ordered->completion);
+}
+
 /*
  * wait for all the ordered extents in a root.  This is done when balancing
  * space between drives.
  */
 void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
 {
-       struct list_head splice;
+       struct list_head splice, works;
        struct list_head *cur;
-       struct btrfs_ordered_extent *ordered;
+       struct btrfs_ordered_extent *ordered, *next;
        struct inode *inode;
 
        INIT_LIST_HEAD(&splice);
+       INIT_LIST_HEAD(&works);
 
        spin_lock(&root->fs_info->ordered_extent_lock);
        list_splice_init(&root->fs_info->ordered_extents, &splice);
@@ -494,19 +506,32 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
                spin_unlock(&root->fs_info->ordered_extent_lock);
 
                if (inode) {
-                       btrfs_start_ordered_extent(inode, ordered, 1);
-                       btrfs_put_ordered_extent(ordered);
-                       if (delay_iput)
-                               btrfs_add_delayed_iput(inode);
-                       else
-                               iput(inode);
+                       ordered->flush_work.func = btrfs_run_ordered_extent_work;
+                       list_add_tail(&ordered->work_list, &works);
+                       btrfs_queue_worker(&root->fs_info->flush_workers,
+                                          &ordered->flush_work);
                } else {
                        btrfs_put_ordered_extent(ordered);
                }
 
+               cond_resched();
                spin_lock(&root->fs_info->ordered_extent_lock);
        }
        spin_unlock(&root->fs_info->ordered_extent_lock);
+
+       list_for_each_entry_safe(ordered, next, &works, work_list) {
+               list_del_init(&ordered->work_list);
+               wait_for_completion(&ordered->completion);
+
+               inode = ordered->inode;
+               btrfs_put_ordered_extent(ordered);
+               if (delay_iput)
+                       btrfs_add_delayed_iput(inode);
+               else
+                       iput(inode);
+
+               cond_resched();
+       }
 }
 
 /*
@@ -628,7 +653,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
        u64 end;
        u64 orig_end;
        struct btrfs_ordered_extent *ordered;
-       int found;
 
        if (start + len < start) {
                orig_end = INT_LIMIT(loff_t);
@@ -664,7 +688,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
        filemap_fdatawait_range(inode->i_mapping, start, orig_end);
 
        end = orig_end;
-       found = 0;
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, end);
                if (!ordered)
@@ -677,7 +700,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
                        btrfs_put_ordered_extent(ordered);
                        break;
                }
-               found++;
                btrfs_start_ordered_extent(inode, ordered, 1);
                end = ordered->file_offset;
                btrfs_put_ordered_extent(ordered);
@@ -814,9 +836,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
         * if the disk i_size is already at the inode->i_size, or
         * this ordered extent is inside the disk i_size, we're done
         */
-       if (disk_i_size == i_size || offset <= disk_i_size) {
+       if (disk_i_size == i_size)
+               goto out;
+
+       /*
+        * We still need to update disk_i_size if outstanding_isize is greater
+        * than disk_i_size.
+        */
+       if (offset <= disk_i_size &&
+           (!ordered || ordered->outstanding_isize <= disk_i_size))
                goto out;
-       }
 
        /*
         * walk backward from this ordered extent to disk_i_size.
@@ -848,7 +877,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                        break;
                if (test->file_offset >= i_size)
                        break;
-               if (test->file_offset >= disk_i_size) {
+               if (entry_end(test) > disk_i_size) {
                        /*
                         * we don't update disk_i_size now, so record this
                         * undealt i_size. Or we will not know the real
This page took 0.028823 seconds and 5 git commands to generate.