diff options
-rw-r--r-- | fs/btrfs/inode.c | 55 |
1 files changed, 41 insertions, 14 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 9bc6c40b182d..ca7ace7b7b52 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -7585,41 +7585,61 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work) | |||
7585 | */ | 7585 | */ |
7586 | int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | 7586 | int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) |
7587 | { | 7587 | { |
7588 | struct list_head *head = &root->fs_info->delalloc_inodes; | ||
7589 | struct btrfs_inode *binode; | 7588 | struct btrfs_inode *binode; |
7590 | struct inode *inode; | 7589 | struct inode *inode; |
7591 | struct btrfs_delalloc_work *work, *next; | 7590 | struct btrfs_delalloc_work *work, *next; |
7592 | struct list_head works; | 7591 | struct list_head works; |
7592 | struct list_head splice; | ||
7593 | int ret = 0; | 7593 | int ret = 0; |
7594 | 7594 | ||
7595 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 7595 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
7596 | return -EROFS; | 7596 | return -EROFS; |
7597 | 7597 | ||
7598 | INIT_LIST_HEAD(&works); | 7598 | INIT_LIST_HEAD(&works); |
7599 | 7599 | INIT_LIST_HEAD(&splice); | |
7600 | again: | ||
7600 | spin_lock(&root->fs_info->delalloc_lock); | 7601 | spin_lock(&root->fs_info->delalloc_lock); |
7601 | while (!list_empty(head)) { | 7602 | list_splice_init(&root->fs_info->delalloc_inodes, &splice); |
7602 | binode = list_entry(head->next, struct btrfs_inode, | 7603 | while (!list_empty(&splice)) { |
7604 | binode = list_entry(splice.next, struct btrfs_inode, | ||
7603 | delalloc_inodes); | 7605 | delalloc_inodes); |
7606 | |||
7607 | list_del_init(&binode->delalloc_inodes); | ||
7608 | |||
7604 | inode = igrab(&binode->vfs_inode); | 7609 | inode = igrab(&binode->vfs_inode); |
7605 | if (!inode) | 7610 | if (!inode) |
7606 | list_del_init(&binode->delalloc_inodes); | 7611 | continue; |
7612 | |||
7613 | list_add_tail(&binode->delalloc_inodes, | ||
7614 | &root->fs_info->delalloc_inodes); | ||
7607 | spin_unlock(&root->fs_info->delalloc_lock); | 7615 | spin_unlock(&root->fs_info->delalloc_lock); |
7608 | if (inode) { | 7616 | |
7609 | work = btrfs_alloc_delalloc_work(inode, 0, delay_iput); | 7617 | work = btrfs_alloc_delalloc_work(inode, 0, delay_iput); |
7610 | if (!work) { | 7618 | if (unlikely(!work)) { |
7611 | ret = -ENOMEM; | 7619 | ret = -ENOMEM; |
7612 | goto out; | 7620 | goto out; |
7613 | } | ||
7614 | list_add_tail(&work->list, &works); | ||
7615 | btrfs_queue_worker(&root->fs_info->flush_workers, | ||
7616 | &work->work); | ||
7617 | } | 7621 | } |
7622 | list_add_tail(&work->list, &works); | ||
7623 | btrfs_queue_worker(&root->fs_info->flush_workers, | ||
7624 | &work->work); | ||
7625 | |||
7618 | cond_resched(); | 7626 | cond_resched(); |
7619 | spin_lock(&root->fs_info->delalloc_lock); | 7627 | spin_lock(&root->fs_info->delalloc_lock); |
7620 | } | 7628 | } |
7621 | spin_unlock(&root->fs_info->delalloc_lock); | 7629 | spin_unlock(&root->fs_info->delalloc_lock); |
7622 | 7630 | ||
7631 | list_for_each_entry_safe(work, next, &works, list) { | ||
7632 | list_del_init(&work->list); | ||
7633 | btrfs_wait_and_free_delalloc_work(work); | ||
7634 | } | ||
7635 | |||
7636 | spin_lock(&root->fs_info->delalloc_lock); | ||
7637 | if (!list_empty(&root->fs_info->delalloc_inodes)) { | ||
7638 | spin_unlock(&root->fs_info->delalloc_lock); | ||
7639 | goto again; | ||
7640 | } | ||
7641 | spin_unlock(&root->fs_info->delalloc_lock); | ||
7642 | |||
7623 | /* the filemap_flush will queue IO into the worker threads, but | 7643 | /* the filemap_flush will queue IO into the worker threads, but |
7624 | * we have to make sure the IO is actually started and that | 7644 | * we have to make sure the IO is actually started and that |
7625 | * ordered extents get created before we return | 7645 | * ordered extents get created before we return |
@@ -7632,11 +7652,18 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | |||
7632 | atomic_read(&root->fs_info->async_delalloc_pages) == 0)); | 7652 | atomic_read(&root->fs_info->async_delalloc_pages) == 0)); |
7633 | } | 7653 | } |
7634 | atomic_dec(&root->fs_info->async_submit_draining); | 7654 | atomic_dec(&root->fs_info->async_submit_draining); |
7655 | return 0; | ||
7635 | out: | 7656 | out: |
7636 | list_for_each_entry_safe(work, next, &works, list) { | 7657 | list_for_each_entry_safe(work, next, &works, list) { |
7637 | list_del_init(&work->list); | 7658 | list_del_init(&work->list); |
7638 | btrfs_wait_and_free_delalloc_work(work); | 7659 | btrfs_wait_and_free_delalloc_work(work); |
7639 | } | 7660 | } |
7661 | |||
7662 | if (!list_empty_careful(&splice)) { | ||
7663 | spin_lock(&root->fs_info->delalloc_lock); | ||
7664 | list_splice_tail(&splice, &root->fs_info->delalloc_inodes); | ||
7665 | spin_unlock(&root->fs_info->delalloc_lock); | ||
7666 | } | ||
7640 | return ret; | 7667 | return ret; |
7641 | } | 7668 | } |
7642 | 7669 | ||