aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2011-11-18 04:43:00 -0500
committerDavid Sterba <dsterba@suse.cz>2011-11-30 12:46:03 -0500
commitaa38a711a893accf5b5192f3d705a120deaa81e0 (patch)
tree59dbb3bca55b7141ba0e0fda1031452ae87a6935
parentb52f75a595e8a70ee453bd6fb8023ee294f7a729 (diff)
Btrfs: fix deadlock on metadata reservation when evicting a inode
When I ran the xfstests, I found the test tasks was blocked on meta-data reservation. By debugging, I found the reason of this bug: start transaction | v reserve meta-data space | v flush delay allocation -> iput inode -> evict inode ^ | | v wait for delay allocation flush <- reserve meta-data space And besides that, the flush on evicting inode will block the thread, which is reclaiming the memory, and make oom happen easily. Fix this bug by skipping the flush step when evicting inode. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/extent-tree.c22
-rw-r--r--fs/btrfs/inode.c2
3 files changed, 22 insertions, 5 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 04a5dfcee5a1..50634abef9b4 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2369,6 +2369,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
2369int btrfs_block_rsv_refill(struct btrfs_root *root, 2369int btrfs_block_rsv_refill(struct btrfs_root *root,
2370 struct btrfs_block_rsv *block_rsv, 2370 struct btrfs_block_rsv *block_rsv,
2371 u64 min_reserved); 2371 u64 min_reserved);
2372int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
2373 struct btrfs_block_rsv *block_rsv,
2374 u64 min_reserved);
2372int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, 2375int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
2373 struct btrfs_block_rsv *dst_rsv, 2376 struct btrfs_block_rsv *dst_rsv,
2374 u64 num_bytes); 2377 u64 num_bytes);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 5d86877f10e1..b7e5f6898d07 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3887,9 +3887,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
3887 return ret; 3887 return ret;
3888} 3888}
3889 3889
3890int btrfs_block_rsv_refill(struct btrfs_root *root, 3890static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
3891 struct btrfs_block_rsv *block_rsv, 3891 struct btrfs_block_rsv *block_rsv,
3892 u64 min_reserved) 3892 u64 min_reserved, int flush)
3893{ 3893{
3894 u64 num_bytes = 0; 3894 u64 num_bytes = 0;
3895 int ret = -ENOSPC; 3895 int ret = -ENOSPC;
@@ -3908,7 +3908,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
3908 if (!ret) 3908 if (!ret)
3909 return 0; 3909 return 0;
3910 3910
3911 ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1); 3911 ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
3912 if (!ret) { 3912 if (!ret) {
3913 block_rsv_add_bytes(block_rsv, num_bytes, 0); 3913 block_rsv_add_bytes(block_rsv, num_bytes, 0);
3914 return 0; 3914 return 0;
@@ -3917,6 +3917,20 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
3917 return ret; 3917 return ret;
3918} 3918}
3919 3919
3920int btrfs_block_rsv_refill(struct btrfs_root *root,
3921 struct btrfs_block_rsv *block_rsv,
3922 u64 min_reserved)
3923{
3924 return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1);
3925}
3926
3927int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
3928 struct btrfs_block_rsv *block_rsv,
3929 u64 min_reserved)
3930{
3931 return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0);
3932}
3933
3920int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, 3934int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
3921 struct btrfs_block_rsv *dst_rsv, 3935 struct btrfs_block_rsv *dst_rsv,
3922 u64 num_bytes) 3936 u64 num_bytes)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8ad26b135a1c..c5ccec23984c 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3490,7 +3490,7 @@ void btrfs_evict_inode(struct inode *inode)
3490 * doing the truncate. 3490 * doing the truncate.
3491 */ 3491 */
3492 while (1) { 3492 while (1) {
3493 ret = btrfs_block_rsv_refill(root, rsv, min_size); 3493 ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size);
3494 3494
3495 /* 3495 /*
3496 * Try and steal from the global reserve since we will 3496 * Try and steal from the global reserve since we will