diff options
-rw-r--r-- | fs/btrfs/relocation.c | 70 |
1 files changed, 47 insertions, 23 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index ce459a7cb16d..7cdc76007c6c 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -1264,10 +1264,10 @@ static int __must_check __add_reloc_root(struct btrfs_root *root) | |||
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | /* | 1266 | /* |
1267 | * helper to update/delete the 'address of tree root -> reloc tree' | 1267 | * helper to delete the 'address of tree root -> reloc tree' |
1268 | * mapping | 1268 | * mapping |
1269 | */ | 1269 | */ |
1270 | static int __update_reloc_root(struct btrfs_root *root, int del) | 1270 | static void __del_reloc_root(struct btrfs_root *root) |
1271 | { | 1271 | { |
1272 | struct rb_node *rb_node; | 1272 | struct rb_node *rb_node; |
1273 | struct mapping_node *node = NULL; | 1273 | struct mapping_node *node = NULL; |
@@ -1275,7 +1275,7 @@ static int __update_reloc_root(struct btrfs_root *root, int del) | |||
1275 | 1275 | ||
1276 | spin_lock(&rc->reloc_root_tree.lock); | 1276 | spin_lock(&rc->reloc_root_tree.lock); |
1277 | rb_node = tree_search(&rc->reloc_root_tree.rb_root, | 1277 | rb_node = tree_search(&rc->reloc_root_tree.rb_root, |
1278 | root->commit_root->start); | 1278 | root->node->start); |
1279 | if (rb_node) { | 1279 | if (rb_node) { |
1280 | node = rb_entry(rb_node, struct mapping_node, rb_node); | 1280 | node = rb_entry(rb_node, struct mapping_node, rb_node); |
1281 | rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); | 1281 | rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); |
@@ -1283,23 +1283,45 @@ static int __update_reloc_root(struct btrfs_root *root, int del) | |||
1283 | spin_unlock(&rc->reloc_root_tree.lock); | 1283 | spin_unlock(&rc->reloc_root_tree.lock); |
1284 | 1284 | ||
1285 | if (!node) | 1285 | if (!node) |
1286 | return 0; | 1286 | return; |
1287 | BUG_ON((struct btrfs_root *)node->data != root); | 1287 | BUG_ON((struct btrfs_root *)node->data != root); |
1288 | 1288 | ||
1289 | if (!del) { | 1289 | spin_lock(&root->fs_info->trans_lock); |
1290 | spin_lock(&rc->reloc_root_tree.lock); | 1290 | list_del_init(&root->root_list); |
1291 | node->bytenr = root->node->start; | 1291 | spin_unlock(&root->fs_info->trans_lock); |
1292 | rb_node = tree_insert(&rc->reloc_root_tree.rb_root, | 1292 | kfree(node); |
1293 | node->bytenr, &node->rb_node); | 1293 | } |
1294 | spin_unlock(&rc->reloc_root_tree.lock); | 1294 | |
1295 | if (rb_node) | 1295 | /* |
1296 | backref_tree_panic(rb_node, -EEXIST, node->bytenr); | 1296 | * helper to update the 'address of tree root -> reloc tree' |
1297 | } else { | 1297 | * mapping |
1298 | spin_lock(&root->fs_info->trans_lock); | 1298 | */ |
1299 | list_del_init(&root->root_list); | 1299 | static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) |
1300 | spin_unlock(&root->fs_info->trans_lock); | 1300 | { |
1301 | kfree(node); | 1301 | struct rb_node *rb_node; |
1302 | struct mapping_node *node = NULL; | ||
1303 | struct reloc_control *rc = root->fs_info->reloc_ctl; | ||
1304 | |||
1305 | spin_lock(&rc->reloc_root_tree.lock); | ||
1306 | rb_node = tree_search(&rc->reloc_root_tree.rb_root, | ||
1307 | root->node->start); | ||
1308 | if (rb_node) { | ||
1309 | node = rb_entry(rb_node, struct mapping_node, rb_node); | ||
1310 | rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); | ||
1302 | } | 1311 | } |
1312 | spin_unlock(&rc->reloc_root_tree.lock); | ||
1313 | |||
1314 | if (!node) | ||
1315 | return 0; | ||
1316 | BUG_ON((struct btrfs_root *)node->data != root); | ||
1317 | |||
1318 | spin_lock(&rc->reloc_root_tree.lock); | ||
1319 | node->bytenr = new_bytenr; | ||
1320 | rb_node = tree_insert(&rc->reloc_root_tree.rb_root, | ||
1321 | node->bytenr, &node->rb_node); | ||
1322 | spin_unlock(&rc->reloc_root_tree.lock); | ||
1323 | if (rb_node) | ||
1324 | backref_tree_panic(rb_node, -EEXIST, node->bytenr); | ||
1303 | return 0; | 1325 | return 0; |
1304 | } | 1326 | } |
1305 | 1327 | ||
@@ -1420,7 +1442,6 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, | |||
1420 | { | 1442 | { |
1421 | struct btrfs_root *reloc_root; | 1443 | struct btrfs_root *reloc_root; |
1422 | struct btrfs_root_item *root_item; | 1444 | struct btrfs_root_item *root_item; |
1423 | int del = 0; | ||
1424 | int ret; | 1445 | int ret; |
1425 | 1446 | ||
1426 | if (!root->reloc_root) | 1447 | if (!root->reloc_root) |
@@ -1432,11 +1453,9 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, | |||
1432 | if (root->fs_info->reloc_ctl->merge_reloc_tree && | 1453 | if (root->fs_info->reloc_ctl->merge_reloc_tree && |
1433 | btrfs_root_refs(root_item) == 0) { | 1454 | btrfs_root_refs(root_item) == 0) { |
1434 | root->reloc_root = NULL; | 1455 | root->reloc_root = NULL; |
1435 | del = 1; | 1456 | __del_reloc_root(reloc_root); |
1436 | } | 1457 | } |
1437 | 1458 | ||
1438 | __update_reloc_root(reloc_root, del); | ||
1439 | |||
1440 | if (reloc_root->commit_root != reloc_root->node) { | 1459 | if (reloc_root->commit_root != reloc_root->node) { |
1441 | btrfs_set_root_node(root_item, reloc_root->node); | 1460 | btrfs_set_root_node(root_item, reloc_root->node); |
1442 | free_extent_buffer(reloc_root->commit_root); | 1461 | free_extent_buffer(reloc_root->commit_root); |
@@ -2287,7 +2306,7 @@ void free_reloc_roots(struct list_head *list) | |||
2287 | while (!list_empty(list)) { | 2306 | while (!list_empty(list)) { |
2288 | reloc_root = list_entry(list->next, struct btrfs_root, | 2307 | reloc_root = list_entry(list->next, struct btrfs_root, |
2289 | root_list); | 2308 | root_list); |
2290 | __update_reloc_root(reloc_root, 1); | 2309 | __del_reloc_root(reloc_root); |
2291 | free_extent_buffer(reloc_root->node); | 2310 | free_extent_buffer(reloc_root->node); |
2292 | free_extent_buffer(reloc_root->commit_root); | 2311 | free_extent_buffer(reloc_root->commit_root); |
2293 | kfree(reloc_root); | 2312 | kfree(reloc_root); |
@@ -2332,7 +2351,7 @@ again: | |||
2332 | 2351 | ||
2333 | ret = merge_reloc_root(rc, root); | 2352 | ret = merge_reloc_root(rc, root); |
2334 | if (ret) { | 2353 | if (ret) { |
2335 | __update_reloc_root(reloc_root, 1); | 2354 | __del_reloc_root(reloc_root); |
2336 | free_extent_buffer(reloc_root->node); | 2355 | free_extent_buffer(reloc_root->node); |
2337 | free_extent_buffer(reloc_root->commit_root); | 2356 | free_extent_buffer(reloc_root->commit_root); |
2338 | kfree(reloc_root); | 2357 | kfree(reloc_root); |
@@ -4522,6 +4541,11 @@ int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, | |||
4522 | BUG_ON(rc->stage == UPDATE_DATA_PTRS && | 4541 | BUG_ON(rc->stage == UPDATE_DATA_PTRS && |
4523 | root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); | 4542 | root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); |
4524 | 4543 | ||
4544 | if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { | ||
4545 | if (buf == root->node) | ||
4546 | __update_reloc_root(root, cow->start); | ||
4547 | } | ||
4548 | |||
4525 | level = btrfs_header_level(buf); | 4549 | level = btrfs_header_level(buf); |
4526 | if (btrfs_header_generation(buf) <= | 4550 | if (btrfs_header_generation(buf) <= |
4527 | btrfs_root_last_snapshot(&root->root_item)) | 4551 | btrfs_root_last_snapshot(&root->root_item)) |