diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2009-11-12 04:36:34 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-12-17 12:33:35 -0500 |
commit | 24bbcf0442ee04660a5a030efdbb6d03f1c275cb (patch) | |
tree | aa57d77d29cc5150b272cc3f6465f10262fcbaac /fs/btrfs/inode.c | |
parent | f34f57a3ab4e73304d78c125682f1a53cd3975f2 (diff) |
Btrfs: Add delayed iput
iput() can trigger new transactions if we are dropping the
final reference, so calling it in btrfs_commit_transaction
may end up deadlock. This patch adds delayed iput to avoid
the issue.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 82740a3c628a..168e8c040aab 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2022,6 +2022,54 @@ zeroit: | |||
2022 | return -EIO; | 2022 | return -EIO; |
2023 | } | 2023 | } |
2024 | 2024 | ||
2025 | struct delayed_iput { | ||
2026 | struct list_head list; | ||
2027 | struct inode *inode; | ||
2028 | }; | ||
2029 | |||
2030 | void btrfs_add_delayed_iput(struct inode *inode) | ||
2031 | { | ||
2032 | struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; | ||
2033 | struct delayed_iput *delayed; | ||
2034 | |||
2035 | if (atomic_add_unless(&inode->i_count, -1, 1)) | ||
2036 | return; | ||
2037 | |||
2038 | delayed = kmalloc(sizeof(*delayed), GFP_NOFS | __GFP_NOFAIL); | ||
2039 | delayed->inode = inode; | ||
2040 | |||
2041 | spin_lock(&fs_info->delayed_iput_lock); | ||
2042 | list_add_tail(&delayed->list, &fs_info->delayed_iputs); | ||
2043 | spin_unlock(&fs_info->delayed_iput_lock); | ||
2044 | } | ||
2045 | |||
2046 | void btrfs_run_delayed_iputs(struct btrfs_root *root) | ||
2047 | { | ||
2048 | LIST_HEAD(list); | ||
2049 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
2050 | struct delayed_iput *delayed; | ||
2051 | int empty; | ||
2052 | |||
2053 | spin_lock(&fs_info->delayed_iput_lock); | ||
2054 | empty = list_empty(&fs_info->delayed_iputs); | ||
2055 | spin_unlock(&fs_info->delayed_iput_lock); | ||
2056 | if (empty) | ||
2057 | return; | ||
2058 | |||
2059 | down_read(&root->fs_info->cleanup_work_sem); | ||
2060 | spin_lock(&fs_info->delayed_iput_lock); | ||
2061 | list_splice_init(&fs_info->delayed_iputs, &list); | ||
2062 | spin_unlock(&fs_info->delayed_iput_lock); | ||
2063 | |||
2064 | while (!list_empty(&list)) { | ||
2065 | delayed = list_entry(list.next, struct delayed_iput, list); | ||
2066 | list_del(&delayed->list); | ||
2067 | iput(delayed->inode); | ||
2068 | kfree(delayed); | ||
2069 | } | ||
2070 | up_read(&root->fs_info->cleanup_work_sem); | ||
2071 | } | ||
2072 | |||
2025 | /* | 2073 | /* |
2026 | * This creates an orphan entry for the given inode in case something goes | 2074 | * This creates an orphan entry for the given inode in case something goes |
2027 | * wrong in the middle of an unlink/truncate. | 2075 | * wrong in the middle of an unlink/truncate. |
@@ -5568,7 +5616,7 @@ out_fail: | |||
5568 | * some fairly slow code that needs optimization. This walks the list | 5616 | * some fairly slow code that needs optimization. This walks the list |
5569 | * of all the inodes with pending delalloc and forces them to disk. | 5617 | * of all the inodes with pending delalloc and forces them to disk. |
5570 | */ | 5618 | */ |
5571 | int btrfs_start_delalloc_inodes(struct btrfs_root *root) | 5619 | int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) |
5572 | { | 5620 | { |
5573 | struct list_head *head = &root->fs_info->delalloc_inodes; | 5621 | struct list_head *head = &root->fs_info->delalloc_inodes; |
5574 | struct btrfs_inode *binode; | 5622 | struct btrfs_inode *binode; |
@@ -5587,7 +5635,10 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root) | |||
5587 | spin_unlock(&root->fs_info->delalloc_lock); | 5635 | spin_unlock(&root->fs_info->delalloc_lock); |
5588 | if (inode) { | 5636 | if (inode) { |
5589 | filemap_flush(inode->i_mapping); | 5637 | filemap_flush(inode->i_mapping); |
5590 | iput(inode); | 5638 | if (delay_iput) |
5639 | btrfs_add_delayed_iput(inode); | ||
5640 | else | ||
5641 | iput(inode); | ||
5591 | } | 5642 | } |
5592 | cond_resched(); | 5643 | cond_resched(); |
5593 | spin_lock(&root->fs_info->delalloc_lock); | 5644 | spin_lock(&root->fs_info->delalloc_lock); |