Skip to content

Commit

Permalink
Btrfs: fix deadlock on metadata reservation when evicting a inode
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Miao Xie authored and kdave committed Nov 30, 2011
1 parent b52f75a commit aa38a71
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
3 changes: 3 additions & 0 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
int btrfs_block_rsv_refill(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved);
int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved);
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
struct btrfs_block_rsv *dst_rsv,
u64 num_bytes);
Expand Down
22 changes: 18 additions & 4 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3887,9 +3887,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
return ret;
}

int btrfs_block_rsv_refill(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved)
static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved, int flush)
{
u64 num_bytes = 0;
int ret = -ENOSPC;
Expand All @@ -3908,7 +3908,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
if (!ret)
return 0;

ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1);
ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
if (!ret) {
block_rsv_add_bytes(block_rsv, num_bytes, 0);
return 0;
Expand All @@ -3917,6 +3917,20 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
return ret;
}

int btrfs_block_rsv_refill(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved)
{
return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1);
}

int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 min_reserved)
{
return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0);
}

int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
struct btrfs_block_rsv *dst_rsv,
u64 num_bytes)
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3490,7 +3490,7 @@ void btrfs_evict_inode(struct inode *inode)
* doing the truncate.
*/
while (1) {
ret = btrfs_block_rsv_refill(root, rsv, min_size);
ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size);

/*
* Try and steal from the global reserve since we will
Expand Down

0 comments on commit aa38a71

Please sign in to comment.