diff options
-rw-r--r-- | fs/btrfs/ctree.h | 95 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 291 | ||||
-rw-r--r-- | fs/btrfs/super.c | 7 |
3 files changed, 369 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5181c53c1124..78f43d1102a0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -361,6 +361,47 @@ struct btrfs_header { | |||
361 | #define BTRFS_LABEL_SIZE 256 | 361 | #define BTRFS_LABEL_SIZE 256 |
362 | 362 | ||
363 | /* | 363 | /* |
364 | * just in case we somehow lose the roots and are not able to mount, | ||
365 | * we store an array of the roots from previous transactions | ||
366 | * in the super. | ||
367 | */ | ||
368 | #define BTRFS_NUM_BACKUP_ROOTS 4 | ||
369 | struct btrfs_root_backup { | ||
370 | __le64 tree_root; | ||
371 | __le64 tree_root_gen; | ||
372 | |||
373 | __le64 chunk_root; | ||
374 | __le64 chunk_root_gen; | ||
375 | |||
376 | __le64 extent_root; | ||
377 | __le64 extent_root_gen; | ||
378 | |||
379 | __le64 fs_root; | ||
380 | __le64 fs_root_gen; | ||
381 | |||
382 | __le64 dev_root; | ||
383 | __le64 dev_root_gen; | ||
384 | |||
385 | __le64 csum_root; | ||
386 | __le64 csum_root_gen; | ||
387 | |||
388 | __le64 total_bytes; | ||
389 | __le64 bytes_used; | ||
390 | __le64 num_devices; | ||
391 | /* future */ | ||
392 | __le64 unsed_64[4]; | ||
393 | |||
394 | u8 tree_root_level; | ||
395 | u8 chunk_root_level; | ||
396 | u8 extent_root_level; | ||
397 | u8 fs_root_level; | ||
398 | u8 dev_root_level; | ||
399 | u8 csum_root_level; | ||
400 | /* future and to align */ | ||
401 | u8 unused_8[10]; | ||
402 | } __attribute__ ((__packed__)); | ||
403 | |||
404 | /* | ||
364 | * the super block basically lists the main trees of the FS | 405 | * the super block basically lists the main trees of the FS |
365 | * it currently lacks any block count etc etc | 406 | * it currently lacks any block count etc etc |
366 | */ | 407 | */ |
@@ -406,6 +447,7 @@ struct btrfs_super_block { | |||
406 | /* future expansion */ | 447 | /* future expansion */ |
407 | __le64 reserved[31]; | 448 | __le64 reserved[31]; |
408 | u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; | 449 | u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; |
450 | struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; | ||
409 | } __attribute__ ((__packed__)); | 451 | } __attribute__ ((__packed__)); |
410 | 452 | ||
411 | /* | 453 | /* |
@@ -1113,6 +1155,9 @@ struct btrfs_fs_info { | |||
1113 | u64 fs_state; | 1155 | u64 fs_state; |
1114 | 1156 | ||
1115 | struct btrfs_delayed_root *delayed_root; | 1157 | struct btrfs_delayed_root *delayed_root; |
1158 | |||
1159 | /* next backup root to be overwritten */ | ||
1160 | int backup_root_index; | ||
1116 | }; | 1161 | }; |
1117 | 1162 | ||
1118 | /* | 1163 | /* |
@@ -1357,6 +1402,7 @@ struct btrfs_ioctl_defrag_range_args { | |||
1357 | #define BTRFS_MOUNT_ENOSPC_DEBUG (1 << 15) | 1402 | #define BTRFS_MOUNT_ENOSPC_DEBUG (1 << 15) |
1358 | #define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16) | 1403 | #define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16) |
1359 | #define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17) | 1404 | #define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17) |
1405 | #define BTRFS_MOUNT_RECOVERY (1 << 18) | ||
1360 | 1406 | ||
1361 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) | 1407 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) |
1362 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) | 1408 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) |
@@ -1972,6 +2018,55 @@ static inline bool btrfs_root_readonly(struct btrfs_root *root) | |||
1972 | return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; | 2018 | return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; |
1973 | } | 2019 | } |
1974 | 2020 | ||
2021 | /* struct btrfs_root_backup */ | ||
2022 | BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, | ||
2023 | tree_root, 64); | ||
2024 | BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, | ||
2025 | tree_root_gen, 64); | ||
2026 | BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, | ||
2027 | tree_root_level, 8); | ||
2028 | |||
2029 | BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, | ||
2030 | chunk_root, 64); | ||
2031 | BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, | ||
2032 | chunk_root_gen, 64); | ||
2033 | BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, | ||
2034 | chunk_root_level, 8); | ||
2035 | |||
2036 | BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, | ||
2037 | extent_root, 64); | ||
2038 | BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, | ||
2039 | extent_root_gen, 64); | ||
2040 | BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, | ||
2041 | extent_root_level, 8); | ||
2042 | |||
2043 | BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, | ||
2044 | fs_root, 64); | ||
2045 | BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, | ||
2046 | fs_root_gen, 64); | ||
2047 | BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, | ||
2048 | fs_root_level, 8); | ||
2049 | |||
2050 | BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, | ||
2051 | dev_root, 64); | ||
2052 | BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, | ||
2053 | dev_root_gen, 64); | ||
2054 | BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, | ||
2055 | dev_root_level, 8); | ||
2056 | |||
2057 | BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, | ||
2058 | csum_root, 64); | ||
2059 | BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, | ||
2060 | csum_root_gen, 64); | ||
2061 | BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, | ||
2062 | csum_root_level, 8); | ||
2063 | BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, | ||
2064 | total_bytes, 64); | ||
2065 | BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, | ||
2066 | bytes_used, 64); | ||
2067 | BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, | ||
2068 | num_devices, 64); | ||
2069 | |||
1975 | /* struct btrfs_super_block */ | 2070 | /* struct btrfs_super_block */ |
1976 | 2071 | ||
1977 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); | 2072 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); |
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; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f7e9de724ef2..57080dffdfc6 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -164,7 +164,7 @@ enum { | |||
164 | Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, | 164 | Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, |
165 | Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, | 165 | Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, |
166 | Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, | 166 | Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, |
167 | Opt_inode_cache, Opt_no_space_cache, Opt_err, | 167 | Opt_inode_cache, Opt_no_space_cache, Opt_recovery, Opt_err, |
168 | }; | 168 | }; |
169 | 169 | ||
170 | static match_table_t tokens = { | 170 | static match_table_t tokens = { |
@@ -198,6 +198,7 @@ static match_table_t tokens = { | |||
198 | {Opt_defrag, "autodefrag"}, | 198 | {Opt_defrag, "autodefrag"}, |
199 | {Opt_inode_cache, "inode_cache"}, | 199 | {Opt_inode_cache, "inode_cache"}, |
200 | {Opt_no_space_cache, "no_space_cache"}, | 200 | {Opt_no_space_cache, "no_space_cache"}, |
201 | {Opt_recovery, "recovery"}, | ||
201 | {Opt_err, NULL}, | 202 | {Opt_err, NULL}, |
202 | }; | 203 | }; |
203 | 204 | ||
@@ -392,6 +393,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) | |||
392 | printk(KERN_INFO "btrfs: enabling auto defrag"); | 393 | printk(KERN_INFO "btrfs: enabling auto defrag"); |
393 | btrfs_set_opt(info->mount_opt, AUTO_DEFRAG); | 394 | btrfs_set_opt(info->mount_opt, AUTO_DEFRAG); |
394 | break; | 395 | break; |
396 | case Opt_recovery: | ||
397 | printk(KERN_INFO "btrfs: enabling auto recovery"); | ||
398 | btrfs_set_opt(info->mount_opt, RECOVERY); | ||
399 | break; | ||
395 | case Opt_err: | 400 | case Opt_err: |
396 | printk(KERN_INFO "btrfs: unrecognized mount option " | 401 | printk(KERN_INFO "btrfs: unrecognized mount option " |
397 | "'%s'\n", p); | 402 | "'%s'\n", p); |