diff options
-rw-r--r-- | fs/btrfs/ctree.c | 147 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 6 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 49 | ||||
-rw-r--r-- | fs/btrfs/locking.c | 16 | ||||
-rw-r--r-- | fs/btrfs/locking.h | 1 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 2 |
6 files changed, 173 insertions, 48 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c4792062dd53..7114faafa9d4 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -181,7 +181,8 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
181 | struct extent_buffer *buf, | 181 | struct extent_buffer *buf, |
182 | struct extent_buffer *parent, int parent_slot, | 182 | struct extent_buffer *parent, int parent_slot, |
183 | struct extent_buffer **cow_ret, | 183 | struct extent_buffer **cow_ret, |
184 | u64 search_start, u64 empty_size) | 184 | u64 search_start, u64 empty_size, |
185 | u64 prealloc_dest) | ||
185 | { | 186 | { |
186 | u64 root_gen; | 187 | u64 root_gen; |
187 | struct extent_buffer *cow; | 188 | struct extent_buffer *cow; |
@@ -216,10 +217,27 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
216 | } else { | 217 | } else { |
217 | first_key.objectid = 0; | 218 | first_key.objectid = 0; |
218 | } | 219 | } |
219 | cow = btrfs_alloc_free_block(trans, root, buf->len, | 220 | if (prealloc_dest) { |
220 | root->root_key.objectid, | 221 | struct btrfs_key ins; |
221 | root_gen, first_key.objectid, level, | 222 | |
222 | search_start, empty_size); | 223 | ins.objectid = prealloc_dest; |
224 | ins.offset = buf->len; | ||
225 | ins.type = BTRFS_EXTENT_ITEM_KEY; | ||
226 | |||
227 | ret = btrfs_alloc_reserved_extent(trans, root, | ||
228 | root->root_key.objectid, | ||
229 | root_gen, level, | ||
230 | first_key.objectid, | ||
231 | &ins); | ||
232 | BUG_ON(ret); | ||
233 | cow = btrfs_init_new_buffer(trans, root, prealloc_dest, | ||
234 | buf->len); | ||
235 | } else { | ||
236 | cow = btrfs_alloc_free_block(trans, root, buf->len, | ||
237 | root->root_key.objectid, | ||
238 | root_gen, first_key.objectid, | ||
239 | level, search_start, empty_size); | ||
240 | } | ||
223 | if (IS_ERR(cow)) | 241 | if (IS_ERR(cow)) |
224 | return PTR_ERR(cow); | 242 | return PTR_ERR(cow); |
225 | 243 | ||
@@ -279,7 +297,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
279 | int btrfs_cow_block(struct btrfs_trans_handle *trans, | 297 | int btrfs_cow_block(struct btrfs_trans_handle *trans, |
280 | struct btrfs_root *root, struct extent_buffer *buf, | 298 | struct btrfs_root *root, struct extent_buffer *buf, |
281 | struct extent_buffer *parent, int parent_slot, | 299 | struct extent_buffer *parent, int parent_slot, |
282 | struct extent_buffer **cow_ret) | 300 | struct extent_buffer **cow_ret, u64 prealloc_dest) |
283 | { | 301 | { |
284 | u64 search_start; | 302 | u64 search_start; |
285 | u64 header_trans; | 303 | u64 header_trans; |
@@ -302,12 +320,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
302 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { | 320 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { |
303 | *cow_ret = buf; | 321 | *cow_ret = buf; |
304 | spin_unlock(&root->fs_info->hash_lock); | 322 | spin_unlock(&root->fs_info->hash_lock); |
323 | WARN_ON(prealloc_dest); | ||
305 | return 0; | 324 | return 0; |
306 | } | 325 | } |
307 | spin_unlock(&root->fs_info->hash_lock); | 326 | spin_unlock(&root->fs_info->hash_lock); |
308 | search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); | 327 | search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); |
309 | ret = __btrfs_cow_block(trans, root, buf, parent, | 328 | ret = __btrfs_cow_block(trans, root, buf, parent, |
310 | parent_slot, cow_ret, search_start, 0); | 329 | parent_slot, cow_ret, search_start, 0, |
330 | prealloc_dest); | ||
311 | return ret; | 331 | return ret; |
312 | } | 332 | } |
313 | 333 | ||
@@ -451,7 +471,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
451 | err = __btrfs_cow_block(trans, root, cur, parent, i, | 471 | err = __btrfs_cow_block(trans, root, cur, parent, i, |
452 | &cur, search_start, | 472 | &cur, search_start, |
453 | min(16 * blocksize, | 473 | min(16 * blocksize, |
454 | (end_slot - i) * blocksize)); | 474 | (end_slot - i) * blocksize), 0); |
455 | if (err) { | 475 | if (err) { |
456 | btrfs_tree_unlock(cur); | 476 | btrfs_tree_unlock(cur); |
457 | free_extent_buffer(cur); | 477 | free_extent_buffer(cur); |
@@ -803,7 +823,7 @@ static int balance_level(struct btrfs_trans_handle *trans, | |||
803 | child = read_node_slot(root, mid, 0); | 823 | child = read_node_slot(root, mid, 0); |
804 | btrfs_tree_lock(child); | 824 | btrfs_tree_lock(child); |
805 | BUG_ON(!child); | 825 | BUG_ON(!child); |
806 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child); | 826 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0); |
807 | BUG_ON(ret); | 827 | BUG_ON(ret); |
808 | 828 | ||
809 | spin_lock(&root->node_lock); | 829 | spin_lock(&root->node_lock); |
@@ -836,7 +856,7 @@ static int balance_level(struct btrfs_trans_handle *trans, | |||
836 | if (left) { | 856 | if (left) { |
837 | btrfs_tree_lock(left); | 857 | btrfs_tree_lock(left); |
838 | wret = btrfs_cow_block(trans, root, left, | 858 | wret = btrfs_cow_block(trans, root, left, |
839 | parent, pslot - 1, &left); | 859 | parent, pslot - 1, &left, 0); |
840 | if (wret) { | 860 | if (wret) { |
841 | ret = wret; | 861 | ret = wret; |
842 | goto enospc; | 862 | goto enospc; |
@@ -846,7 +866,7 @@ static int balance_level(struct btrfs_trans_handle *trans, | |||
846 | if (right) { | 866 | if (right) { |
847 | btrfs_tree_lock(right); | 867 | btrfs_tree_lock(right); |
848 | wret = btrfs_cow_block(trans, root, right, | 868 | wret = btrfs_cow_block(trans, root, right, |
849 | parent, pslot + 1, &right); | 869 | parent, pslot + 1, &right, 0); |
850 | if (wret) { | 870 | if (wret) { |
851 | ret = wret; | 871 | ret = wret; |
852 | goto enospc; | 872 | goto enospc; |
@@ -1021,7 +1041,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
1021 | wret = 1; | 1041 | wret = 1; |
1022 | } else { | 1042 | } else { |
1023 | ret = btrfs_cow_block(trans, root, left, parent, | 1043 | ret = btrfs_cow_block(trans, root, left, parent, |
1024 | pslot - 1, &left); | 1044 | pslot - 1, &left, 0); |
1025 | if (ret) | 1045 | if (ret) |
1026 | wret = 1; | 1046 | wret = 1; |
1027 | else { | 1047 | else { |
@@ -1069,7 +1089,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
1069 | } else { | 1089 | } else { |
1070 | ret = btrfs_cow_block(trans, root, right, | 1090 | ret = btrfs_cow_block(trans, root, right, |
1071 | parent, pslot + 1, | 1091 | parent, pslot + 1, |
1072 | &right); | 1092 | &right, 0); |
1073 | if (ret) | 1093 | if (ret) |
1074 | wret = 1; | 1094 | wret = 1; |
1075 | else { | 1095 | else { |
@@ -1245,6 +1265,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1245 | u8 lowest_level = 0; | 1265 | u8 lowest_level = 0; |
1246 | u64 blocknr; | 1266 | u64 blocknr; |
1247 | u64 gen; | 1267 | u64 gen; |
1268 | struct btrfs_key prealloc_block; | ||
1248 | 1269 | ||
1249 | lowest_level = p->lowest_level; | 1270 | lowest_level = p->lowest_level; |
1250 | WARN_ON(lowest_level && ins_len); | 1271 | WARN_ON(lowest_level && ins_len); |
@@ -1253,6 +1274,9 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1253 | !mutex_is_locked(&root->fs_info->alloc_mutex)); | 1274 | !mutex_is_locked(&root->fs_info->alloc_mutex)); |
1254 | if (ins_len < 0) | 1275 | if (ins_len < 0) |
1255 | lowest_unlock = 2; | 1276 | lowest_unlock = 2; |
1277 | |||
1278 | prealloc_block.objectid = 0; | ||
1279 | |||
1256 | again: | 1280 | again: |
1257 | if (p->skip_locking) | 1281 | if (p->skip_locking) |
1258 | b = btrfs_root_node(root); | 1282 | b = btrfs_root_node(root); |
@@ -1261,27 +1285,82 @@ again: | |||
1261 | 1285 | ||
1262 | while (b) { | 1286 | while (b) { |
1263 | level = btrfs_header_level(b); | 1287 | level = btrfs_header_level(b); |
1288 | |||
1289 | /* | ||
1290 | * setup the path here so we can release it under lock | ||
1291 | * contention with the cow code | ||
1292 | */ | ||
1293 | p->nodes[level] = b; | ||
1294 | if (!p->skip_locking) | ||
1295 | p->locks[level] = 1; | ||
1296 | |||
1264 | if (cow) { | 1297 | if (cow) { |
1265 | int wret; | 1298 | int wret; |
1299 | |||
1300 | /* is a cow on this block not required */ | ||
1301 | spin_lock(&root->fs_info->hash_lock); | ||
1302 | if (btrfs_header_generation(b) == trans->transid && | ||
1303 | !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) { | ||
1304 | spin_unlock(&root->fs_info->hash_lock); | ||
1305 | goto cow_done; | ||
1306 | } | ||
1307 | spin_unlock(&root->fs_info->hash_lock); | ||
1308 | |||
1309 | /* ok, we have to cow, is our old prealloc the right | ||
1310 | * size? | ||
1311 | */ | ||
1312 | if (prealloc_block.objectid && | ||
1313 | prealloc_block.offset != b->len) { | ||
1314 | btrfs_free_reserved_extent(root, | ||
1315 | prealloc_block.objectid, | ||
1316 | prealloc_block.offset); | ||
1317 | prealloc_block.objectid = 0; | ||
1318 | } | ||
1319 | |||
1320 | /* | ||
1321 | * for higher level blocks, try not to allocate blocks | ||
1322 | * with the block and the parent locks held. | ||
1323 | */ | ||
1324 | if (level > 1 && !prealloc_block.objectid && | ||
1325 | btrfs_path_lock_waiting(p, level)) { | ||
1326 | u32 size = b->len; | ||
1327 | u64 hint = b->start; | ||
1328 | |||
1329 | btrfs_release_path(root, p); | ||
1330 | ret = btrfs_reserve_extent(trans, root, | ||
1331 | size, size, 0, | ||
1332 | hint, (u64)-1, | ||
1333 | &prealloc_block, 0); | ||
1334 | BUG_ON(ret); | ||
1335 | goto again; | ||
1336 | } | ||
1337 | |||
1266 | wret = btrfs_cow_block(trans, root, b, | 1338 | wret = btrfs_cow_block(trans, root, b, |
1267 | p->nodes[level + 1], | 1339 | p->nodes[level + 1], |
1268 | p->slots[level + 1], | 1340 | p->slots[level + 1], |
1269 | &b); | 1341 | &b, prealloc_block.objectid); |
1342 | prealloc_block.objectid = 0; | ||
1270 | if (wret) { | 1343 | if (wret) { |
1271 | free_extent_buffer(b); | 1344 | free_extent_buffer(b); |
1272 | return wret; | 1345 | ret = wret; |
1346 | goto done; | ||
1273 | } | 1347 | } |
1274 | } | 1348 | } |
1349 | cow_done: | ||
1275 | BUG_ON(!cow && ins_len); | 1350 | BUG_ON(!cow && ins_len); |
1276 | if (level != btrfs_header_level(b)) | 1351 | if (level != btrfs_header_level(b)) |
1277 | WARN_ON(1); | 1352 | WARN_ON(1); |
1278 | level = btrfs_header_level(b); | 1353 | level = btrfs_header_level(b); |
1354 | |||
1279 | p->nodes[level] = b; | 1355 | p->nodes[level] = b; |
1280 | if (!p->skip_locking) | 1356 | if (!p->skip_locking) |
1281 | p->locks[level] = 1; | 1357 | p->locks[level] = 1; |
1358 | |||
1282 | ret = check_block(root, p, level); | 1359 | ret = check_block(root, p, level); |
1283 | if (ret) | 1360 | if (ret) { |
1284 | return -1; | 1361 | ret = -1; |
1362 | goto done; | ||
1363 | } | ||
1285 | 1364 | ||
1286 | ret = bin_search(b, key, level, &slot); | 1365 | ret = bin_search(b, key, level, &slot); |
1287 | if (level != 0) { | 1366 | if (level != 0) { |
@@ -1292,15 +1371,19 @@ again: | |||
1292 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { | 1371 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { |
1293 | int sret = split_node(trans, root, p, level); | 1372 | int sret = split_node(trans, root, p, level); |
1294 | BUG_ON(sret > 0); | 1373 | BUG_ON(sret > 0); |
1295 | if (sret) | 1374 | if (sret) { |
1296 | return sret; | 1375 | ret = sret; |
1376 | goto done; | ||
1377 | } | ||
1297 | b = p->nodes[level]; | 1378 | b = p->nodes[level]; |
1298 | slot = p->slots[level]; | 1379 | slot = p->slots[level]; |
1299 | } else if (ins_len < 0) { | 1380 | } else if (ins_len < 0) { |
1300 | int sret = balance_level(trans, root, p, | 1381 | int sret = balance_level(trans, root, p, |
1301 | level); | 1382 | level); |
1302 | if (sret) | 1383 | if (sret) { |
1303 | return sret; | 1384 | ret = sret; |
1385 | goto done; | ||
1386 | } | ||
1304 | b = p->nodes[level]; | 1387 | b = p->nodes[level]; |
1305 | if (!b) { | 1388 | if (!b) { |
1306 | btrfs_release_path(NULL, p); | 1389 | btrfs_release_path(NULL, p); |
@@ -1362,14 +1445,24 @@ again: | |||
1362 | int sret = split_leaf(trans, root, key, | 1445 | int sret = split_leaf(trans, root, key, |
1363 | p, ins_len, ret == 0); | 1446 | p, ins_len, ret == 0); |
1364 | BUG_ON(sret > 0); | 1447 | BUG_ON(sret > 0); |
1365 | if (sret) | 1448 | if (sret) { |
1366 | return sret; | 1449 | ret = sret; |
1450 | goto done; | ||
1451 | } | ||
1367 | } | 1452 | } |
1368 | unlock_up(p, level, lowest_unlock); | 1453 | unlock_up(p, level, lowest_unlock); |
1369 | return ret; | 1454 | goto done; |
1370 | } | 1455 | } |
1371 | } | 1456 | } |
1372 | return 1; | 1457 | ret = 1; |
1458 | done: | ||
1459 | if (prealloc_block.objectid) { | ||
1460 | btrfs_free_reserved_extent(root, | ||
1461 | prealloc_block.objectid, | ||
1462 | prealloc_block.offset); | ||
1463 | } | ||
1464 | |||
1465 | return ret; | ||
1373 | } | 1466 | } |
1374 | 1467 | ||
1375 | /* | 1468 | /* |
@@ -1840,7 +1933,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1840 | 1933 | ||
1841 | /* cow and double check */ | 1934 | /* cow and double check */ |
1842 | ret = btrfs_cow_block(trans, root, right, upper, | 1935 | ret = btrfs_cow_block(trans, root, right, upper, |
1843 | slot + 1, &right); | 1936 | slot + 1, &right, 0); |
1844 | if (ret) | 1937 | if (ret) |
1845 | goto out_unlock; | 1938 | goto out_unlock; |
1846 | 1939 | ||
@@ -2021,7 +2114,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2021 | 2114 | ||
2022 | /* cow and double check */ | 2115 | /* cow and double check */ |
2023 | ret = btrfs_cow_block(trans, root, left, | 2116 | ret = btrfs_cow_block(trans, root, left, |
2024 | path->nodes[1], slot - 1, &left); | 2117 | path->nodes[1], slot - 1, &left, 0); |
2025 | if (ret) { | 2118 | if (ret) { |
2026 | /* we hit -ENOSPC, but it isn't fatal here */ | 2119 | /* we hit -ENOSPC, but it isn't fatal here */ |
2027 | ret = 1; | 2120 | ret = 1; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d788ab0dcd96..9b025960bbde 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1421,6 +1421,9 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1421 | int level, | 1421 | int level, |
1422 | u64 hint, | 1422 | u64 hint, |
1423 | u64 empty_size); | 1423 | u64 empty_size); |
1424 | struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, | ||
1425 | struct btrfs_root *root, | ||
1426 | u64 bytenr, u32 blocksize); | ||
1424 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size); | 1427 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size); |
1425 | int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans, | 1428 | int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans, |
1426 | struct btrfs_root *root, | 1429 | struct btrfs_root *root, |
@@ -1451,6 +1454,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1451 | *root, u64 bytenr, u64 num_bytes, | 1454 | *root, u64 bytenr, u64 num_bytes, |
1452 | u64 root_objectid, u64 ref_generation, | 1455 | u64 root_objectid, u64 ref_generation, |
1453 | u64 owner_objectid, u64 owner_offset, int pin); | 1456 | u64 owner_objectid, u64 owner_offset, int pin); |
1457 | int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); | ||
1454 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | 1458 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, |
1455 | struct btrfs_root *root, | 1459 | struct btrfs_root *root, |
1456 | struct extent_io_tree *unpin); | 1460 | struct extent_io_tree *unpin); |
@@ -1484,7 +1488,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, | |||
1484 | int btrfs_cow_block(struct btrfs_trans_handle *trans, | 1488 | int btrfs_cow_block(struct btrfs_trans_handle *trans, |
1485 | struct btrfs_root *root, struct extent_buffer *buf, | 1489 | struct btrfs_root *root, struct extent_buffer *buf, |
1486 | struct extent_buffer *parent, int parent_slot, | 1490 | struct extent_buffer *parent, int parent_slot, |
1487 | struct extent_buffer **cow_ret); | 1491 | struct extent_buffer **cow_ret, u64 prealloc_dest); |
1488 | int btrfs_copy_root(struct btrfs_trans_handle *trans, | 1492 | int btrfs_copy_root(struct btrfs_trans_handle *trans, |
1489 | struct btrfs_root *root, | 1493 | struct btrfs_root *root, |
1490 | struct extent_buffer *buf, | 1494 | struct extent_buffer *buf, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 74bcd48a9c43..98a1c0faedae 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2118,6 +2118,15 @@ again: | |||
2118 | return 0; | 2118 | return 0; |
2119 | } | 2119 | } |
2120 | 2120 | ||
2121 | int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) | ||
2122 | { | ||
2123 | maybe_lock_mutex(root); | ||
2124 | set_extent_dirty(&root->fs_info->free_space_cache, | ||
2125 | start, start + len - 1, GFP_NOFS); | ||
2126 | maybe_unlock_mutex(root); | ||
2127 | return 0; | ||
2128 | } | ||
2129 | |||
2121 | int btrfs_reserve_extent(struct btrfs_trans_handle *trans, | 2130 | int btrfs_reserve_extent(struct btrfs_trans_handle *trans, |
2122 | struct btrfs_root *root, | 2131 | struct btrfs_root *root, |
2123 | u64 num_bytes, u64 min_alloc_size, | 2132 | u64 num_bytes, u64 min_alloc_size, |
@@ -2267,6 +2276,26 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
2267 | maybe_unlock_mutex(root); | 2276 | maybe_unlock_mutex(root); |
2268 | return ret; | 2277 | return ret; |
2269 | } | 2278 | } |
2279 | |||
2280 | struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, | ||
2281 | struct btrfs_root *root, | ||
2282 | u64 bytenr, u32 blocksize) | ||
2283 | { | ||
2284 | struct extent_buffer *buf; | ||
2285 | |||
2286 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | ||
2287 | if (!buf) | ||
2288 | return ERR_PTR(-ENOMEM); | ||
2289 | btrfs_set_header_generation(buf, trans->transid); | ||
2290 | btrfs_tree_lock(buf); | ||
2291 | clean_tree_block(trans, root, buf); | ||
2292 | btrfs_set_buffer_uptodate(buf); | ||
2293 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | ||
2294 | buf->start + buf->len - 1, GFP_NOFS); | ||
2295 | trans->blocks_used++; | ||
2296 | return buf; | ||
2297 | } | ||
2298 | |||
2270 | /* | 2299 | /* |
2271 | * helper function to allocate a block for a given tree | 2300 | * helper function to allocate a block for a given tree |
2272 | * returns the tree buffer or NULL. | 2301 | * returns the tree buffer or NULL. |
@@ -2293,26 +2322,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
2293 | BUG_ON(ret > 0); | 2322 | BUG_ON(ret > 0); |
2294 | return ERR_PTR(ret); | 2323 | return ERR_PTR(ret); |
2295 | } | 2324 | } |
2296 | buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize); | ||
2297 | if (!buf) { | ||
2298 | btrfs_free_extent(trans, root, ins.objectid, blocksize, | ||
2299 | root->root_key.objectid, ref_generation, | ||
2300 | 0, 0, 0); | ||
2301 | return ERR_PTR(-ENOMEM); | ||
2302 | } | ||
2303 | btrfs_set_header_generation(buf, trans->transid); | ||
2304 | btrfs_tree_lock(buf); | ||
2305 | clean_tree_block(trans, root, buf); | ||
2306 | btrfs_set_buffer_uptodate(buf); | ||
2307 | |||
2308 | if (PageDirty(buf->first_page)) { | ||
2309 | printk("page %lu dirty\n", buf->first_page->index); | ||
2310 | WARN_ON(1); | ||
2311 | } | ||
2312 | 2325 | ||
2313 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 2326 | buf = btrfs_init_new_buffer(trans, root, ins.objectid, blocksize); |
2314 | buf->start + buf->len - 1, GFP_NOFS); | ||
2315 | trans->blocks_used++; | ||
2316 | return buf; | 2327 | return buf; |
2317 | } | 2328 | } |
2318 | 2329 | ||
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index d43e14c7471a..0cc314c10d66 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c | |||
@@ -56,3 +56,19 @@ int btrfs_tree_locked(struct extent_buffer *eb) | |||
56 | { | 56 | { |
57 | return mutex_is_locked(&eb->mutex); | 57 | return mutex_is_locked(&eb->mutex); |
58 | } | 58 | } |
59 | |||
60 | int btrfs_path_lock_waiting(struct btrfs_path *path, int level) | ||
61 | { | ||
62 | int i; | ||
63 | struct extent_buffer *eb; | ||
64 | for (i = level; i <= level + 1 && i < BTRFS_MAX_LEVEL; i++) { | ||
65 | eb = path->nodes[i]; | ||
66 | if (!eb) | ||
67 | break; | ||
68 | smp_mb(); | ||
69 | if (!list_empty(&eb->mutex.wait_list)) | ||
70 | return 1; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h index 2dab96d8280e..bc1faef12519 100644 --- a/fs/btrfs/locking.h +++ b/fs/btrfs/locking.h | |||
@@ -23,4 +23,5 @@ int btrfs_tree_lock(struct extent_buffer *eb); | |||
23 | int btrfs_tree_unlock(struct extent_buffer *eb); | 23 | int btrfs_tree_unlock(struct extent_buffer *eb); |
24 | int btrfs_tree_locked(struct extent_buffer *eb); | 24 | int btrfs_tree_locked(struct extent_buffer *eb); |
25 | int btrfs_try_tree_lock(struct extent_buffer *eb); | 25 | int btrfs_try_tree_lock(struct extent_buffer *eb); |
26 | int btrfs_path_lock_waiting(struct btrfs_path *path, int level); | ||
26 | #endif | 27 | #endif |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index a68779499302..9d84daf10008 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -622,7 +622,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
622 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 622 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
623 | 623 | ||
624 | old = btrfs_lock_root_node(root); | 624 | old = btrfs_lock_root_node(root); |
625 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | 625 | btrfs_cow_block(trans, root, old, NULL, 0, &old, 0); |
626 | 626 | ||
627 | btrfs_copy_root(trans, root, old, &tmp, objectid); | 627 | btrfs_copy_root(trans, root, old, &tmp, objectid); |
628 | btrfs_tree_unlock(old); | 628 | btrfs_tree_unlock(old); |