aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZhao Lei <zhaolei@cn.fujitsu.com>2015-02-25 21:49:20 -0500
committerChris Mason <clm@fb.com>2015-04-13 10:27:41 -0400
commitd7c151717a1efe289aec29fb9f94485f64262c0b (patch)
tree64a17c0b1403fbbb14e474e101a997f117de237c /fs
parent18d018ad2c899d3d9c503c25125d56046ed7d3ca (diff)
btrfs: Fix NO_SPACE bug caused by delayed-iput
Steps to reproduce: while true; do dd if=/dev/zero of=/btrfs_dir/file count=[fs_size * 75%] rm /btrfs_dir/file sync done And we'll see dd failed because btrfs return NO_SPACE. Reason: Normally, btrfs_commit_transaction() call btrfs_run_delayed_iputs() in end to free fs space for next write, but sometimes it hadn't done work on time, because btrfs-cleaner thread get delayed-iputs from list before, but do iput() after next write. This is log: [ 2569.050776] comm=btrfs-cleaner func=btrfs_evict_inode() begin [ 2569.084280] comm=sync func=btrfs_commit_transaction() call btrfs_run_delayed_iputs() [ 2569.085418] comm=sync func=btrfs_commit_transaction() done btrfs_run_delayed_iputs() [ 2569.087554] comm=sync func=btrfs_commit_transaction() end [ 2569.191081] comm=dd begin [ 2569.790112] comm=dd func=__btrfs_buffered_write() ret=-28 [ 2569.847479] comm=btrfs-cleaner func=add_pinned_bytes() 0 + 32677888 = 32677888 [ 2569.849530] comm=btrfs-cleaner func=add_pinned_bytes() 32677888 + 23834624 = 56512512 ... [ 2569.903893] comm=btrfs-cleaner func=add_pinned_bytes() 943976448 + 21762048 = 965738496 [ 2569.908270] comm=btrfs-cleaner func=btrfs_evict_inode() end Fix: Make btrfs_commit_transaction() wait current running btrfs-cleaner's delayed-iputs() done in end. Test: Use script similar to above(more complex), before patch: 7 failed in 100 * 20 loop. after patch: 0 failed in 100 * 20 loop. Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c3
-rw-r--r--fs/btrfs/extent-tree.c6
-rw-r--r--fs/btrfs/inode.c4
4 files changed, 13 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 10b6a75ab7e6..d48b22f31182 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1538,6 +1538,7 @@ struct btrfs_fs_info {
1538 1538
1539 spinlock_t delayed_iput_lock; 1539 spinlock_t delayed_iput_lock;
1540 struct list_head delayed_iputs; 1540 struct list_head delayed_iputs;
1541 struct rw_semaphore delayed_iput_sem;
1541 1542
1542 /* this protects tree_mod_seq_list */ 1543 /* this protects tree_mod_seq_list */
1543 spinlock_t tree_mod_seq_lock; 1544 spinlock_t tree_mod_seq_lock;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 62cd3b63190d..2ef9a4b72d06 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2487,11 +2487,12 @@ int open_ctree(struct super_block *sb,
2487 spin_lock_init(&fs_info->qgroup_op_lock); 2487 spin_lock_init(&fs_info->qgroup_op_lock);
2488 spin_lock_init(&fs_info->buffer_lock); 2488 spin_lock_init(&fs_info->buffer_lock);
2489 spin_lock_init(&fs_info->unused_bgs_lock); 2489 spin_lock_init(&fs_info->unused_bgs_lock);
2490 mutex_init(&fs_info->unused_bg_unpin_mutex);
2491 rwlock_init(&fs_info->tree_mod_log_lock); 2490 rwlock_init(&fs_info->tree_mod_log_lock);
2491 mutex_init(&fs_info->unused_bg_unpin_mutex);
2492 mutex_init(&fs_info->reloc_mutex); 2492 mutex_init(&fs_info->reloc_mutex);
2493 mutex_init(&fs_info->delalloc_root_mutex); 2493 mutex_init(&fs_info->delalloc_root_mutex);
2494 seqlock_init(&fs_info->profiles_lock); 2494 seqlock_init(&fs_info->profiles_lock);
2495 init_rwsem(&fs_info->delayed_iput_sem);
2495 2496
2496 init_completion(&fs_info->kobj_unregister); 2497 init_completion(&fs_info->kobj_unregister);
2497 INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); 2498 INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index be4a79a69ed1..46cb1d414912 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3950,6 +3950,12 @@ commit_trans:
3950 ret = btrfs_commit_transaction(trans, root); 3950 ret = btrfs_commit_transaction(trans, root);
3951 if (ret) 3951 if (ret)
3952 return ret; 3952 return ret;
3953 /*
3954 * make sure that all running delayed iput are
3955 * done
3956 */
3957 down_write(&root->fs_info->delayed_iput_sem);
3958 up_write(&root->fs_info->delayed_iput_sem);
3953 goto again; 3959 goto again;
3954 } else { 3960 } else {
3955 btrfs_end_transaction(trans, root); 3961 btrfs_end_transaction(trans, root);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 141df0ce6f93..6ef97c184c7b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3111,6 +3111,8 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root)
3111 if (empty) 3111 if (empty)
3112 return; 3112 return;
3113 3113
3114 down_read(&fs_info->delayed_iput_sem);
3115
3114 spin_lock(&fs_info->delayed_iput_lock); 3116 spin_lock(&fs_info->delayed_iput_lock);
3115 list_splice_init(&fs_info->delayed_iputs, &list); 3117 list_splice_init(&fs_info->delayed_iputs, &list);
3116 spin_unlock(&fs_info->delayed_iput_lock); 3118 spin_unlock(&fs_info->delayed_iput_lock);
@@ -3121,6 +3123,8 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root)
3121 iput(delayed->inode); 3123 iput(delayed->inode);
3122 kfree(delayed); 3124 kfree(delayed);
3123 } 3125 }
3126
3127 up_read(&root->fs_info->delayed_iput_sem);
3124} 3128}
3125 3129
3126/* 3130/*