diff options
author | Josef Bacik <josef@redhat.com> | 2012-05-31 15:58:55 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-06-14 21:29:15 -0400 |
commit | 17ca04aff7e6171df684b7b65804df8830eb8c15 (patch) | |
tree | 6fa1d7daf40ba3c2df952dd30c660c88f418c1fd /fs/btrfs | |
parent | ee670f0af35871edb492db5ba406cef36d1b7c21 (diff) |
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/inode.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ccd6355af73f..b7f398c36cb7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1136,8 +1136,18 @@ static noinline int run_delalloc_nocow(struct inode *inode, | |||
1136 | u64 ino = btrfs_ino(inode); | 1136 | u64 ino = btrfs_ino(inode); |
1137 | 1137 | ||
1138 | path = btrfs_alloc_path(); | 1138 | path = btrfs_alloc_path(); |
1139 | if (!path) | 1139 | if (!path) { |
1140 | extent_clear_unlock_delalloc(inode, | ||
1141 | &BTRFS_I(inode)->io_tree, | ||
1142 | start, end, locked_page, | ||
1143 | EXTENT_CLEAR_UNLOCK_PAGE | | ||
1144 | EXTENT_CLEAR_UNLOCK | | ||
1145 | EXTENT_CLEAR_DELALLOC | | ||
1146 | EXTENT_CLEAR_DIRTY | | ||
1147 | EXTENT_SET_WRITEBACK | | ||
1148 | EXTENT_END_WRITEBACK); | ||
1140 | return -ENOMEM; | 1149 | return -ENOMEM; |
1150 | } | ||
1141 | 1151 | ||
1142 | nolock = btrfs_is_free_space_inode(root, inode); | 1152 | nolock = btrfs_is_free_space_inode(root, inode); |
1143 | 1153 | ||
@@ -1147,6 +1157,15 @@ static noinline int run_delalloc_nocow(struct inode *inode, | |||
1147 | trans = btrfs_join_transaction(root); | 1157 | trans = btrfs_join_transaction(root); |
1148 | 1158 | ||
1149 | if (IS_ERR(trans)) { | 1159 | if (IS_ERR(trans)) { |
1160 | extent_clear_unlock_delalloc(inode, | ||
1161 | &BTRFS_I(inode)->io_tree, | ||
1162 | start, end, locked_page, | ||
1163 | EXTENT_CLEAR_UNLOCK_PAGE | | ||
1164 | EXTENT_CLEAR_UNLOCK | | ||
1165 | EXTENT_CLEAR_DELALLOC | | ||
1166 | EXTENT_CLEAR_DIRTY | | ||
1167 | EXTENT_SET_WRITEBACK | | ||
1168 | EXTENT_END_WRITEBACK); | ||
1150 | btrfs_free_path(path); | 1169 | btrfs_free_path(path); |
1151 | return PTR_ERR(trans); | 1170 | return PTR_ERR(trans); |
1152 | } | 1171 | } |
@@ -1327,8 +1346,11 @@ out_check: | |||
1327 | } | 1346 | } |
1328 | btrfs_release_path(path); | 1347 | btrfs_release_path(path); |
1329 | 1348 | ||
1330 | if (cur_offset <= end && cow_start == (u64)-1) | 1349 | if (cur_offset <= end && cow_start == (u64)-1) { |
1331 | cow_start = cur_offset; | 1350 | cow_start = cur_offset; |
1351 | cur_offset = end; | ||
1352 | } | ||
1353 | |||
1332 | if (cow_start != (u64)-1) { | 1354 | if (cow_start != (u64)-1) { |
1333 | ret = cow_file_range(inode, locked_page, cow_start, end, | 1355 | ret = cow_file_range(inode, locked_page, cow_start, end, |
1334 | page_started, nr_written, 1); | 1356 | page_started, nr_written, 1); |
@@ -1347,6 +1369,17 @@ error: | |||
1347 | if (!ret) | 1369 | if (!ret) |
1348 | ret = err; | 1370 | ret = err; |
1349 | 1371 | ||
1372 | if (ret && cur_offset < end) | ||
1373 | extent_clear_unlock_delalloc(inode, | ||
1374 | &BTRFS_I(inode)->io_tree, | ||
1375 | cur_offset, end, locked_page, | ||
1376 | EXTENT_CLEAR_UNLOCK_PAGE | | ||
1377 | EXTENT_CLEAR_UNLOCK | | ||
1378 | EXTENT_CLEAR_DELALLOC | | ||
1379 | EXTENT_CLEAR_DIRTY | | ||
1380 | EXTENT_SET_WRITEBACK | | ||
1381 | EXTENT_END_WRITEBACK); | ||
1382 | |||
1350 | btrfs_free_path(path); | 1383 | btrfs_free_path(path); |
1351 | return ret; | 1384 | return ret; |
1352 | } | 1385 | } |