Skip to content

Commit 546888d

Browse files
committed
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 <[email protected]>
1 parent 8c594ea commit 546888d

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

fs/btrfs/file.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
830830

831831
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
832832
BUG_ON(ret);
833-
goto done;
833+
goto release;
834834
} else if (split == start) {
835835
if (locked_end < extent_end) {
836836
ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
@@ -926,6 +926,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
926926
}
927927
done:
928928
btrfs_mark_buffer_dirty(leaf);
929+
930+
release:
929931
btrfs_release_path(root, path);
930932
if (split_end && split == start) {
931933
split = end;

fs/btrfs/inode.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4970,21 +4970,17 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
49704970
return err;
49714971
}
49724972

4973-
static int prealloc_file_range(struct inode *inode, u64 start, u64 end,
4973+
static int prealloc_file_range(struct btrfs_trans_handle *trans,
4974+
struct inode *inode, u64 start, u64 end,
49744975
u64 alloc_hint, int mode)
49754976
{
4976-
struct btrfs_trans_handle *trans;
49774977
struct btrfs_root *root = BTRFS_I(inode)->root;
49784978
struct btrfs_key ins;
49794979
u64 alloc_size;
49804980
u64 cur_offset = start;
49814981
u64 num_bytes = end - start;
49824982
int ret = 0;
49834983

4984-
trans = btrfs_join_transaction(root, 1);
4985-
BUG_ON(!trans);
4986-
btrfs_set_trans_block_group(trans, inode);
4987-
49884984
while (num_bytes > 0) {
49894985
alloc_size = min(num_bytes, root->fs_info->max_extent);
49904986
ret = btrfs_reserve_extent(trans, root, alloc_size,
@@ -5015,7 +5011,6 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end,
50155011
BUG_ON(ret);
50165012
}
50175013

5018-
btrfs_end_transaction(trans, root);
50195014
return ret;
50205015
}
50215016

@@ -5029,11 +5024,18 @@ static long btrfs_fallocate(struct inode *inode, int mode,
50295024
u64 alloc_hint = 0;
50305025
u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
50315026
struct extent_map *em;
5027+
struct btrfs_trans_handle *trans;
50325028
int ret;
50335029

50345030
alloc_start = offset & ~mask;
50355031
alloc_end = (offset + len + mask) & ~mask;
50365032

5033+
/*
5034+
* wait for ordered IO before we have any locks. We'll loop again
5035+
* below with the locks held.
5036+
*/
5037+
btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
5038+
50375039
mutex_lock(&inode->i_mutex);
50385040
if (alloc_start > inode->i_size) {
50395041
ret = btrfs_cont_expand(inode, alloc_start);
@@ -5043,6 +5045,16 @@ static long btrfs_fallocate(struct inode *inode, int mode,
50435045

50445046
while (1) {
50455047
struct btrfs_ordered_extent *ordered;
5048+
5049+
trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
5050+
if (!trans) {
5051+
ret = -EIO;
5052+
goto out;
5053+
}
5054+
5055+
/* the extent lock is ordered inside the running
5056+
* transaction
5057+
*/
50465058
lock_extent(&BTRFS_I(inode)->io_tree, alloc_start,
50475059
alloc_end - 1, GFP_NOFS);
50485060
ordered = btrfs_lookup_first_ordered_extent(inode,
@@ -5053,6 +5065,12 @@ static long btrfs_fallocate(struct inode *inode, int mode,
50535065
btrfs_put_ordered_extent(ordered);
50545066
unlock_extent(&BTRFS_I(inode)->io_tree,
50555067
alloc_start, alloc_end - 1, GFP_NOFS);
5068+
btrfs_end_transaction(trans, BTRFS_I(inode)->root);
5069+
5070+
/*
5071+
* we can't wait on the range with the transaction
5072+
* running or with the extent lock held
5073+
*/
50565074
btrfs_wait_ordered_range(inode, alloc_start,
50575075
alloc_end - alloc_start);
50585076
} else {
@@ -5070,7 +5088,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
50705088
last_byte = min(extent_map_end(em), alloc_end);
50715089
last_byte = (last_byte + mask) & ~mask;
50725090
if (em->block_start == EXTENT_MAP_HOLE) {
5073-
ret = prealloc_file_range(inode, cur_offset,
5091+
ret = prealloc_file_range(trans, inode, cur_offset,
50745092
last_byte, alloc_hint, mode);
50755093
if (ret < 0) {
50765094
free_extent_map(em);
@@ -5089,6 +5107,8 @@ static long btrfs_fallocate(struct inode *inode, int mode,
50895107
}
50905108
unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, alloc_end - 1,
50915109
GFP_NOFS);
5110+
5111+
btrfs_end_transaction(trans, BTRFS_I(inode)->root);
50925112
out:
50935113
mutex_unlock(&inode->i_mutex);
50945114
return ret;

0 commit comments

Comments
 (0)