diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-04-21 11:53:38 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-04-21 12:45:12 -0400 |
commit | 546888da82082555a56528730a83f0afd12f33bf (patch) | |
tree | 98ee868d1b8a4bd390a980fed707f91419b79fb5 /fs/btrfs/file.c | |
parent | 8c594ea81d7abbbffdda447b127f8ba8d76f319d (diff) |
Btrfs: fix btrfs fallocate oops and deadlock
Btrfs fallocate was incorrectly starting a transaction with a lock held
on the extent_io tree for the file, which could deadlock. Strictly
speaking it was using join_transaction which would be safe, but it is better
to move the transaction outside of the lock.
When preallocated extents are overwritten, btrfs_mark_buffer_dirty was
being called on an unlocked buffer. This was triggering an assertion and
oops because the lock is supposed to be held.
The bug was calling btrfs_mark_buffer_dirty on a leaf after btrfs_del_item had
been run. btrfs_del_item takes care of dirtying things, so the solution is a
to skip the btrfs_mark_buffer_dirty call in this case.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e21c0060ee73..482f8db2cfd0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -830,7 +830,7 @@ again: | |||
830 | 830 | ||
831 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | 831 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); |
832 | BUG_ON(ret); | 832 | BUG_ON(ret); |
833 | goto done; | 833 | goto release; |
834 | } else if (split == start) { | 834 | } else if (split == start) { |
835 | if (locked_end < extent_end) { | 835 | if (locked_end < extent_end) { |
836 | ret = try_lock_extent(&BTRFS_I(inode)->io_tree, | 836 | ret = try_lock_extent(&BTRFS_I(inode)->io_tree, |
@@ -926,6 +926,8 @@ again: | |||
926 | } | 926 | } |
927 | done: | 927 | done: |
928 | btrfs_mark_buffer_dirty(leaf); | 928 | btrfs_mark_buffer_dirty(leaf); |
929 | |||
930 | release: | ||
929 | btrfs_release_path(root, path); | 931 | btrfs_release_path(root, path); |
930 | if (split_end && split == start) { | 932 | if (split_end && split == start) { |
931 | split = end; | 933 | split = end; |