Btrfs: unlock everything properly in the error case for nocow
I was getting hung on umount when a transaction was aborted because a range of one of the free space inodes was still locked. This is because the nocow stuff doesn't unlock anything on error. This fixed the problem and I verified that is what was happening. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
This commit is contained in:
parent
ee670f0af3
commit
17ca04aff7
|
@ -1136,8 +1136,18 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
u64 ino = btrfs_ino(inode);
|
u64 ino = btrfs_ino(inode);
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path) {
|
||||||
|
extent_clear_unlock_delalloc(inode,
|
||||||
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
start, end, locked_page,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_UNLOCK |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
nolock = btrfs_is_free_space_inode(root, inode);
|
nolock = btrfs_is_free_space_inode(root, inode);
|
||||||
|
|
||||||
|
@ -1147,6 +1157,15 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
|
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
|
extent_clear_unlock_delalloc(inode,
|
||||||
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
start, end, locked_page,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_UNLOCK |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return PTR_ERR(trans);
|
return PTR_ERR(trans);
|
||||||
}
|
}
|
||||||
|
@ -1327,8 +1346,11 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
}
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
if (cur_offset <= end && cow_start == (u64)-1)
|
if (cur_offset <= end && cow_start == (u64)-1) {
|
||||||
cow_start = cur_offset;
|
cow_start = cur_offset;
|
||||||
|
cur_offset = end;
|
||||||
|
}
|
||||||
|
|
||||||
if (cow_start != (u64)-1) {
|
if (cow_start != (u64)-1) {
|
||||||
ret = cow_file_range(inode, locked_page, cow_start, end,
|
ret = cow_file_range(inode, locked_page, cow_start, end,
|
||||||
page_started, nr_written, 1);
|
page_started, nr_written, 1);
|
||||||
|
@ -1347,6 +1369,17 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = err;
|
ret = err;
|
||||||
|
|
||||||
|
if (ret && cur_offset < end)
|
||||||
|
extent_clear_unlock_delalloc(inode,
|
||||||
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
cur_offset, end, locked_page,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_UNLOCK |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user