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/ctree.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/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 106 |
1 files changed, 82 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 498dea0854c1..606a19b5916d 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -73,6 +73,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
73 | { | 73 | { |
74 | struct buffer_head *cow; | 74 | struct buffer_head *cow; |
75 | struct btrfs_node *cow_node; | 75 | struct btrfs_node *cow_node; |
76 | int ret; | ||
76 | 77 | ||
77 | if (btrfs_header_generation(btrfs_buffer_header(buf)) == | 78 | if (btrfs_header_generation(btrfs_buffer_header(buf)) == |
78 | trans->transid) { | 79 | trans->transid) { |
@@ -80,6 +81,8 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
80 | return 0; | 81 | return 0; |
81 | } | 82 | } |
82 | cow = btrfs_alloc_free_block(trans, root, buf->b_blocknr); | 83 | cow = btrfs_alloc_free_block(trans, root, buf->b_blocknr); |
84 | if (IS_ERR(cow)) | ||
85 | return PTR_ERR(cow); | ||
83 | cow_node = btrfs_buffer_node(cow); | 86 | cow_node = btrfs_buffer_node(cow); |
84 | if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) | 87 | if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) |
85 | WARN_ON(1); | 88 | WARN_ON(1); |
@@ -87,7 +90,9 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
87 | btrfs_set_header_blocknr(&cow_node->header, bh_blocknr(cow)); | 90 | btrfs_set_header_blocknr(&cow_node->header, bh_blocknr(cow)); |
88 | btrfs_set_header_generation(&cow_node->header, trans->transid); | 91 | btrfs_set_header_generation(&cow_node->header, trans->transid); |
89 | btrfs_set_header_owner(&cow_node->header, root->root_key.objectid); | 92 | btrfs_set_header_owner(&cow_node->header, root->root_key.objectid); |
90 | btrfs_inc_ref(trans, root, buf); | 93 | ret = btrfs_inc_ref(trans, root, buf); |
94 | if (ret) | ||
95 | return ret; | ||
91 | if (buf == root->node) { | 96 | if (buf == root->node) { |
92 | root->node = cow; | 97 | root->node = cow; |
93 | get_bh(cow); | 98 | get_bh(cow); |
@@ -320,6 +325,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
320 | int wret; | 325 | int wret; |
321 | int pslot; | 326 | int pslot; |
322 | int orig_slot = path->slots[level]; | 327 | int orig_slot = path->slots[level]; |
328 | int err_on_enospc = 0; | ||
323 | u64 orig_ptr; | 329 | u64 orig_ptr; |
324 | 330 | ||
325 | if (level == 0) | 331 | if (level == 0) |
@@ -363,29 +369,43 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
363 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) | 369 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
364 | return 0; | 370 | return 0; |
365 | 371 | ||
372 | if (btrfs_header_nritems(&mid->header) < 2) | ||
373 | err_on_enospc = 1; | ||
374 | |||
366 | left_buf = read_node_slot(root, parent_buf, pslot - 1); | 375 | left_buf = read_node_slot(root, parent_buf, pslot - 1); |
367 | right_buf = read_node_slot(root, parent_buf, pslot + 1); | 376 | right_buf = read_node_slot(root, parent_buf, pslot + 1); |
368 | 377 | ||
369 | /* first, try to make some room in the middle buffer */ | 378 | /* first, try to make some room in the middle buffer */ |
370 | if (left_buf) { | 379 | if (left_buf) { |
371 | btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, | 380 | wret = btrfs_cow_block(trans, root, left_buf, |
372 | &left_buf); | 381 | parent_buf, pslot - 1, &left_buf); |
382 | if (wret) { | ||
383 | ret = wret; | ||
384 | goto enospc; | ||
385 | } | ||
373 | left = btrfs_buffer_node(left_buf); | 386 | left = btrfs_buffer_node(left_buf); |
374 | orig_slot += btrfs_header_nritems(&left->header); | 387 | orig_slot += btrfs_header_nritems(&left->header); |
375 | wret = push_node_left(trans, root, left_buf, mid_buf); | 388 | wret = push_node_left(trans, root, left_buf, mid_buf); |
376 | if (wret < 0) | 389 | if (wret < 0) |
377 | ret = wret; | 390 | ret = wret; |
391 | if (btrfs_header_nritems(&mid->header) < 2) | ||
392 | err_on_enospc = 1; | ||
378 | } | 393 | } |
379 | 394 | ||
380 | /* | 395 | /* |
381 | * then try to empty the right most buffer into the middle | 396 | * then try to empty the right most buffer into the middle |
382 | */ | 397 | */ |
383 | if (right_buf) { | 398 | if (right_buf) { |
384 | btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, | 399 | wret = btrfs_cow_block(trans, root, right_buf, |
385 | &right_buf); | 400 | parent_buf, pslot + 1, &right_buf); |
401 | if (wret) { | ||
402 | ret = wret; | ||
403 | goto enospc; | ||
404 | } | ||
405 | |||
386 | right = btrfs_buffer_node(right_buf); | 406 | right = btrfs_buffer_node(right_buf); |
387 | wret = push_node_left(trans, root, mid_buf, right_buf); | 407 | wret = push_node_left(trans, root, mid_buf, right_buf); |
388 | if (wret < 0) | 408 | if (wret < 0 && wret != -ENOSPC) |
389 | ret = wret; | 409 | ret = wret; |
390 | if (btrfs_header_nritems(&right->header) == 0) { | 410 | if (btrfs_header_nritems(&right->header) == 0) { |
391 | u64 blocknr = bh_blocknr(right_buf); | 411 | u64 blocknr = bh_blocknr(right_buf); |
@@ -421,8 +441,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
421 | */ | 441 | */ |
422 | BUG_ON(!left_buf); | 442 | BUG_ON(!left_buf); |
423 | wret = balance_node_right(trans, root, mid_buf, left_buf); | 443 | wret = balance_node_right(trans, root, mid_buf, left_buf); |
424 | if (wret < 0) | 444 | if (wret < 0) { |
425 | ret = wret; | 445 | ret = wret; |
446 | goto enospc; | ||
447 | } | ||
426 | BUG_ON(wret == 1); | 448 | BUG_ON(wret == 1); |
427 | } | 449 | } |
428 | if (btrfs_header_nritems(&mid->header) == 0) { | 450 | if (btrfs_header_nritems(&mid->header) == 0) { |
@@ -467,7 +489,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
467 | btrfs_node_blockptr(btrfs_buffer_node(path->nodes[level]), | 489 | btrfs_node_blockptr(btrfs_buffer_node(path->nodes[level]), |
468 | path->slots[level])) | 490 | path->slots[level])) |
469 | BUG(); | 491 | BUG(); |
470 | 492 | enospc: | |
471 | if (right_buf) | 493 | if (right_buf) |
472 | btrfs_block_release(root, right_buf); | 494 | btrfs_block_release(root, right_buf); |
473 | if (left_buf) | 495 | if (left_buf) |
@@ -519,10 +541,15 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
519 | if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { | 541 | if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { |
520 | wret = 1; | 542 | wret = 1; |
521 | } else { | 543 | } else { |
522 | btrfs_cow_block(trans, root, left_buf, parent_buf, | 544 | ret = btrfs_cow_block(trans, root, left_buf, parent_buf, |
523 | pslot - 1, &left_buf); | 545 | pslot - 1, &left_buf); |
524 | left = btrfs_buffer_node(left_buf); | 546 | if (ret) |
525 | wret = push_node_left(trans, root, left_buf, mid_buf); | 547 | wret = 1; |
548 | else { | ||
549 | left = btrfs_buffer_node(left_buf); | ||
550 | wret = push_node_left(trans, root, | ||
551 | left_buf, mid_buf); | ||
552 | } | ||
526 | } | 553 | } |
527 | if (wret < 0) | 554 | if (wret < 0) |
528 | ret = wret; | 555 | ret = wret; |
@@ -561,11 +588,16 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
561 | if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { | 588 | if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { |
562 | wret = 1; | 589 | wret = 1; |
563 | } else { | 590 | } else { |
564 | btrfs_cow_block(trans, root, right_buf, | 591 | ret = btrfs_cow_block(trans, root, right_buf, |
565 | parent_buf, pslot + 1, &right_buf); | 592 | parent_buf, pslot + 1, |
566 | right = btrfs_buffer_node(right_buf); | 593 | &right_buf); |
567 | wret = balance_node_right(trans, root, | 594 | if (ret) |
568 | right_buf, mid_buf); | 595 | wret = 1; |
596 | else { | ||
597 | right = btrfs_buffer_node(right_buf); | ||
598 | wret = balance_node_right(trans, root, | ||
599 | right_buf, mid_buf); | ||
600 | } | ||
569 | } | 601 | } |
570 | if (wret < 0) | 602 | if (wret < 0) |
571 | ret = wret; | 603 | ret = wret; |
@@ -631,6 +663,10 @@ again: | |||
631 | p->nodes[level + 1], | 663 | p->nodes[level + 1], |
632 | p->slots[level + 1], | 664 | p->slots[level + 1], |
633 | &cow_buf); | 665 | &cow_buf); |
666 | if (wret) { | ||
667 | btrfs_block_release(root, cow_buf); | ||
668 | return wret; | ||
669 | } | ||
634 | b = cow_buf; | 670 | b = cow_buf; |
635 | c = btrfs_buffer_node(b); | 671 | c = btrfs_buffer_node(b); |
636 | } | 672 | } |
@@ -737,6 +773,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
737 | src_nritems = btrfs_header_nritems(&src->header); | 773 | src_nritems = btrfs_header_nritems(&src->header); |
738 | dst_nritems = btrfs_header_nritems(&dst->header); | 774 | dst_nritems = btrfs_header_nritems(&dst->header); |
739 | push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; | 775 | push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; |
776 | |||
740 | if (push_items <= 0) { | 777 | if (push_items <= 0) { |
741 | return 1; | 778 | return 1; |
742 | } | 779 | } |
@@ -827,6 +864,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
827 | BUG_ON(path->nodes[level-1] != root->node); | 864 | BUG_ON(path->nodes[level-1] != root->node); |
828 | 865 | ||
829 | t = btrfs_alloc_free_block(trans, root, root->node->b_blocknr); | 866 | t = btrfs_alloc_free_block(trans, root, root->node->b_blocknr); |
867 | if (IS_ERR(t)) | ||
868 | return PTR_ERR(t); | ||
830 | c = btrfs_buffer_node(t); | 869 | c = btrfs_buffer_node(t); |
831 | memset(c, 0, root->blocksize); | 870 | memset(c, 0, root->blocksize); |
832 | btrfs_set_header_nritems(&c->header, 1); | 871 | btrfs_set_header_nritems(&c->header, 1); |
@@ -929,10 +968,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | |||
929 | btrfs_header_nritems(&c->header) < | 968 | btrfs_header_nritems(&c->header) < |
930 | BTRFS_NODEPTRS_PER_BLOCK(root) - 1) | 969 | BTRFS_NODEPTRS_PER_BLOCK(root) - 1) |
931 | return 0; | 970 | return 0; |
971 | if (ret < 0) | ||
972 | return ret; | ||
932 | } | 973 | } |
933 | 974 | ||
934 | c_nritems = btrfs_header_nritems(&c->header); | 975 | c_nritems = btrfs_header_nritems(&c->header); |
935 | split_buffer = btrfs_alloc_free_block(trans, root, t->b_blocknr); | 976 | split_buffer = btrfs_alloc_free_block(trans, root, t->b_blocknr); |
977 | if (IS_ERR(split_buffer)) | ||
978 | return PTR_ERR(split_buffer); | ||
979 | |||
936 | split = btrfs_buffer_node(split_buffer); | 980 | split = btrfs_buffer_node(split_buffer); |
937 | btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); | 981 | btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); |
938 | btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); | 982 | btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); |
@@ -1022,6 +1066,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1022 | struct btrfs_item *item; | 1066 | struct btrfs_item *item; |
1023 | u32 left_nritems; | 1067 | u32 left_nritems; |
1024 | u32 right_nritems; | 1068 | u32 right_nritems; |
1069 | int ret; | ||
1025 | 1070 | ||
1026 | slot = path->slots[1]; | 1071 | slot = path->slots[1]; |
1027 | if (!path->nodes[1]) { | 1072 | if (!path->nodes[1]) { |
@@ -1041,7 +1086,12 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1041 | return 1; | 1086 | return 1; |
1042 | } | 1087 | } |
1043 | /* cow and double check */ | 1088 | /* cow and double check */ |
1044 | btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf); | 1089 | ret = btrfs_cow_block(trans, root, right_buf, upper, |
1090 | slot + 1, &right_buf); | ||
1091 | if (ret) { | ||
1092 | btrfs_block_release(root, right_buf); | ||
1093 | return 1; | ||
1094 | } | ||
1045 | right = btrfs_buffer_leaf(right_buf); | 1095 | right = btrfs_buffer_leaf(right_buf); |
1046 | free_space = btrfs_leaf_free_space(root, right); | 1096 | free_space = btrfs_leaf_free_space(root, right); |
1047 | if (free_space < data_size + sizeof(struct btrfs_item)) { | 1097 | if (free_space < data_size + sizeof(struct btrfs_item)) { |
@@ -1162,7 +1212,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1162 | } | 1212 | } |
1163 | 1213 | ||
1164 | /* cow and double check */ | 1214 | /* cow and double check */ |
1165 | btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); | 1215 | ret = btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); |
1216 | if (ret) { | ||
1217 | /* we hit -ENOSPC, but it isn't fatal here */ | ||
1218 | return 1; | ||
1219 | } | ||
1166 | left = btrfs_buffer_leaf(t); | 1220 | left = btrfs_buffer_leaf(t); |
1167 | free_space = btrfs_leaf_free_space(root, left); | 1221 | free_space = btrfs_leaf_free_space(root, left); |
1168 | if (free_space < data_size + sizeof(struct btrfs_item)) { | 1222 | if (free_space < data_size + sizeof(struct btrfs_item)) { |
@@ -1309,8 +1363,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1309 | slot = path->slots[0]; | 1363 | slot = path->slots[0]; |
1310 | nritems = btrfs_header_nritems(&l->header); | 1364 | nritems = btrfs_header_nritems(&l->header); |
1311 | mid = (nritems + 1)/ 2; | 1365 | mid = (nritems + 1)/ 2; |
1366 | |||
1312 | right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); | 1367 | right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); |
1313 | BUG_ON(!right_buffer); | 1368 | if (IS_ERR(right_buffer)) |
1369 | return PTR_ERR(right_buffer); | ||
1370 | |||
1314 | right = btrfs_buffer_leaf(right_buffer); | 1371 | right = btrfs_buffer_leaf(right_buffer); |
1315 | memset(&right->header, 0, sizeof(right->header)); | 1372 | memset(&right->header, 0, sizeof(right->header)); |
1316 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); | 1373 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); |
@@ -1407,7 +1464,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1407 | if (!double_split) | 1464 | if (!double_split) |
1408 | return ret; | 1465 | return ret; |
1409 | right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); | 1466 | right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); |
1410 | BUG_ON(!right_buffer); | 1467 | if (IS_ERR(right_buffer)) |
1468 | return PTR_ERR(right_buffer); | ||
1469 | |||
1411 | right = btrfs_buffer_leaf(right_buffer); | 1470 | right = btrfs_buffer_leaf(right_buffer); |
1412 | memset(&right->header, 0, sizeof(right->header)); | 1471 | memset(&right->header, 0, sizeof(right->header)); |
1413 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); | 1472 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); |
@@ -1655,7 +1714,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1655 | ptr, data, data_size); | 1714 | ptr, data, data_size); |
1656 | btrfs_mark_buffer_dirty(path->nodes[0]); | 1715 | btrfs_mark_buffer_dirty(path->nodes[0]); |
1657 | } | 1716 | } |
1658 | btrfs_release_path(root, path); | ||
1659 | btrfs_free_path(path); | 1717 | btrfs_free_path(path); |
1660 | return ret; | 1718 | return ret; |
1661 | } | 1719 | } |
@@ -1775,12 +1833,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1775 | slot = path->slots[1]; | 1833 | slot = path->slots[1]; |
1776 | get_bh(leaf_buf); | 1834 | get_bh(leaf_buf); |
1777 | wret = push_leaf_left(trans, root, path, 1); | 1835 | wret = push_leaf_left(trans, root, path, 1); |
1778 | if (wret < 0) | 1836 | if (wret < 0 && wret != -ENOSPC) |
1779 | ret = wret; | 1837 | ret = wret; |
1780 | if (path->nodes[0] == leaf_buf && | 1838 | if (path->nodes[0] == leaf_buf && |
1781 | btrfs_header_nritems(&leaf->header)) { | 1839 | btrfs_header_nritems(&leaf->header)) { |
1782 | wret = push_leaf_right(trans, root, path, 1); | 1840 | wret = push_leaf_right(trans, root, path, 1); |
1783 | if (wret < 0) | 1841 | if (wret < 0 && wret != -ENOSPC) |
1784 | ret = wret; | 1842 | ret = wret; |
1785 | } | 1843 | } |
1786 | if (btrfs_header_nritems(&leaf->header) == 0) { | 1844 | if (btrfs_header_nritems(&leaf->header) == 0) { |