diff options
author | Chris Mason <chris.mason@oracle.com> | 2010-10-24 11:01:27 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-10-29 09:31:30 -0400 |
commit | cb44921a09221f0a90217b44044448f63190f3e5 (patch) | |
tree | 5580522b6db6868c02d3072320e338442272cb2b | |
parent | 6b5b817f103450444f3f658a498f435d92a197e5 (diff) |
Btrfs: don't loop forever on bad btree blocks
When btrfs discovers the generation number in a btree block is
incorrect, it can loop forever without forcing the RAID
code to try a valid mirror, and without returning EIO.
This changes things to properly kick out the EIO.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c3df14ce2cc2..6921231e0efb 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1577,13 +1577,33 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1577 | blocksize = btrfs_level_size(root, level - 1); | 1577 | blocksize = btrfs_level_size(root, level - 1); |
1578 | 1578 | ||
1579 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1579 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
1580 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | 1580 | if (tmp) { |
1581 | /* | 1581 | if (btrfs_buffer_uptodate(tmp, 0)) { |
1582 | * we found an up to date block without sleeping, return | 1582 | if (btrfs_buffer_uptodate(tmp, gen)) { |
1583 | * right away | 1583 | /* |
1584 | */ | 1584 | * we found an up to date block without |
1585 | *eb_ret = tmp; | 1585 | * sleeping, return |
1586 | return 0; | 1586 | * right away |
1587 | */ | ||
1588 | *eb_ret = tmp; | ||
1589 | return 0; | ||
1590 | } | ||
1591 | /* the pages were up to date, but we failed | ||
1592 | * the generation number check. Do a full | ||
1593 | * read for the generation number that is correct. | ||
1594 | * We must do this without dropping locks so | ||
1595 | * we can trust our generation number | ||
1596 | */ | ||
1597 | free_extent_buffer(tmp); | ||
1598 | tmp = read_tree_block(root, blocknr, blocksize, gen); | ||
1599 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | ||
1600 | *eb_ret = tmp; | ||
1601 | return 0; | ||
1602 | } | ||
1603 | free_extent_buffer(tmp); | ||
1604 | btrfs_release_path(NULL, p); | ||
1605 | return -EIO; | ||
1606 | } | ||
1587 | } | 1607 | } |
1588 | 1608 | ||
1589 | /* | 1609 | /* |
@@ -1596,8 +1616,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1596 | btrfs_unlock_up_safe(p, level + 1); | 1616 | btrfs_unlock_up_safe(p, level + 1); |
1597 | btrfs_set_path_blocking(p); | 1617 | btrfs_set_path_blocking(p); |
1598 | 1618 | ||
1599 | if (tmp) | 1619 | free_extent_buffer(tmp); |
1600 | free_extent_buffer(tmp); | ||
1601 | if (p->reada) | 1620 | if (p->reada) |
1602 | reada_for_search(root, p, level, slot, key->objectid); | 1621 | reada_for_search(root, p, level, slot, key->objectid); |
1603 | 1622 | ||