diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-06-22 14:16:25 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-06-22 14:16:25 -0400 |
commit | 54aa1f4dfdacd60a19c4471220b24e581be6f774 (patch) | |
tree | 1462277822cc63c00ad31b522457363a5c6be6ab /fs/btrfs/extent-tree.c | |
parent | 11bd143fc8243cf48c934dc1c4479a5aacf58ce3 (diff) |
Btrfs: Audit callers and return codes to make sure -ENOSPC gets up the stack
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 141 |
1 files changed, 115 insertions, 26 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b38c3e92f0c8..8025e9f8ef19 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -100,6 +100,8 @@ static int cache_block_group(struct btrfs_root *root, | |||
100 | if (slot >= btrfs_header_nritems(&leaf->header)) { | 100 | if (slot >= btrfs_header_nritems(&leaf->header)) { |
101 | reada_extent_leaves(root, path, limit); | 101 | reada_extent_leaves(root, path, limit); |
102 | ret = btrfs_next_leaf(root, path); | 102 | ret = btrfs_next_leaf(root, path); |
103 | if (ret < 0) | ||
104 | goto err; | ||
103 | if (ret == 0) { | 105 | if (ret == 0) { |
104 | continue; | 106 | continue; |
105 | } else { | 107 | } else { |
@@ -148,6 +150,7 @@ static int cache_block_group(struct btrfs_root *root, | |||
148 | } | 150 | } |
149 | 151 | ||
150 | block_group->cached = 1; | 152 | block_group->cached = 1; |
153 | err: | ||
151 | btrfs_free_path(path); | 154 | btrfs_free_path(path); |
152 | return 0; | 155 | return 0; |
153 | } | 156 | } |
@@ -201,7 +204,9 @@ static u64 find_search_start(struct btrfs_root *root, | |||
201 | last = max(last, cache->last_prealloc); | 204 | last = max(last, cache->last_prealloc); |
202 | } | 205 | } |
203 | again: | 206 | again: |
204 | cache_block_group(root, cache); | 207 | ret = cache_block_group(root, cache); |
208 | if (ret) | ||
209 | goto out; | ||
205 | while(1) { | 210 | while(1) { |
206 | ret = find_first_radix_bit(&root->fs_info->extent_map_radix, | 211 | ret = find_first_radix_bit(&root->fs_info->extent_map_radix, |
207 | gang, last, ARRAY_SIZE(gang)); | 212 | gang, last, ARRAY_SIZE(gang)); |
@@ -398,16 +403,23 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
398 | struct btrfs_key ins; | 403 | struct btrfs_key ins; |
399 | u32 refs; | 404 | u32 refs; |
400 | 405 | ||
401 | find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, | ||
402 | &ins, 0); | ||
403 | path = btrfs_alloc_path(); | 406 | path = btrfs_alloc_path(); |
404 | BUG_ON(!path); | 407 | if (!path) |
408 | return -ENOMEM; | ||
409 | ret = find_free_extent(trans, root->fs_info->extent_root, 0, 0, | ||
410 | (u64)-1, 0, &ins, 0); | ||
411 | if (ret) { | ||
412 | btrfs_free_path(path); | ||
413 | return ret; | ||
414 | } | ||
405 | key.objectid = blocknr; | 415 | key.objectid = blocknr; |
406 | key.flags = 0; | 416 | key.flags = 0; |
407 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 417 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
408 | key.offset = num_blocks; | 418 | key.offset = num_blocks; |
409 | ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, | 419 | ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, |
410 | 0, 1); | 420 | 0, 1); |
421 | if (ret < 0) | ||
422 | return ret; | ||
411 | if (ret != 0) { | 423 | if (ret != 0) { |
412 | BUG(); | 424 | BUG(); |
413 | } | 425 | } |
@@ -442,12 +454,14 @@ static int lookup_extent_ref(struct btrfs_trans_handle *trans, | |||
442 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 454 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
443 | ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, | 455 | ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, |
444 | 0, 0); | 456 | 0, 0); |
457 | if (ret < 0) | ||
458 | goto out; | ||
445 | if (ret != 0) | 459 | if (ret != 0) |
446 | BUG(); | 460 | BUG(); |
447 | l = btrfs_buffer_leaf(path->nodes[0]); | 461 | l = btrfs_buffer_leaf(path->nodes[0]); |
448 | item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); | 462 | item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); |
449 | *refs = btrfs_extent_refs(item); | 463 | *refs = btrfs_extent_refs(item); |
450 | btrfs_release_path(root->fs_info->extent_root, path); | 464 | out: |
451 | btrfs_free_path(path); | 465 | btrfs_free_path(path); |
452 | return 0; | 466 | return 0; |
453 | } | 467 | } |
@@ -469,6 +483,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
469 | int i; | 483 | int i; |
470 | int leaf; | 484 | int leaf; |
471 | int ret; | 485 | int ret; |
486 | int faili; | ||
487 | int err; | ||
472 | 488 | ||
473 | if (!root->ref_cows) | 489 | if (!root->ref_cows) |
474 | return 0; | 490 | return 0; |
@@ -491,14 +507,45 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
491 | continue; | 507 | continue; |
492 | ret = btrfs_inc_extent_ref(trans, root, disk_blocknr, | 508 | ret = btrfs_inc_extent_ref(trans, root, disk_blocknr, |
493 | btrfs_file_extent_disk_num_blocks(fi)); | 509 | btrfs_file_extent_disk_num_blocks(fi)); |
494 | BUG_ON(ret); | 510 | if (ret) { |
511 | faili = i; | ||
512 | goto fail; | ||
513 | } | ||
495 | } else { | 514 | } else { |
496 | blocknr = btrfs_node_blockptr(buf_node, i); | 515 | blocknr = btrfs_node_blockptr(buf_node, i); |
497 | ret = btrfs_inc_extent_ref(trans, root, blocknr, 1); | 516 | ret = btrfs_inc_extent_ref(trans, root, blocknr, 1); |
498 | BUG_ON(ret); | 517 | if (ret) { |
518 | faili = i; | ||
519 | goto fail; | ||
520 | } | ||
499 | } | 521 | } |
500 | } | 522 | } |
501 | return 0; | 523 | return 0; |
524 | fail: | ||
525 | for (i =0; i < faili; i++) { | ||
526 | if (leaf) { | ||
527 | u64 disk_blocknr; | ||
528 | key = &buf_leaf->items[i].key; | ||
529 | if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY) | ||
530 | continue; | ||
531 | fi = btrfs_item_ptr(buf_leaf, i, | ||
532 | struct btrfs_file_extent_item); | ||
533 | if (btrfs_file_extent_type(fi) == | ||
534 | BTRFS_FILE_EXTENT_INLINE) | ||
535 | continue; | ||
536 | disk_blocknr = btrfs_file_extent_disk_blocknr(fi); | ||
537 | if (disk_blocknr == 0) | ||
538 | continue; | ||
539 | err = btrfs_free_extent(trans, root, disk_blocknr, | ||
540 | btrfs_file_extent_disk_num_blocks(fi), 0); | ||
541 | BUG_ON(err); | ||
542 | } else { | ||
543 | blocknr = btrfs_node_blockptr(buf_node, i); | ||
544 | err = btrfs_free_extent(trans, root, blocknr, 1, 0); | ||
545 | BUG_ON(err); | ||
546 | } | ||
547 | } | ||
548 | return ret; | ||
502 | } | 549 | } |
503 | 550 | ||
504 | static int write_one_cache_group(struct btrfs_trans_handle *trans, | 551 | static int write_one_cache_group(struct btrfs_trans_handle *trans, |
@@ -512,15 +559,20 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
512 | struct btrfs_block_group_item *bi; | 559 | struct btrfs_block_group_item *bi; |
513 | struct btrfs_key ins; | 560 | struct btrfs_key ins; |
514 | 561 | ||
515 | find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); | 562 | ret = find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); |
563 | /* FIXME, set bit to recalc cache groups on next mount */ | ||
564 | if (ret) | ||
565 | return ret; | ||
516 | ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); | 566 | ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); |
567 | if (ret < 0) | ||
568 | goto fail; | ||
517 | BUG_ON(ret); | 569 | BUG_ON(ret); |
518 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 570 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
519 | struct btrfs_block_group_item); | 571 | struct btrfs_block_group_item); |
520 | memcpy(bi, &cache->item, sizeof(*bi)); | 572 | memcpy(bi, &cache->item, sizeof(*bi)); |
521 | mark_buffer_dirty(path->nodes[0]); | 573 | mark_buffer_dirty(path->nodes[0]); |
522 | btrfs_release_path(extent_root, path); | 574 | btrfs_release_path(extent_root, path); |
523 | 575 | fail: | |
524 | finish_current_insert(trans, extent_root); | 576 | finish_current_insert(trans, extent_root); |
525 | pending_ret = del_pending_extents(trans, extent_root); | 577 | pending_ret = del_pending_extents(trans, extent_root); |
526 | if (ret) | 578 | if (ret) |
@@ -543,6 +595,7 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, | |||
543 | int werr = 0; | 595 | int werr = 0; |
544 | int i; | 596 | int i; |
545 | struct btrfs_path *path; | 597 | struct btrfs_path *path; |
598 | unsigned long off = 0; | ||
546 | 599 | ||
547 | path = btrfs_alloc_path(); | 600 | path = btrfs_alloc_path(); |
548 | if (!path) | 601 | if (!path) |
@@ -550,18 +603,28 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, | |||
550 | 603 | ||
551 | while(1) { | 604 | while(1) { |
552 | ret = radix_tree_gang_lookup_tag(radix, (void **)cache, | 605 | ret = radix_tree_gang_lookup_tag(radix, (void **)cache, |
553 | 0, ARRAY_SIZE(cache), | 606 | off, ARRAY_SIZE(cache), |
554 | BTRFS_BLOCK_GROUP_DIRTY); | 607 | BTRFS_BLOCK_GROUP_DIRTY); |
555 | if (!ret) | 608 | if (!ret) |
556 | break; | 609 | break; |
557 | for (i = 0; i < ret; i++) { | 610 | for (i = 0; i < ret; i++) { |
558 | radix_tree_tag_clear(radix, cache[i]->key.objectid + | ||
559 | cache[i]->key.offset - 1, | ||
560 | BTRFS_BLOCK_GROUP_DIRTY); | ||
561 | err = write_one_cache_group(trans, root, | 611 | err = write_one_cache_group(trans, root, |
562 | path, cache[i]); | 612 | path, cache[i]); |
563 | if (err) | 613 | /* |
614 | * if we fail to write the cache group, we want | ||
615 | * to keep it marked dirty in hopes that a later | ||
616 | * write will work | ||
617 | */ | ||
618 | if (err) { | ||
564 | werr = err; | 619 | werr = err; |
620 | off = cache[i]->key.objectid + | ||
621 | cache[i]->key.offset; | ||
622 | continue; | ||
623 | } | ||
624 | |||
625 | radix_tree_tag_clear(radix, cache[i]->key.objectid + | ||
626 | cache[i]->key.offset - 1, | ||
627 | BTRFS_BLOCK_GROUP_DIRTY); | ||
565 | } | 628 | } |
566 | } | 629 | } |
567 | btrfs_free_path(path); | 630 | btrfs_free_path(path); |
@@ -801,14 +864,20 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
801 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 864 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
802 | key.offset = num_blocks; | 865 | key.offset = num_blocks; |
803 | 866 | ||
804 | find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); | ||
805 | path = btrfs_alloc_path(); | 867 | path = btrfs_alloc_path(); |
806 | BUG_ON(!path); | 868 | if (!path) |
869 | return -ENOMEM; | ||
807 | 870 | ||
808 | ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); | 871 | ret = find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); |
809 | if (ret) { | 872 | if (ret) { |
810 | BUG(); | 873 | btrfs_free_path(path); |
874 | return ret; | ||
811 | } | 875 | } |
876 | |||
877 | ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); | ||
878 | if (ret < 0) | ||
879 | return ret; | ||
880 | BUG_ON(ret); | ||
812 | ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 881 | ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
813 | struct btrfs_extent_item); | 882 | struct btrfs_extent_item); |
814 | BUG_ON(ei->refs == 0); | 883 | BUG_ON(ei->refs == 0); |
@@ -827,8 +896,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
827 | btrfs_set_super_blocks_used(info->disk_super, | 896 | btrfs_set_super_blocks_used(info->disk_super, |
828 | super_blocks_used - num_blocks); | 897 | super_blocks_used - num_blocks); |
829 | ret = btrfs_del_item(trans, extent_root, path); | 898 | ret = btrfs_del_item(trans, extent_root, path); |
830 | if (ret) | 899 | if (ret) { |
831 | BUG(); | 900 | return ret; |
901 | } | ||
832 | ret = update_block_group(trans, root, blocknr, num_blocks, 0, | 902 | ret = update_block_group(trans, root, blocknr, num_blocks, 0, |
833 | mark_free, 0); | 903 | mark_free, 0); |
834 | BUG_ON(ret); | 904 | BUG_ON(ret); |
@@ -1075,7 +1145,6 @@ next: | |||
1075 | path->slots[0]++; | 1145 | path->slots[0]++; |
1076 | cond_resched(); | 1146 | cond_resched(); |
1077 | } | 1147 | } |
1078 | // FIXME -ENOSPC | ||
1079 | check_pending: | 1148 | check_pending: |
1080 | /* we have to make sure we didn't find an extent that has already | 1149 | /* we have to make sure we didn't find an extent that has already |
1081 | * been allocated by the map tree or the original allocation | 1150 | * been allocated by the map tree or the original allocation |
@@ -1246,7 +1315,15 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1246 | ret = find_free_extent(trans, root, num_blocks, search_start, | 1315 | ret = find_free_extent(trans, root, num_blocks, search_start, |
1247 | search_end, hint_block, ins, data); | 1316 | search_end, hint_block, ins, data); |
1248 | if (ret) { | 1317 | if (ret) { |
1249 | return ret; | 1318 | if (search_start == 0) |
1319 | return ret; | ||
1320 | search_end = search_start - 1; | ||
1321 | search_start = 0; | ||
1322 | hint_block = search_start; | ||
1323 | ret = find_free_extent(trans, root, num_blocks, search_start, | ||
1324 | search_end, hint_block, ins, data); | ||
1325 | if (ret) | ||
1326 | return ret; | ||
1250 | } | 1327 | } |
1251 | 1328 | ||
1252 | /* | 1329 | /* |
@@ -1271,7 +1348,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1271 | search_end, hint_block, | 1348 | search_end, hint_block, |
1272 | &prealloc_key, 0); | 1349 | &prealloc_key, 0); |
1273 | if (ret) { | 1350 | if (ret) { |
1274 | return ret; | 1351 | if (search_start == 0) |
1352 | return ret; | ||
1353 | search_end = search_start - 1; | ||
1354 | search_start = 0; | ||
1355 | hint_block = search_start; | ||
1356 | ret = find_free_extent(trans, root, 0, search_start, | ||
1357 | search_end, hint_block, | ||
1358 | &prealloc_key, 0); | ||
1359 | if (ret) | ||
1360 | return ret; | ||
1275 | } | 1361 | } |
1276 | } | 1362 | } |
1277 | 1363 | ||
@@ -1309,11 +1395,14 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1309 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 1395 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
1310 | 1, hint, (unsigned long)-1, &ins, 0); | 1396 | 1, hint, (unsigned long)-1, &ins, 0); |
1311 | if (ret) { | 1397 | if (ret) { |
1312 | BUG(); | 1398 | BUG_ON(ret > 0); |
1313 | return NULL; | 1399 | return ERR_PTR(ret); |
1314 | } | 1400 | } |
1315 | BUG_ON(ret); | ||
1316 | buf = btrfs_find_create_tree_block(root, ins.objectid); | 1401 | buf = btrfs_find_create_tree_block(root, ins.objectid); |
1402 | if (!buf) { | ||
1403 | btrfs_free_extent(trans, root, ins.objectid, 1, 0); | ||
1404 | return ERR_PTR(-ENOMEM); | ||
1405 | } | ||
1317 | set_buffer_uptodate(buf); | 1406 | set_buffer_uptodate(buf); |
1318 | set_buffer_checked(buf); | 1407 | set_buffer_checked(buf); |
1319 | set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); | 1408 | set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); |