diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-04-24 14:39:24 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-04-24 15:46:05 -0400 |
commit | e980b50cda1610f1c17978d9b7fd311a9dd93877 (patch) | |
tree | a5ab72fa4b791758e25fd6ece6f1aedd29954e7b /fs/btrfs/inode.c | |
parent | 9601e3f6336f6ca66929f451b1f66085e68e36e3 (diff) |
Btrfs: fix fallocate deadlock on inode extent lock
The btrfs fallocate call takes an extent lock on the entire range
being fallocated, and then runs through insert_reserved_extent on each
extent as they are allocated.
The problem with this is that btrfs_drop_extents may decide to try
and take the same extent lock fallocate was already holding. The solution
used here is to push down knowledge of the range that is already locked
going into btrfs_drop_extents.
It turns out that at least one other caller had the same bug.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 176b6cc28b1e..2fdb2995be64 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -234,7 +234,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, | |||
234 | } | 234 | } |
235 | 235 | ||
236 | ret = btrfs_drop_extents(trans, root, inode, start, | 236 | ret = btrfs_drop_extents(trans, root, inode, start, |
237 | aligned_end, start, &hint_byte); | 237 | aligned_end, aligned_end, start, &hint_byte); |
238 | BUG_ON(ret); | 238 | BUG_ON(ret); |
239 | 239 | ||
240 | if (isize > actual_end) | 240 | if (isize > actual_end) |
@@ -1439,6 +1439,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1439 | struct inode *inode, u64 file_pos, | 1439 | struct inode *inode, u64 file_pos, |
1440 | u64 disk_bytenr, u64 disk_num_bytes, | 1440 | u64 disk_bytenr, u64 disk_num_bytes, |
1441 | u64 num_bytes, u64 ram_bytes, | 1441 | u64 num_bytes, u64 ram_bytes, |
1442 | u64 locked_end, | ||
1442 | u8 compression, u8 encryption, | 1443 | u8 compression, u8 encryption, |
1443 | u16 other_encoding, int extent_type) | 1444 | u16 other_encoding, int extent_type) |
1444 | { | 1445 | { |
@@ -1455,7 +1456,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1455 | 1456 | ||
1456 | path->leave_spinning = 1; | 1457 | path->leave_spinning = 1; |
1457 | ret = btrfs_drop_extents(trans, root, inode, file_pos, | 1458 | ret = btrfs_drop_extents(trans, root, inode, file_pos, |
1458 | file_pos + num_bytes, file_pos, &hint); | 1459 | file_pos + num_bytes, locked_end, |
1460 | file_pos, &hint); | ||
1459 | BUG_ON(ret); | 1461 | BUG_ON(ret); |
1460 | 1462 | ||
1461 | ins.objectid = inode->i_ino; | 1463 | ins.objectid = inode->i_ino; |
@@ -1590,6 +1592,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1590 | ordered_extent->disk_len, | 1592 | ordered_extent->disk_len, |
1591 | ordered_extent->len, | 1593 | ordered_extent->len, |
1592 | ordered_extent->len, | 1594 | ordered_extent->len, |
1595 | ordered_extent->file_offset + | ||
1596 | ordered_extent->len, | ||
1593 | compressed, 0, 0, | 1597 | compressed, 0, 0, |
1594 | BTRFS_FILE_EXTENT_REG); | 1598 | BTRFS_FILE_EXTENT_REG); |
1595 | BUG_ON(ret); | 1599 | BUG_ON(ret); |
@@ -2877,6 +2881,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) | |||
2877 | err = btrfs_drop_extents(trans, root, inode, | 2881 | err = btrfs_drop_extents(trans, root, inode, |
2878 | cur_offset, | 2882 | cur_offset, |
2879 | cur_offset + hole_size, | 2883 | cur_offset + hole_size, |
2884 | block_end, | ||
2880 | cur_offset, &hint_byte); | 2885 | cur_offset, &hint_byte); |
2881 | if (err) | 2886 | if (err) |
2882 | break; | 2887 | break; |
@@ -4968,7 +4973,7 @@ out_fail: | |||
4968 | 4973 | ||
4969 | static int prealloc_file_range(struct btrfs_trans_handle *trans, | 4974 | static int prealloc_file_range(struct btrfs_trans_handle *trans, |
4970 | struct inode *inode, u64 start, u64 end, | 4975 | struct inode *inode, u64 start, u64 end, |
4971 | u64 alloc_hint, int mode) | 4976 | u64 locked_end, u64 alloc_hint, int mode) |
4972 | { | 4977 | { |
4973 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4978 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4974 | struct btrfs_key ins; | 4979 | struct btrfs_key ins; |
@@ -4989,7 +4994,8 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans, | |||
4989 | ret = insert_reserved_file_extent(trans, inode, | 4994 | ret = insert_reserved_file_extent(trans, inode, |
4990 | cur_offset, ins.objectid, | 4995 | cur_offset, ins.objectid, |
4991 | ins.offset, ins.offset, | 4996 | ins.offset, ins.offset, |
4992 | ins.offset, 0, 0, 0, | 4997 | ins.offset, locked_end, |
4998 | 0, 0, 0, | ||
4993 | BTRFS_FILE_EXTENT_PREALLOC); | 4999 | BTRFS_FILE_EXTENT_PREALLOC); |
4994 | BUG_ON(ret); | 5000 | BUG_ON(ret); |
4995 | num_bytes -= ins.offset; | 5001 | num_bytes -= ins.offset; |
@@ -5018,6 +5024,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5018 | u64 alloc_start; | 5024 | u64 alloc_start; |
5019 | u64 alloc_end; | 5025 | u64 alloc_end; |
5020 | u64 alloc_hint = 0; | 5026 | u64 alloc_hint = 0; |
5027 | u64 locked_end; | ||
5021 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | 5028 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
5022 | struct extent_map *em; | 5029 | struct extent_map *em; |
5023 | struct btrfs_trans_handle *trans; | 5030 | struct btrfs_trans_handle *trans; |
@@ -5039,6 +5046,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5039 | goto out; | 5046 | goto out; |
5040 | } | 5047 | } |
5041 | 5048 | ||
5049 | locked_end = alloc_end - 1; | ||
5042 | while (1) { | 5050 | while (1) { |
5043 | struct btrfs_ordered_extent *ordered; | 5051 | struct btrfs_ordered_extent *ordered; |
5044 | 5052 | ||
@@ -5051,8 +5059,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5051 | /* the extent lock is ordered inside the running | 5059 | /* the extent lock is ordered inside the running |
5052 | * transaction | 5060 | * transaction |
5053 | */ | 5061 | */ |
5054 | lock_extent(&BTRFS_I(inode)->io_tree, alloc_start, | 5062 | lock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, |
5055 | alloc_end - 1, GFP_NOFS); | 5063 | GFP_NOFS); |
5056 | ordered = btrfs_lookup_first_ordered_extent(inode, | 5064 | ordered = btrfs_lookup_first_ordered_extent(inode, |
5057 | alloc_end - 1); | 5065 | alloc_end - 1); |
5058 | if (ordered && | 5066 | if (ordered && |
@@ -5060,7 +5068,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5060 | ordered->file_offset < alloc_end) { | 5068 | ordered->file_offset < alloc_end) { |
5061 | btrfs_put_ordered_extent(ordered); | 5069 | btrfs_put_ordered_extent(ordered); |
5062 | unlock_extent(&BTRFS_I(inode)->io_tree, | 5070 | unlock_extent(&BTRFS_I(inode)->io_tree, |
5063 | alloc_start, alloc_end - 1, GFP_NOFS); | 5071 | alloc_start, locked_end, GFP_NOFS); |
5064 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | 5072 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); |
5065 | 5073 | ||
5066 | /* | 5074 | /* |
@@ -5085,7 +5093,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5085 | last_byte = (last_byte + mask) & ~mask; | 5093 | last_byte = (last_byte + mask) & ~mask; |
5086 | if (em->block_start == EXTENT_MAP_HOLE) { | 5094 | if (em->block_start == EXTENT_MAP_HOLE) { |
5087 | ret = prealloc_file_range(trans, inode, cur_offset, | 5095 | ret = prealloc_file_range(trans, inode, cur_offset, |
5088 | last_byte, alloc_hint, mode); | 5096 | last_byte, locked_end + 1, |
5097 | alloc_hint, mode); | ||
5089 | if (ret < 0) { | 5098 | if (ret < 0) { |
5090 | free_extent_map(em); | 5099 | free_extent_map(em); |
5091 | break; | 5100 | break; |
@@ -5101,7 +5110,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5101 | break; | 5110 | break; |
5102 | } | 5111 | } |
5103 | } | 5112 | } |
5104 | unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, alloc_end - 1, | 5113 | unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, |
5105 | GFP_NOFS); | 5114 | GFP_NOFS); |
5106 | 5115 | ||
5107 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | 5116 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); |