Btrfs: don't flush all delalloc inodes when we doesn't get s_umount lock
authorMiao Xie <miaox@cn.fujitsu.com>
Thu, 6 Mar 2014 05:55:01 +0000 (13:55 +0800)
committerJosef Bacik <jbacik@fb.com>
Mon, 10 Mar 2014 19:17:27 +0000 (15:17 -0400)
We needn't flush all delalloc inodes when we doesn't get s_umount lock,
or we would make the tasks wait for a long time.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
fs/btrfs/ctree.h
fs/btrfs/dev-replace.c
fs/btrfs/extent-tree.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/transaction.c

index 374bb2f8ccd9bd1a1307d558ce1f3a7201e4cc89..5a800986f416c3df034231f14a36e68551a12451 100644 (file)
@@ -3740,7 +3740,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               u32 min_type);
 
 int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
-int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput);
+int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
+                              int nr);
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
index ec1c3f3a775de28e5a06a54d73289f3d201ce533..9f2290509acaeb105e3097831be8401b9a659dbe 100644 (file)
@@ -491,7 +491,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
         * flush all outstanding I/O and inode extent mappings before the
         * copy operation is declared as being finished
         */
-       ret = btrfs_start_delalloc_roots(root->fs_info, 0);
+       ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1);
        if (ret) {
                mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
                return ret;
index 5c0c5457268a3eca66ab3feeb31ca7f5c551ff5b..c6b6a6e3e735ce73bf06a735a9ee85533d94e4bf 100644 (file)
@@ -3971,7 +3971,7 @@ static int can_overcommit(struct btrfs_root *root,
 }
 
 static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
-                                        unsigned long nr_pages)
+                                        unsigned long nr_pages, int nr_items)
 {
        struct super_block *sb = root->fs_info->sb;
 
@@ -3986,9 +3986,9 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
                 * the filesystem is readonly(all dirty pages are written to
                 * the disk).
                 */
-               btrfs_start_delalloc_roots(root->fs_info, 0);
+               btrfs_start_delalloc_roots(root->fs_info, 0, nr_items);
                if (!current->journal_info)
-                       btrfs_wait_ordered_roots(root->fs_info, -1);
+                       btrfs_wait_ordered_roots(root->fs_info, nr_items);
        }
 }
 
@@ -4045,7 +4045,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
        while (delalloc_bytes && loops < 3) {
                max_reclaim = min(delalloc_bytes, to_reclaim);
                nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
-               btrfs_writeback_inodes_sb_nr(root, nr_pages);
+               btrfs_writeback_inodes_sb_nr(root, nr_pages, items);
                /*
                 * We need to wait for the async pages to actually start before
                 * we do anything.
index f5e623371bf387408820dbadec3ed9d5388cc76c..fbaf1ac3941b5e05fa68681a3fa5b82fffaeedba 100644 (file)
@@ -8437,7 +8437,8 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work)
  * 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, int delay_iput)
+static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput,
+                                  int nr)
 {
        struct btrfs_inode *binode;
        struct inode *inode;
@@ -8471,23 +8472,19 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
                        else
                                iput(inode);
                        ret = -ENOMEM;
-                       goto out;
+                       break;
                }
                list_add_tail(&work->list, &works);
                btrfs_queue_work(root->fs_info->flush_workers,
                                 &work->work);
-
+               ret++;
+               if (nr != -1 && ret >= nr)
+                       break;
                cond_resched();
                spin_lock(&root->delalloc_lock);
        }
        spin_unlock(&root->delalloc_lock);
 
-       list_for_each_entry_safe(work, next, &works, list) {
-               list_del_init(&work->list);
-               btrfs_wait_and_free_delalloc_work(work);
-       }
-       return 0;
-out:
        list_for_each_entry_safe(work, next, &works, list) {
                list_del_init(&work->list);
                btrfs_wait_and_free_delalloc_work(work);
@@ -8508,7 +8505,9 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return -EROFS;
 
-       ret = __start_delalloc_inodes(root, delay_iput);
+       ret = __start_delalloc_inodes(root, delay_iput, -1);
+       if (ret > 0)
+               ret = 0;
        /*
         * the filemap_flush will queue IO into the worker threads, but
         * we have to make sure the IO is actually started and that
@@ -8525,7 +8524,8 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        return ret;
 }
 
-int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
+int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
+                              int nr)
 {
        struct btrfs_root *root;
        struct list_head splice;
@@ -8538,7 +8538,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
 
        spin_lock(&fs_info->delalloc_root_lock);
        list_splice_init(&fs_info->delalloc_roots, &splice);
-       while (!list_empty(&splice)) {
+       while (!list_empty(&splice) && nr) {
                root = list_first_entry(&splice, struct btrfs_root,
                                        delalloc_root);
                root = btrfs_grab_fs_root(root);
@@ -8547,15 +8547,20 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
                               &fs_info->delalloc_roots);
                spin_unlock(&fs_info->delalloc_root_lock);
 
-               ret = __start_delalloc_inodes(root, delay_iput);
+               ret = __start_delalloc_inodes(root, delay_iput, nr);
                btrfs_put_fs_root(root);
-               if (ret)
+               if (ret < 0)
                        goto out;
 
+               if (nr != -1) {
+                       nr -= ret;
+                       WARN_ON(nr < 0);
+               }
                spin_lock(&fs_info->delalloc_root_lock);
        }
        spin_unlock(&fs_info->delalloc_root_lock);
 
+       ret = 0;
        atomic_inc(&fs_info->async_submit_draining);
        while (atomic_read(&fs_info->nr_async_submits) ||
              atomic_read(&fs_info->async_delalloc_pages)) {
@@ -8564,7 +8569,6 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
                    atomic_read(&fs_info->async_delalloc_pages) == 0));
        }
        atomic_dec(&fs_info->async_submit_draining);
-       return 0;
 out:
        if (!list_empty_careful(&splice)) {
                spin_lock(&fs_info->delalloc_root_lock);
index 57bc9f33fa3c6d5b3f6d7ffc0d50821ac183d436..e1747701f5205da7b26c8c0cab379946bbe0d02e 100644 (file)
@@ -4893,7 +4893,7 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_SYNC: {
                int ret;
 
-               ret = btrfs_start_delalloc_roots(root->fs_info, 0);
+               ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1);
                if (ret)
                        return ret;
                ret = btrfs_sync_fs(file->f_dentry->d_sb, 1);
index 07b3b36f40ee51657b248112a6d1f028cea9e364..def428a25b2ab915f1331fccf4d8e98d62509ec7 100644 (file)
@@ -4248,7 +4248,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
        btrfs_info(extent_root->fs_info, "relocating block group %llu flags %llu",
               rc->block_group->key.objectid, rc->block_group->flags);
 
-       ret = btrfs_start_delalloc_roots(fs_info, 0);
+       ret = btrfs_start_delalloc_roots(fs_info, 0, -1);
        if (ret < 0) {
                err = ret;
                goto out;
index 79a4186b724a21ac28547b2dac5a13f548712d54..a999b85d11769b336525ffb08c8029a2af822952 100644 (file)
@@ -1620,7 +1620,7 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
-               return btrfs_start_delalloc_roots(fs_info, 1);
+               return btrfs_start_delalloc_roots(fs_info, 1, -1);
        return 0;
 }