diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 291 |
1 files changed, 268 insertions, 23 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 761717c98278..a61f8a6cf219 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1134,10 +1134,12 @@ static int find_and_setup_root(struct btrfs_root *tree_root, | |||
1134 | 1134 | ||
1135 | generation = btrfs_root_generation(&root->root_item); | 1135 | generation = btrfs_root_generation(&root->root_item); |
1136 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); | 1136 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
1137 | root->commit_root = NULL; | ||
1137 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 1138 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
1138 | blocksize, generation); | 1139 | blocksize, generation); |
1139 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { | 1140 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { |
1140 | free_extent_buffer(root->node); | 1141 | free_extent_buffer(root->node); |
1142 | root->node = NULL; | ||
1141 | return -EIO; | 1143 | return -EIO; |
1142 | } | 1144 | } |
1143 | root->commit_root = btrfs_root_node(root); | 1145 | root->commit_root = btrfs_root_node(root); |
@@ -1576,6 +1578,228 @@ sleep: | |||
1576 | return 0; | 1578 | return 0; |
1577 | } | 1579 | } |
1578 | 1580 | ||
1581 | /* | ||
1582 | * this will find the highest generation in the array of | ||
1583 | * root backups. The index of the highest array is returned, | ||
1584 | * or -1 if we can't find anything. | ||
1585 | * | ||
1586 | * We check to make sure the array is valid by comparing the | ||
1587 | * generation of the latest root in the array with the generation | ||
1588 | * in the super block. If they don't match we pitch it. | ||
1589 | */ | ||
1590 | static int find_newest_super_backup(struct btrfs_fs_info *info, u64 newest_gen) | ||
1591 | { | ||
1592 | u64 cur; | ||
1593 | int newest_index = -1; | ||
1594 | struct btrfs_root_backup *root_backup; | ||
1595 | int i; | ||
1596 | |||
1597 | for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) { | ||
1598 | root_backup = info->super_copy->super_roots + i; | ||
1599 | cur = btrfs_backup_tree_root_gen(root_backup); | ||
1600 | if (cur == newest_gen) | ||
1601 | newest_index = i; | ||
1602 | } | ||
1603 | |||
1604 | /* check to see if we actually wrapped around */ | ||
1605 | if (newest_index == BTRFS_NUM_BACKUP_ROOTS - 1) { | ||
1606 | root_backup = info->super_copy->super_roots; | ||
1607 | cur = btrfs_backup_tree_root_gen(root_backup); | ||
1608 | if (cur == newest_gen) | ||
1609 | newest_index = 0; | ||
1610 | } | ||
1611 | return newest_index; | ||
1612 | } | ||
1613 | |||
1614 | |||
1615 | /* | ||
1616 | * find the oldest backup so we know where to store new entries | ||
1617 | * in the backup array. This will set the backup_root_index | ||
1618 | * field in the fs_info struct | ||
1619 | */ | ||
1620 | static void find_oldest_super_backup(struct btrfs_fs_info *info, | ||
1621 | u64 newest_gen) | ||
1622 | { | ||
1623 | int newest_index = -1; | ||
1624 | |||
1625 | newest_index = find_newest_super_backup(info, newest_gen); | ||
1626 | /* if there was garbage in there, just move along */ | ||
1627 | if (newest_index == -1) { | ||
1628 | info->backup_root_index = 0; | ||
1629 | } else { | ||
1630 | info->backup_root_index = (newest_index + 1) % BTRFS_NUM_BACKUP_ROOTS; | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | /* | ||
1635 | * copy all the root pointers into the super backup array. | ||
1636 | * this will bump the backup pointer by one when it is | ||
1637 | * done | ||
1638 | */ | ||
1639 | static void backup_super_roots(struct btrfs_fs_info *info) | ||
1640 | { | ||
1641 | int next_backup; | ||
1642 | struct btrfs_root_backup *root_backup; | ||
1643 | int last_backup; | ||
1644 | |||
1645 | next_backup = info->backup_root_index; | ||
1646 | last_backup = (next_backup + BTRFS_NUM_BACKUP_ROOTS - 1) % | ||
1647 | BTRFS_NUM_BACKUP_ROOTS; | ||
1648 | |||
1649 | /* | ||
1650 | * just overwrite the last backup if we're at the same generation | ||
1651 | * this happens only at umount | ||
1652 | */ | ||
1653 | root_backup = info->super_for_commit->super_roots + last_backup; | ||
1654 | if (btrfs_backup_tree_root_gen(root_backup) == | ||
1655 | btrfs_header_generation(info->tree_root->node)) | ||
1656 | next_backup = last_backup; | ||
1657 | |||
1658 | root_backup = info->super_for_commit->super_roots + next_backup; | ||
1659 | |||
1660 | /* | ||
1661 | * make sure all of our padding and empty slots get zero filled | ||
1662 | * regardless of which ones we use today | ||
1663 | */ | ||
1664 | memset(root_backup, 0, sizeof(*root_backup)); | ||
1665 | |||
1666 | info->backup_root_index = (next_backup + 1) % BTRFS_NUM_BACKUP_ROOTS; | ||
1667 | |||
1668 | btrfs_set_backup_tree_root(root_backup, info->tree_root->node->start); | ||
1669 | btrfs_set_backup_tree_root_gen(root_backup, | ||
1670 | btrfs_header_generation(info->tree_root->node)); | ||
1671 | |||
1672 | btrfs_set_backup_tree_root_level(root_backup, | ||
1673 | btrfs_header_level(info->tree_root->node)); | ||
1674 | |||
1675 | btrfs_set_backup_chunk_root(root_backup, info->chunk_root->node->start); | ||
1676 | btrfs_set_backup_chunk_root_gen(root_backup, | ||
1677 | btrfs_header_generation(info->chunk_root->node)); | ||
1678 | btrfs_set_backup_chunk_root_level(root_backup, | ||
1679 | btrfs_header_level(info->chunk_root->node)); | ||
1680 | |||
1681 | btrfs_set_backup_extent_root(root_backup, info->extent_root->node->start); | ||
1682 | btrfs_set_backup_extent_root_gen(root_backup, | ||
1683 | btrfs_header_generation(info->extent_root->node)); | ||
1684 | btrfs_set_backup_extent_root_level(root_backup, | ||
1685 | btrfs_header_level(info->extent_root->node)); | ||
1686 | |||
1687 | btrfs_set_backup_fs_root(root_backup, info->fs_root->node->start); | ||
1688 | btrfs_set_backup_fs_root_gen(root_backup, | ||
1689 | btrfs_header_generation(info->fs_root->node)); | ||
1690 | btrfs_set_backup_fs_root_level(root_backup, | ||
1691 | btrfs_header_level(info->fs_root->node)); | ||
1692 | |||
1693 | btrfs_set_backup_dev_root(root_backup, info->dev_root->node->start); | ||
1694 | btrfs_set_backup_dev_root_gen(root_backup, | ||
1695 | btrfs_header_generation(info->dev_root->node)); | ||
1696 | btrfs_set_backup_dev_root_level(root_backup, | ||
1697 | btrfs_header_level(info->dev_root->node)); | ||
1698 | |||
1699 | btrfs_set_backup_csum_root(root_backup, info->csum_root->node->start); | ||
1700 | btrfs_set_backup_csum_root_gen(root_backup, | ||
1701 | btrfs_header_generation(info->csum_root->node)); | ||
1702 | btrfs_set_backup_csum_root_level(root_backup, | ||
1703 | btrfs_header_level(info->csum_root->node)); | ||
1704 | |||
1705 | btrfs_set_backup_total_bytes(root_backup, | ||
1706 | btrfs_super_total_bytes(info->super_copy)); | ||
1707 | btrfs_set_backup_bytes_used(root_backup, | ||
1708 | btrfs_super_bytes_used(info->super_copy)); | ||
1709 | btrfs_set_backup_num_devices(root_backup, | ||
1710 | btrfs_super_num_devices(info->super_copy)); | ||
1711 | |||
1712 | /* | ||
1713 | * if we don't copy this out to the super_copy, it won't get remembered | ||
1714 | * for the next commit | ||
1715 | */ | ||
1716 | memcpy(&info->super_copy->super_roots, | ||
1717 | &info->super_for_commit->super_roots, | ||
1718 | sizeof(*root_backup) * BTRFS_NUM_BACKUP_ROOTS); | ||
1719 | } | ||
1720 | |||
1721 | /* | ||
1722 | * this copies info out of the root backup array and back into | ||
1723 | * the in-memory super block. It is meant to help iterate through | ||
1724 | * the array, so you send it the number of backups you've already | ||
1725 | * tried and the last backup index you used. | ||
1726 | * | ||
1727 | * this returns -1 when it has tried all the backups | ||
1728 | */ | ||
1729 | static noinline int next_root_backup(struct btrfs_fs_info *info, | ||
1730 | struct btrfs_super_block *super, | ||
1731 | int *num_backups_tried, int *backup_index) | ||
1732 | { | ||
1733 | struct btrfs_root_backup *root_backup; | ||
1734 | int newest = *backup_index; | ||
1735 | |||
1736 | if (*num_backups_tried == 0) { | ||
1737 | u64 gen = btrfs_super_generation(super); | ||
1738 | |||
1739 | newest = find_newest_super_backup(info, gen); | ||
1740 | if (newest == -1) | ||
1741 | return -1; | ||
1742 | |||
1743 | *backup_index = newest; | ||
1744 | *num_backups_tried = 1; | ||
1745 | } else if (*num_backups_tried == BTRFS_NUM_BACKUP_ROOTS) { | ||
1746 | /* we've tried all the backups, all done */ | ||
1747 | return -1; | ||
1748 | } else { | ||
1749 | /* jump to the next oldest backup */ | ||
1750 | newest = (*backup_index + BTRFS_NUM_BACKUP_ROOTS - 1) % | ||
1751 | BTRFS_NUM_BACKUP_ROOTS; | ||
1752 | *backup_index = newest; | ||
1753 | *num_backups_tried += 1; | ||
1754 | } | ||
1755 | root_backup = super->super_roots + newest; | ||
1756 | |||
1757 | btrfs_set_super_generation(super, | ||
1758 | btrfs_backup_tree_root_gen(root_backup)); | ||
1759 | btrfs_set_super_root(super, btrfs_backup_tree_root(root_backup)); | ||
1760 | btrfs_set_super_root_level(super, | ||
1761 | btrfs_backup_tree_root_level(root_backup)); | ||
1762 | btrfs_set_super_bytes_used(super, btrfs_backup_bytes_used(root_backup)); | ||
1763 | |||
1764 | /* | ||
1765 | * fixme: the total bytes and num_devices need to match or we should | ||
1766 | * need a fsck | ||
1767 | */ | ||
1768 | btrfs_set_super_total_bytes(super, btrfs_backup_total_bytes(root_backup)); | ||
1769 | btrfs_set_super_num_devices(super, btrfs_backup_num_devices(root_backup)); | ||
1770 | return 0; | ||
1771 | } | ||
1772 | |||
1773 | /* helper to cleanup tree roots */ | ||
1774 | static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) | ||
1775 | { | ||
1776 | free_extent_buffer(info->tree_root->node); | ||
1777 | free_extent_buffer(info->tree_root->commit_root); | ||
1778 | free_extent_buffer(info->dev_root->node); | ||
1779 | free_extent_buffer(info->dev_root->commit_root); | ||
1780 | free_extent_buffer(info->extent_root->node); | ||
1781 | free_extent_buffer(info->extent_root->commit_root); | ||
1782 | free_extent_buffer(info->csum_root->node); | ||
1783 | free_extent_buffer(info->csum_root->commit_root); | ||
1784 | |||
1785 | info->tree_root->node = NULL; | ||
1786 | info->tree_root->commit_root = NULL; | ||
1787 | info->dev_root->node = NULL; | ||
1788 | info->dev_root->commit_root = NULL; | ||
1789 | info->extent_root->node = NULL; | ||
1790 | info->extent_root->commit_root = NULL; | ||
1791 | info->csum_root->node = NULL; | ||
1792 | info->csum_root->commit_root = NULL; | ||
1793 | |||
1794 | if (chunk_root) { | ||
1795 | free_extent_buffer(info->chunk_root->node); | ||
1796 | free_extent_buffer(info->chunk_root->commit_root); | ||
1797 | info->chunk_root->node = NULL; | ||
1798 | info->chunk_root->commit_root = NULL; | ||
1799 | } | ||
1800 | } | ||
1801 | |||
1802 | |||
1579 | struct btrfs_root *open_ctree(struct super_block *sb, | 1803 | struct btrfs_root *open_ctree(struct super_block *sb, |
1580 | struct btrfs_fs_devices *fs_devices, | 1804 | struct btrfs_fs_devices *fs_devices, |
1581 | char *options) | 1805 | char *options) |
@@ -1603,6 +1827,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1603 | 1827 | ||
1604 | int ret; | 1828 | int ret; |
1605 | int err = -EINVAL; | 1829 | int err = -EINVAL; |
1830 | int num_backups_tried = 0; | ||
1831 | int backup_index = 0; | ||
1606 | 1832 | ||
1607 | struct btrfs_super_block *disk_super; | 1833 | struct btrfs_super_block *disk_super; |
1608 | 1834 | ||
@@ -1782,6 +2008,13 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1782 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); | 2008 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); |
1783 | 2009 | ||
1784 | /* | 2010 | /* |
2011 | * run through our array of backup supers and setup | ||
2012 | * our ring pointer to the oldest one | ||
2013 | */ | ||
2014 | generation = btrfs_super_generation(disk_super); | ||
2015 | find_oldest_super_backup(fs_info, generation); | ||
2016 | |||
2017 | /* | ||
1785 | * In the long term, we'll store the compression type in the super | 2018 | * In the long term, we'll store the compression type in the super |
1786 | * block, and it'll be used for per file compression control. | 2019 | * block, and it'll be used for per file compression control. |
1787 | */ | 2020 | */ |
@@ -1938,7 +2171,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1938 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { | 2171 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { |
1939 | printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", | 2172 | printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", |
1940 | sb->s_id); | 2173 | sb->s_id); |
1941 | goto fail_chunk_root; | 2174 | goto fail_tree_roots; |
1942 | } | 2175 | } |
1943 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); | 2176 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); |
1944 | chunk_root->commit_root = btrfs_root_node(chunk_root); | 2177 | chunk_root->commit_root = btrfs_root_node(chunk_root); |
@@ -1953,11 +2186,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1953 | if (ret) { | 2186 | if (ret) { |
1954 | printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", | 2187 | printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", |
1955 | sb->s_id); | 2188 | sb->s_id); |
1956 | goto fail_chunk_root; | 2189 | goto fail_tree_roots; |
1957 | } | 2190 | } |
1958 | 2191 | ||
1959 | btrfs_close_extra_devices(fs_devices); | 2192 | btrfs_close_extra_devices(fs_devices); |
1960 | 2193 | ||
2194 | retry_root_backup: | ||
1961 | blocksize = btrfs_level_size(tree_root, | 2195 | blocksize = btrfs_level_size(tree_root, |
1962 | btrfs_super_root_level(disk_super)); | 2196 | btrfs_super_root_level(disk_super)); |
1963 | generation = btrfs_super_generation(disk_super); | 2197 | generation = btrfs_super_generation(disk_super); |
@@ -1965,32 +2199,33 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1965 | tree_root->node = read_tree_block(tree_root, | 2199 | tree_root->node = read_tree_block(tree_root, |
1966 | btrfs_super_root(disk_super), | 2200 | btrfs_super_root(disk_super), |
1967 | blocksize, generation); | 2201 | blocksize, generation); |
1968 | if (!tree_root->node) | 2202 | if (!tree_root->node || |
1969 | goto fail_chunk_root; | 2203 | !test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { |
1970 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { | ||
1971 | printk(KERN_WARNING "btrfs: failed to read tree root on %s\n", | 2204 | printk(KERN_WARNING "btrfs: failed to read tree root on %s\n", |
1972 | sb->s_id); | 2205 | sb->s_id); |
1973 | goto fail_tree_root; | 2206 | |
2207 | goto recovery_tree_root; | ||
1974 | } | 2208 | } |
2209 | |||
1975 | btrfs_set_root_node(&tree_root->root_item, tree_root->node); | 2210 | btrfs_set_root_node(&tree_root->root_item, tree_root->node); |
1976 | tree_root->commit_root = btrfs_root_node(tree_root); | 2211 | tree_root->commit_root = btrfs_root_node(tree_root); |
1977 | 2212 | ||
1978 | ret = find_and_setup_root(tree_root, fs_info, | 2213 | ret = find_and_setup_root(tree_root, fs_info, |
1979 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); | 2214 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); |
1980 | if (ret) | 2215 | if (ret) |
1981 | goto fail_tree_root; | 2216 | goto recovery_tree_root; |
1982 | extent_root->track_dirty = 1; | 2217 | extent_root->track_dirty = 1; |
1983 | 2218 | ||
1984 | ret = find_and_setup_root(tree_root, fs_info, | 2219 | ret = find_and_setup_root(tree_root, fs_info, |
1985 | BTRFS_DEV_TREE_OBJECTID, dev_root); | 2220 | BTRFS_DEV_TREE_OBJECTID, dev_root); |
1986 | if (ret) | 2221 | if (ret) |
1987 | goto fail_extent_root; | 2222 | goto recovery_tree_root; |
1988 | dev_root->track_dirty = 1; | 2223 | dev_root->track_dirty = 1; |
1989 | 2224 | ||
1990 | ret = find_and_setup_root(tree_root, fs_info, | 2225 | ret = find_and_setup_root(tree_root, fs_info, |
1991 | BTRFS_CSUM_TREE_OBJECTID, csum_root); | 2226 | BTRFS_CSUM_TREE_OBJECTID, csum_root); |
1992 | if (ret) | 2227 | if (ret) |
1993 | goto fail_dev_root; | 2228 | goto recovery_tree_root; |
1994 | 2229 | ||
1995 | csum_root->track_dirty = 1; | 2230 | csum_root->track_dirty = 1; |
1996 | 2231 | ||
@@ -2123,20 +2358,10 @@ fail_cleaner: | |||
2123 | 2358 | ||
2124 | fail_block_groups: | 2359 | fail_block_groups: |
2125 | btrfs_free_block_groups(fs_info); | 2360 | btrfs_free_block_groups(fs_info); |
2126 | free_extent_buffer(csum_root->node); | 2361 | |
2127 | free_extent_buffer(csum_root->commit_root); | 2362 | fail_tree_roots: |
2128 | fail_dev_root: | 2363 | free_root_pointers(fs_info, 1); |
2129 | free_extent_buffer(dev_root->node); | 2364 | |
2130 | free_extent_buffer(dev_root->commit_root); | ||
2131 | fail_extent_root: | ||
2132 | free_extent_buffer(extent_root->node); | ||
2133 | free_extent_buffer(extent_root->commit_root); | ||
2134 | fail_tree_root: | ||
2135 | free_extent_buffer(tree_root->node); | ||
2136 | free_extent_buffer(tree_root->commit_root); | ||
2137 | fail_chunk_root: | ||
2138 | free_extent_buffer(chunk_root->node); | ||
2139 | free_extent_buffer(chunk_root->commit_root); | ||
2140 | fail_sb_buffer: | 2365 | fail_sb_buffer: |
2141 | btrfs_stop_workers(&fs_info->generic_worker); | 2366 | btrfs_stop_workers(&fs_info->generic_worker); |
2142 | btrfs_stop_workers(&fs_info->fixup_workers); | 2367 | btrfs_stop_workers(&fs_info->fixup_workers); |
@@ -2164,6 +2389,25 @@ fail_srcu: | |||
2164 | fail: | 2389 | fail: |
2165 | free_fs_info(fs_info); | 2390 | free_fs_info(fs_info); |
2166 | return ERR_PTR(err); | 2391 | return ERR_PTR(err); |
2392 | |||
2393 | recovery_tree_root: | ||
2394 | |||
2395 | if (!btrfs_test_opt(tree_root, RECOVERY)) | ||
2396 | goto fail_tree_roots; | ||
2397 | |||
2398 | free_root_pointers(fs_info, 0); | ||
2399 | |||
2400 | /* don't use the log in recovery mode, it won't be valid */ | ||
2401 | btrfs_set_super_log_root(disk_super, 0); | ||
2402 | |||
2403 | /* we can't trust the free space cache either */ | ||
2404 | btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE); | ||
2405 | |||
2406 | ret = next_root_backup(fs_info, fs_info->super_copy, | ||
2407 | &num_backups_tried, &backup_index); | ||
2408 | if (ret == -1) | ||
2409 | goto fail_block_groups; | ||
2410 | goto retry_root_backup; | ||
2167 | } | 2411 | } |
2168 | 2412 | ||
2169 | static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) | 2413 | static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) |
@@ -2333,6 +2577,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
2333 | 2577 | ||
2334 | max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; | 2578 | max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; |
2335 | do_barriers = !btrfs_test_opt(root, NOBARRIER); | 2579 | do_barriers = !btrfs_test_opt(root, NOBARRIER); |
2580 | backup_super_roots(root->fs_info); | ||
2336 | 2581 | ||
2337 | sb = root->fs_info->super_for_commit; | 2582 | sb = root->fs_info->super_for_commit; |
2338 | dev_item = &sb->dev_item; | 2583 | dev_item = &sb->dev_item; |