diff options
author | Dave Chinner <dgc@sgi.com> | 2013-04-03 01:11:15 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-04-21 15:57:43 -0400 |
commit | 983d09ffe396ed5d5339a1b9ff994dd0b0f2069f (patch) | |
tree | 42779460b8910c6537bd4d53fa99f23eb5fde830 | |
parent | 77c95bba013089fa868217283eb6d98a05913e53 (diff) |
xfs: add CRC checks to the AGI
Same set of changes made to the AGF need to be made to the AGI.
This patch has a similar history to the AGF, hence a similar
sign-off chain.
Signed-off-by: Dave Chinner <dgc@sgi.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <dgc@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r-- | fs/xfs/xfs_ag.h | 8 | ||||
-rw-r--r-- | fs/xfs/xfs_buf_item.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 57 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 8 |
5 files changed, 65 insertions, 15 deletions
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 272ef097e2be..317aa86d96ea 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h | |||
@@ -152,6 +152,7 @@ typedef struct xfs_agi { | |||
152 | __be32 agi_root; /* root of inode btree */ | 152 | __be32 agi_root; /* root of inode btree */ |
153 | __be32 agi_level; /* levels in inode btree */ | 153 | __be32 agi_level; /* levels in inode btree */ |
154 | __be32 agi_freecount; /* number of free inodes */ | 154 | __be32 agi_freecount; /* number of free inodes */ |
155 | |||
155 | __be32 agi_newino; /* new inode just allocated */ | 156 | __be32 agi_newino; /* new inode just allocated */ |
156 | __be32 agi_dirino; /* last directory inode chunk */ | 157 | __be32 agi_dirino; /* last directory inode chunk */ |
157 | /* | 158 | /* |
@@ -159,6 +160,13 @@ typedef struct xfs_agi { | |||
159 | * still being referenced. | 160 | * still being referenced. |
160 | */ | 161 | */ |
161 | __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; | 162 | __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; |
163 | |||
164 | uuid_t agi_uuid; /* uuid of filesystem */ | ||
165 | __be32 agi_crc; /* crc of agi sector */ | ||
166 | __be32 agi_pad32; | ||
167 | __be64 agi_lsn; /* last write sequence */ | ||
168 | |||
169 | /* structure must be padded to 64 bit alignment */ | ||
162 | } xfs_agi_t; | 170 | } xfs_agi_t; |
163 | 171 | ||
164 | #define XFS_AGI_MAGICNUM 0x00000001 | 172 | #define XFS_AGI_MAGICNUM 0x00000001 |
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 067d5f0fc233..c25660691e08 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h | |||
@@ -47,6 +47,7 @@ extern kmem_zone_t *xfs_buf_item_zone; | |||
47 | #define XFS_BLF_BTREE_BUF (1<<5) | 47 | #define XFS_BLF_BTREE_BUF (1<<5) |
48 | #define XFS_BLF_AGF_BUF (1<<6) | 48 | #define XFS_BLF_AGF_BUF (1<<6) |
49 | #define XFS_BLF_AGFL_BUF (1<<7) | 49 | #define XFS_BLF_AGFL_BUF (1<<7) |
50 | #define XFS_BLF_AGI_BUF (1<<8) | ||
50 | 51 | ||
51 | #define XFS_BLF_TYPE_MASK \ | 52 | #define XFS_BLF_TYPE_MASK \ |
52 | (XFS_BLF_UDQUOT_BUF | \ | 53 | (XFS_BLF_UDQUOT_BUF | \ |
@@ -54,7 +55,8 @@ extern kmem_zone_t *xfs_buf_item_zone; | |||
54 | XFS_BLF_GDQUOT_BUF | \ | 55 | XFS_BLF_GDQUOT_BUF | \ |
55 | XFS_BLF_BTREE_BUF | \ | 56 | XFS_BLF_BTREE_BUF | \ |
56 | XFS_BLF_AGF_BUF | \ | 57 | XFS_BLF_AGF_BUF | \ |
57 | XFS_BLF_AGFL_BUF) | 58 | XFS_BLF_AGFL_BUF | \ |
59 | XFS_BLF_AGI_BUF) | ||
58 | 60 | ||
59 | #define XFS_BLF_CHUNK 128 | 61 | #define XFS_BLF_CHUNK 128 |
60 | #define XFS_BLF_SHIFT 7 | 62 | #define XFS_BLF_SHIFT 7 |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index a693a54799e5..87595b211da1 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -304,8 +304,11 @@ xfs_growfs_data_private( | |||
304 | agi->agi_freecount = 0; | 304 | agi->agi_freecount = 0; |
305 | agi->agi_newino = cpu_to_be32(NULLAGINO); | 305 | agi->agi_newino = cpu_to_be32(NULLAGINO); |
306 | agi->agi_dirino = cpu_to_be32(NULLAGINO); | 306 | agi->agi_dirino = cpu_to_be32(NULLAGINO); |
307 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
308 | uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); | ||
307 | for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) | 309 | for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) |
308 | agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); | 310 | agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); |
311 | |||
309 | error = xfs_bwrite(bp); | 312 | error = xfs_bwrite(bp); |
310 | xfs_buf_relse(bp); | 313 | xfs_buf_relse(bp); |
311 | if (error) | 314 | if (error) |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index ba626613bf49..6d0a4954aa8c 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include "xfs_rtalloc.h" | 36 | #include "xfs_rtalloc.h" |
37 | #include "xfs_error.h" | 37 | #include "xfs_error.h" |
38 | #include "xfs_bmap.h" | 38 | #include "xfs_bmap.h" |
39 | #include "xfs_cksum.h" | ||
40 | #include "xfs_buf_item.h" | ||
39 | 41 | ||
40 | 42 | ||
41 | /* | 43 | /* |
@@ -1453,6 +1455,7 @@ xfs_ialloc_log_agi( | |||
1453 | /* | 1455 | /* |
1454 | * Log the allocation group inode header buffer. | 1456 | * Log the allocation group inode header buffer. |
1455 | */ | 1457 | */ |
1458 | xfs_trans_buf_set_type(tp, bp, XFS_BLF_AGI_BUF); | ||
1456 | xfs_trans_log_buf(tp, bp, first, last); | 1459 | xfs_trans_log_buf(tp, bp, first, last); |
1457 | } | 1460 | } |
1458 | 1461 | ||
@@ -1470,19 +1473,23 @@ xfs_check_agi_unlinked( | |||
1470 | #define xfs_check_agi_unlinked(agi) | 1473 | #define xfs_check_agi_unlinked(agi) |
1471 | #endif | 1474 | #endif |
1472 | 1475 | ||
1473 | static void | 1476 | static bool |
1474 | xfs_agi_verify( | 1477 | xfs_agi_verify( |
1475 | struct xfs_buf *bp) | 1478 | struct xfs_buf *bp) |
1476 | { | 1479 | { |
1477 | struct xfs_mount *mp = bp->b_target->bt_mount; | 1480 | struct xfs_mount *mp = bp->b_target->bt_mount; |
1478 | struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); | 1481 | struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); |
1479 | int agi_ok; | ||
1480 | 1482 | ||
1483 | if (xfs_sb_version_hascrc(&mp->m_sb) && | ||
1484 | !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_uuid)) | ||
1485 | return false; | ||
1481 | /* | 1486 | /* |
1482 | * Validate the magic number of the agi block. | 1487 | * Validate the magic number of the agi block. |
1483 | */ | 1488 | */ |
1484 | agi_ok = agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC) && | 1489 | if (agi->agi_magicnum != cpu_to_be32(XFS_AGI_MAGIC)) |
1485 | XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)); | 1490 | return false; |
1491 | if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) | ||
1492 | return false; | ||
1486 | 1493 | ||
1487 | /* | 1494 | /* |
1488 | * during growfs operations, the perag is not fully initialised, | 1495 | * during growfs operations, the perag is not fully initialised, |
@@ -1490,30 +1497,52 @@ xfs_agi_verify( | |||
1490 | * use it by using uncached buffers that don't have the perag attached | 1497 | * use it by using uncached buffers that don't have the perag attached |
1491 | * so we can detect and avoid this problem. | 1498 | * so we can detect and avoid this problem. |
1492 | */ | 1499 | */ |
1493 | if (bp->b_pag) | 1500 | if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno) |
1494 | agi_ok = agi_ok && be32_to_cpu(agi->agi_seqno) == | 1501 | return false; |
1495 | bp->b_pag->pag_agno; | ||
1496 | 1502 | ||
1497 | if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, | ||
1498 | XFS_RANDOM_IALLOC_READ_AGI))) { | ||
1499 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agi); | ||
1500 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
1501 | } | ||
1502 | xfs_check_agi_unlinked(agi); | 1503 | xfs_check_agi_unlinked(agi); |
1504 | return true; | ||
1503 | } | 1505 | } |
1504 | 1506 | ||
1505 | static void | 1507 | static void |
1506 | xfs_agi_read_verify( | 1508 | xfs_agi_read_verify( |
1507 | struct xfs_buf *bp) | 1509 | struct xfs_buf *bp) |
1508 | { | 1510 | { |
1509 | xfs_agi_verify(bp); | 1511 | struct xfs_mount *mp = bp->b_target->bt_mount; |
1512 | int agi_ok = 1; | ||
1513 | |||
1514 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
1515 | agi_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
1516 | offsetof(struct xfs_agi, agi_crc)); | ||
1517 | agi_ok = agi_ok && xfs_agi_verify(bp); | ||
1518 | |||
1519 | if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, | ||
1520 | XFS_RANDOM_IALLOC_READ_AGI))) { | ||
1521 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
1522 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
1523 | } | ||
1510 | } | 1524 | } |
1511 | 1525 | ||
1512 | static void | 1526 | static void |
1513 | xfs_agi_write_verify( | 1527 | xfs_agi_write_verify( |
1514 | struct xfs_buf *bp) | 1528 | struct xfs_buf *bp) |
1515 | { | 1529 | { |
1516 | xfs_agi_verify(bp); | 1530 | struct xfs_mount *mp = bp->b_target->bt_mount; |
1531 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
1532 | |||
1533 | if (!xfs_agi_verify(bp)) { | ||
1534 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
1535 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
1536 | return; | ||
1537 | } | ||
1538 | |||
1539 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
1540 | return; | ||
1541 | |||
1542 | if (bip) | ||
1543 | XFS_BUF_TO_AGI(bp)->agi_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
1544 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
1545 | offsetof(struct xfs_agi, agi_crc)); | ||
1517 | } | 1546 | } |
1518 | 1547 | ||
1519 | const struct xfs_buf_ops xfs_agi_buf_ops = { | 1548 | const struct xfs_buf_ops xfs_agi_buf_ops = { |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index da2a19e0554e..6778a7943db4 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -1971,6 +1971,14 @@ xlog_recover_do_reg_buffer( | |||
1971 | } | 1971 | } |
1972 | bp->b_ops = &xfs_agfl_buf_ops; | 1972 | bp->b_ops = &xfs_agfl_buf_ops; |
1973 | break; | 1973 | break; |
1974 | case XFS_BLF_AGI_BUF: | ||
1975 | if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGI_MAGIC)) { | ||
1976 | xfs_warn(mp, "Bad AGI block magic!"); | ||
1977 | ASSERT(0); | ||
1978 | break; | ||
1979 | } | ||
1980 | bp->b_ops = &xfs_agi_buf_ops; | ||
1981 | break; | ||
1974 | default: | 1982 | default: |
1975 | break; | 1983 | break; |
1976 | } | 1984 | } |