diff options
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 246 |
1 files changed, 239 insertions, 7 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index d1dba7ce75ae..93f03ec17eec 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
30 | #include "xfs_alloc_btree.h" | 30 | #include "xfs_alloc_btree.h" |
31 | #include "xfs_ialloc_btree.h" | 31 | #include "xfs_ialloc_btree.h" |
32 | #include "xfs_btree.h" | ||
32 | #include "xfs_dinode.h" | 33 | #include "xfs_dinode.h" |
33 | #include "xfs_inode.h" | 34 | #include "xfs_inode.h" |
34 | #include "xfs_inode_item.h" | 35 | #include "xfs_inode_item.h" |
@@ -45,6 +46,14 @@ | |||
45 | #include "xfs_trace.h" | 46 | #include "xfs_trace.h" |
46 | #include "xfs_icache.h" | 47 | #include "xfs_icache.h" |
47 | 48 | ||
49 | /* Need all the magic numbers and buffer ops structures from these headers */ | ||
50 | #include "xfs_symlink.h" | ||
51 | #include "xfs_da_btree.h" | ||
52 | #include "xfs_dir2_format.h" | ||
53 | #include "xfs_dir2_priv.h" | ||
54 | #include "xfs_attr_leaf.h" | ||
55 | #include "xfs_attr_remote.h" | ||
56 | |||
48 | STATIC int | 57 | STATIC int |
49 | xlog_find_zeroed( | 58 | xlog_find_zeroed( |
50 | struct xlog *, | 59 | struct xlog *, |
@@ -1785,6 +1794,7 @@ xlog_recover_do_inode_buffer( | |||
1785 | xfs_agino_t *buffer_nextp; | 1794 | xfs_agino_t *buffer_nextp; |
1786 | 1795 | ||
1787 | trace_xfs_log_recover_buf_inode_buf(mp->m_log, buf_f); | 1796 | trace_xfs_log_recover_buf_inode_buf(mp->m_log, buf_f); |
1797 | bp->b_ops = &xfs_inode_buf_ops; | ||
1788 | 1798 | ||
1789 | inodes_per_buf = BBTOB(bp->b_io_length) >> mp->m_sb.sb_inodelog; | 1799 | inodes_per_buf = BBTOB(bp->b_io_length) >> mp->m_sb.sb_inodelog; |
1790 | for (i = 0; i < inodes_per_buf; i++) { | 1800 | for (i = 0; i < inodes_per_buf; i++) { |
@@ -1857,6 +1867,201 @@ xlog_recover_do_inode_buffer( | |||
1857 | } | 1867 | } |
1858 | 1868 | ||
1859 | /* | 1869 | /* |
1870 | * Validate the recovered buffer is of the correct type and attach the | ||
1871 | * appropriate buffer operations to them for writeback. Magic numbers are in a | ||
1872 | * few places: | ||
1873 | * the first 16 bits of the buffer (inode buffer, dquot buffer), | ||
1874 | * the first 32 bits of the buffer (most blocks), | ||
1875 | * inside a struct xfs_da_blkinfo at the start of the buffer. | ||
1876 | */ | ||
1877 | static void | ||
1878 | xlog_recovery_validate_buf_type( | ||
1879 | struct xfs_mount *mp, | ||
1880 | struct xfs_buf *bp, | ||
1881 | xfs_buf_log_format_t *buf_f) | ||
1882 | { | ||
1883 | struct xfs_da_blkinfo *info = bp->b_addr; | ||
1884 | __uint32_t magic32; | ||
1885 | __uint16_t magic16; | ||
1886 | __uint16_t magicda; | ||
1887 | |||
1888 | magic32 = be32_to_cpu(*(__be32 *)bp->b_addr); | ||
1889 | magic16 = be16_to_cpu(*(__be16*)bp->b_addr); | ||
1890 | magicda = be16_to_cpu(info->magic); | ||
1891 | switch (xfs_blft_from_flags(buf_f)) { | ||
1892 | case XFS_BLFT_BTREE_BUF: | ||
1893 | switch (magic32) { | ||
1894 | case XFS_ABTB_CRC_MAGIC: | ||
1895 | case XFS_ABTC_CRC_MAGIC: | ||
1896 | case XFS_ABTB_MAGIC: | ||
1897 | case XFS_ABTC_MAGIC: | ||
1898 | bp->b_ops = &xfs_allocbt_buf_ops; | ||
1899 | break; | ||
1900 | case XFS_IBT_CRC_MAGIC: | ||
1901 | case XFS_IBT_MAGIC: | ||
1902 | bp->b_ops = &xfs_inobt_buf_ops; | ||
1903 | break; | ||
1904 | case XFS_BMAP_CRC_MAGIC: | ||
1905 | case XFS_BMAP_MAGIC: | ||
1906 | bp->b_ops = &xfs_bmbt_buf_ops; | ||
1907 | break; | ||
1908 | default: | ||
1909 | xfs_warn(mp, "Bad btree block magic!"); | ||
1910 | ASSERT(0); | ||
1911 | break; | ||
1912 | } | ||
1913 | break; | ||
1914 | case XFS_BLFT_AGF_BUF: | ||
1915 | if (magic32 != XFS_AGF_MAGIC) { | ||
1916 | xfs_warn(mp, "Bad AGF block magic!"); | ||
1917 | ASSERT(0); | ||
1918 | break; | ||
1919 | } | ||
1920 | bp->b_ops = &xfs_agf_buf_ops; | ||
1921 | break; | ||
1922 | case XFS_BLFT_AGFL_BUF: | ||
1923 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
1924 | break; | ||
1925 | if (magic32 != XFS_AGFL_MAGIC) { | ||
1926 | xfs_warn(mp, "Bad AGFL block magic!"); | ||
1927 | ASSERT(0); | ||
1928 | break; | ||
1929 | } | ||
1930 | bp->b_ops = &xfs_agfl_buf_ops; | ||
1931 | break; | ||
1932 | case XFS_BLFT_AGI_BUF: | ||
1933 | if (magic32 != XFS_AGI_MAGIC) { | ||
1934 | xfs_warn(mp, "Bad AGI block magic!"); | ||
1935 | ASSERT(0); | ||
1936 | break; | ||
1937 | } | ||
1938 | bp->b_ops = &xfs_agi_buf_ops; | ||
1939 | break; | ||
1940 | case XFS_BLFT_UDQUOT_BUF: | ||
1941 | case XFS_BLFT_PDQUOT_BUF: | ||
1942 | case XFS_BLFT_GDQUOT_BUF: | ||
1943 | #ifdef CONFIG_XFS_QUOTA | ||
1944 | if (magic16 != XFS_DQUOT_MAGIC) { | ||
1945 | xfs_warn(mp, "Bad DQUOT block magic!"); | ||
1946 | ASSERT(0); | ||
1947 | break; | ||
1948 | } | ||
1949 | bp->b_ops = &xfs_dquot_buf_ops; | ||
1950 | #else | ||
1951 | xfs_alert(mp, | ||
1952 | "Trying to recover dquots without QUOTA support built in!"); | ||
1953 | ASSERT(0); | ||
1954 | #endif | ||
1955 | break; | ||
1956 | case XFS_BLFT_DINO_BUF: | ||
1957 | /* | ||
1958 | * we get here with inode allocation buffers, not buffers that | ||
1959 | * track unlinked list changes. | ||
1960 | */ | ||
1961 | if (magic16 != XFS_DINODE_MAGIC) { | ||
1962 | xfs_warn(mp, "Bad INODE block magic!"); | ||
1963 | ASSERT(0); | ||
1964 | break; | ||
1965 | } | ||
1966 | bp->b_ops = &xfs_inode_buf_ops; | ||
1967 | break; | ||
1968 | case XFS_BLFT_SYMLINK_BUF: | ||
1969 | if (magic32 != XFS_SYMLINK_MAGIC) { | ||
1970 | xfs_warn(mp, "Bad symlink block magic!"); | ||
1971 | ASSERT(0); | ||
1972 | break; | ||
1973 | } | ||
1974 | bp->b_ops = &xfs_symlink_buf_ops; | ||
1975 | break; | ||
1976 | case XFS_BLFT_DIR_BLOCK_BUF: | ||
1977 | if (magic32 != XFS_DIR2_BLOCK_MAGIC && | ||
1978 | magic32 != XFS_DIR3_BLOCK_MAGIC) { | ||
1979 | xfs_warn(mp, "Bad dir block magic!"); | ||
1980 | ASSERT(0); | ||
1981 | break; | ||
1982 | } | ||
1983 | bp->b_ops = &xfs_dir3_block_buf_ops; | ||
1984 | break; | ||
1985 | case XFS_BLFT_DIR_DATA_BUF: | ||
1986 | if (magic32 != XFS_DIR2_DATA_MAGIC && | ||
1987 | magic32 != XFS_DIR3_DATA_MAGIC) { | ||
1988 | xfs_warn(mp, "Bad dir data magic!"); | ||
1989 | ASSERT(0); | ||
1990 | break; | ||
1991 | } | ||
1992 | bp->b_ops = &xfs_dir3_data_buf_ops; | ||
1993 | break; | ||
1994 | case XFS_BLFT_DIR_FREE_BUF: | ||
1995 | if (magic32 != XFS_DIR2_FREE_MAGIC && | ||
1996 | magic32 != XFS_DIR3_FREE_MAGIC) { | ||
1997 | xfs_warn(mp, "Bad dir3 free magic!"); | ||
1998 | ASSERT(0); | ||
1999 | break; | ||
2000 | } | ||
2001 | bp->b_ops = &xfs_dir3_free_buf_ops; | ||
2002 | break; | ||
2003 | case XFS_BLFT_DIR_LEAF1_BUF: | ||
2004 | if (magicda != XFS_DIR2_LEAF1_MAGIC && | ||
2005 | magicda != XFS_DIR3_LEAF1_MAGIC) { | ||
2006 | xfs_warn(mp, "Bad dir leaf1 magic!"); | ||
2007 | ASSERT(0); | ||
2008 | break; | ||
2009 | } | ||
2010 | bp->b_ops = &xfs_dir3_leaf1_buf_ops; | ||
2011 | break; | ||
2012 | case XFS_BLFT_DIR_LEAFN_BUF: | ||
2013 | if (magicda != XFS_DIR2_LEAFN_MAGIC && | ||
2014 | magicda != XFS_DIR3_LEAFN_MAGIC) { | ||
2015 | xfs_warn(mp, "Bad dir leafn magic!"); | ||
2016 | ASSERT(0); | ||
2017 | break; | ||
2018 | } | ||
2019 | bp->b_ops = &xfs_dir3_leafn_buf_ops; | ||
2020 | break; | ||
2021 | case XFS_BLFT_DA_NODE_BUF: | ||
2022 | if (magicda != XFS_DA_NODE_MAGIC && | ||
2023 | magicda != XFS_DA3_NODE_MAGIC) { | ||
2024 | xfs_warn(mp, "Bad da node magic!"); | ||
2025 | ASSERT(0); | ||
2026 | break; | ||
2027 | } | ||
2028 | bp->b_ops = &xfs_da3_node_buf_ops; | ||
2029 | break; | ||
2030 | case XFS_BLFT_ATTR_LEAF_BUF: | ||
2031 | if (magicda != XFS_ATTR_LEAF_MAGIC && | ||
2032 | magicda != XFS_ATTR3_LEAF_MAGIC) { | ||
2033 | xfs_warn(mp, "Bad attr leaf magic!"); | ||
2034 | ASSERT(0); | ||
2035 | break; | ||
2036 | } | ||
2037 | bp->b_ops = &xfs_attr3_leaf_buf_ops; | ||
2038 | break; | ||
2039 | case XFS_BLFT_ATTR_RMT_BUF: | ||
2040 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
2041 | break; | ||
2042 | if (magic32 != XFS_ATTR3_RMT_MAGIC) { | ||
2043 | xfs_warn(mp, "Bad attr remote magic!"); | ||
2044 | ASSERT(0); | ||
2045 | break; | ||
2046 | } | ||
2047 | bp->b_ops = &xfs_attr3_rmt_buf_ops; | ||
2048 | break; | ||
2049 | case XFS_BLFT_SB_BUF: | ||
2050 | if (magic32 != XFS_SB_MAGIC) { | ||
2051 | xfs_warn(mp, "Bad SB block magic!"); | ||
2052 | ASSERT(0); | ||
2053 | break; | ||
2054 | } | ||
2055 | bp->b_ops = &xfs_sb_buf_ops; | ||
2056 | break; | ||
2057 | default: | ||
2058 | xfs_warn(mp, "Unknown buffer type %d!", | ||
2059 | xfs_blft_from_flags(buf_f)); | ||
2060 | break; | ||
2061 | } | ||
2062 | } | ||
2063 | |||
2064 | /* | ||
1860 | * Perform a 'normal' buffer recovery. Each logged region of the | 2065 | * Perform a 'normal' buffer recovery. Each logged region of the |
1861 | * buffer should be copied over the corresponding region in the | 2066 | * buffer should be copied over the corresponding region in the |
1862 | * given buffer. The bitmap in the buf log format structure indicates | 2067 | * given buffer. The bitmap in the buf log format structure indicates |
@@ -1928,6 +2133,8 @@ xlog_recover_do_reg_buffer( | |||
1928 | 2133 | ||
1929 | /* Shouldn't be any more regions */ | 2134 | /* Shouldn't be any more regions */ |
1930 | ASSERT(i == item->ri_total); | 2135 | ASSERT(i == item->ri_total); |
2136 | |||
2137 | xlog_recovery_validate_buf_type(mp, bp, buf_f); | ||
1931 | } | 2138 | } |
1932 | 2139 | ||
1933 | /* | 2140 | /* |
@@ -2213,6 +2420,7 @@ xlog_recover_inode_pass2( | |||
2213 | int attr_index; | 2420 | int attr_index; |
2214 | uint fields; | 2421 | uint fields; |
2215 | xfs_icdinode_t *dicp; | 2422 | xfs_icdinode_t *dicp; |
2423 | uint isize; | ||
2216 | int need_free = 0; | 2424 | int need_free = 0; |
2217 | 2425 | ||
2218 | if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) { | 2426 | if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) { |
@@ -2238,7 +2446,7 @@ xlog_recover_inode_pass2( | |||
2238 | trace_xfs_log_recover_inode_recover(log, in_f); | 2446 | trace_xfs_log_recover_inode_recover(log, in_f); |
2239 | 2447 | ||
2240 | bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0, | 2448 | bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0, |
2241 | NULL); | 2449 | &xfs_inode_buf_ops); |
2242 | if (!bp) { | 2450 | if (!bp) { |
2243 | error = ENOMEM; | 2451 | error = ENOMEM; |
2244 | goto error; | 2452 | goto error; |
@@ -2349,7 +2557,8 @@ xlog_recover_inode_pass2( | |||
2349 | error = EFSCORRUPTED; | 2557 | error = EFSCORRUPTED; |
2350 | goto error; | 2558 | goto error; |
2351 | } | 2559 | } |
2352 | if (unlikely(item->ri_buf[1].i_len > sizeof(struct xfs_icdinode))) { | 2560 | isize = xfs_icdinode_size(dicp->di_version); |
2561 | if (unlikely(item->ri_buf[1].i_len > isize)) { | ||
2353 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", | 2562 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", |
2354 | XFS_ERRLEVEL_LOW, mp, dicp); | 2563 | XFS_ERRLEVEL_LOW, mp, dicp); |
2355 | xfs_buf_relse(bp); | 2564 | xfs_buf_relse(bp); |
@@ -2361,13 +2570,13 @@ xlog_recover_inode_pass2( | |||
2361 | } | 2570 | } |
2362 | 2571 | ||
2363 | /* The core is in in-core format */ | 2572 | /* The core is in in-core format */ |
2364 | xfs_dinode_to_disk(dip, item->ri_buf[1].i_addr); | 2573 | xfs_dinode_to_disk(dip, dicp); |
2365 | 2574 | ||
2366 | /* the rest is in on-disk format */ | 2575 | /* the rest is in on-disk format */ |
2367 | if (item->ri_buf[1].i_len > sizeof(struct xfs_icdinode)) { | 2576 | if (item->ri_buf[1].i_len > isize) { |
2368 | memcpy((xfs_caddr_t) dip + sizeof(struct xfs_icdinode), | 2577 | memcpy((char *)dip + isize, |
2369 | item->ri_buf[1].i_addr + sizeof(struct xfs_icdinode), | 2578 | item->ri_buf[1].i_addr + isize, |
2370 | item->ri_buf[1].i_len - sizeof(struct xfs_icdinode)); | 2579 | item->ri_buf[1].i_len - isize); |
2371 | } | 2580 | } |
2372 | 2581 | ||
2373 | fields = in_f->ilf_fields; | 2582 | fields = in_f->ilf_fields; |
@@ -2451,6 +2660,9 @@ xlog_recover_inode_pass2( | |||
2451 | } | 2660 | } |
2452 | 2661 | ||
2453 | write_inode_buffer: | 2662 | write_inode_buffer: |
2663 | /* re-generate the checksum. */ | ||
2664 | xfs_dinode_calc_crc(log->l_mp, dip); | ||
2665 | |||
2454 | ASSERT(bp->b_target->bt_mount == mp); | 2666 | ASSERT(bp->b_target->bt_mount == mp); |
2455 | bp->b_iodone = xlog_recover_iodone; | 2667 | bp->b_iodone = xlog_recover_iodone; |
2456 | xfs_buf_delwri_queue(bp, buffer_list); | 2668 | xfs_buf_delwri_queue(bp, buffer_list); |
@@ -2948,6 +3160,7 @@ xlog_recover_process_efi( | |||
2948 | * This will pull the EFI from the AIL and | 3160 | * This will pull the EFI from the AIL and |
2949 | * free the memory associated with it. | 3161 | * free the memory associated with it. |
2950 | */ | 3162 | */ |
3163 | set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); | ||
2951 | xfs_efi_release(efip, efip->efi_format.efi_nextents); | 3164 | xfs_efi_release(efip, efip->efi_format.efi_nextents); |
2952 | return XFS_ERROR(EIO); | 3165 | return XFS_ERROR(EIO); |
2953 | } | 3166 | } |
@@ -3751,6 +3964,25 @@ xlog_recover( | |||
3751 | return error; | 3964 | return error; |
3752 | } | 3965 | } |
3753 | 3966 | ||
3967 | /* | ||
3968 | * Version 5 superblock log feature mask validation. We know the | ||
3969 | * log is dirty so check if there are any unknown log features | ||
3970 | * in what we need to recover. If there are unknown features | ||
3971 | * (e.g. unsupported transactions, then simply reject the | ||
3972 | * attempt at recovery before touching anything. | ||
3973 | */ | ||
3974 | if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 && | ||
3975 | xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb, | ||
3976 | XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) { | ||
3977 | xfs_warn(log->l_mp, | ||
3978 | "Superblock has unknown incompatible log features (0x%x) enabled.\n" | ||
3979 | "The log can not be fully and/or safely recovered by this kernel.\n" | ||
3980 | "Please recover the log on a kernel that supports the unknown features.", | ||
3981 | (log->l_mp->m_sb.sb_features_log_incompat & | ||
3982 | XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)); | ||
3983 | return EINVAL; | ||
3984 | } | ||
3985 | |||
3754 | xfs_notice(log->l_mp, "Starting recovery (logdev: %s)", | 3986 | xfs_notice(log->l_mp, "Starting recovery (logdev: %s)", |
3755 | log->l_mp->m_logname ? log->l_mp->m_logname | 3987 | log->l_mp->m_logname ? log->l_mp->m_logname |
3756 | : "internal"); | 3988 | : "internal"); |