aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-04-24 14:39:24 -0400
committerChris Mason <chris.mason@oracle.com>2009-04-24 15:46:05 -0400
commite980b50cda1610f1c17978d9b7fd311a9dd93877 (patch)
treea5ab72fa4b791758e25fd6ece6f1aedd29954e7b /fs/btrfs/inode.c
parent9601e3f6336f6ca66929f451b1f66085e68e36e3 (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.c27
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
4969static int prealloc_file_range(struct btrfs_trans_handle *trans, 4974static 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);