aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.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/file.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/file.c')
-rw-r--r--fs/btrfs/file.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 482f8db2cfd0..da3ed965c956 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -363,15 +363,16 @@ out:
363 */ 363 */
364noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, 364noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
365 struct btrfs_root *root, struct inode *inode, 365 struct btrfs_root *root, struct inode *inode,
366 u64 start, u64 end, u64 inline_limit, u64 *hint_byte) 366 u64 start, u64 end, u64 locked_end,
367 u64 inline_limit, u64 *hint_byte)
367{ 368{
368 u64 extent_end = 0; 369 u64 extent_end = 0;
369 u64 locked_end = end;
370 u64 search_start = start; 370 u64 search_start = start;
371 u64 leaf_start; 371 u64 leaf_start;
372 u64 ram_bytes = 0; 372 u64 ram_bytes = 0;
373 u64 orig_parent = 0; 373 u64 orig_parent = 0;
374 u64 disk_bytenr = 0; 374 u64 disk_bytenr = 0;
375 u64 orig_locked_end = locked_end;
375 u8 compression; 376 u8 compression;
376 u8 encryption; 377 u8 encryption;
377 u16 other_encoding = 0; 378 u16 other_encoding = 0;
@@ -684,9 +685,9 @@ next_slot:
684 } 685 }
685out: 686out:
686 btrfs_free_path(path); 687 btrfs_free_path(path);
687 if (locked_end > end) { 688 if (locked_end > orig_locked_end) {
688 unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1, 689 unlock_extent(&BTRFS_I(inode)->io_tree, orig_locked_end,
689 GFP_NOFS); 690 locked_end - 1, GFP_NOFS);
690 } 691 }
691 btrfs_check_file(root, inode); 692 btrfs_check_file(root, inode);
692 return ret; 693 return ret;