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>
This commit is contained in:
parent
77c95bba01
commit
983d09ffe3
|
@ -152,6 +152,7 @@ typedef struct xfs_agi {
|
||||||
__be32 agi_root; /* root of inode btree */
|
__be32 agi_root; /* root of inode btree */
|
||||||
__be32 agi_level; /* levels in inode btree */
|
__be32 agi_level; /* levels in inode btree */
|
||||||
__be32 agi_freecount; /* number of free inodes */
|
__be32 agi_freecount; /* number of free inodes */
|
||||||
|
|
||||||
__be32 agi_newino; /* new inode just allocated */
|
__be32 agi_newino; /* new inode just allocated */
|
||||||
__be32 agi_dirino; /* last directory inode chunk */
|
__be32 agi_dirino; /* last directory inode chunk */
|
||||||
/*
|
/*
|
||||||
|
@ -159,6 +160,13 @@ typedef struct xfs_agi {
|
||||||
* still being referenced.
|
* still being referenced.
|
||||||
*/
|
*/
|
||||||
__be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
|
__be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
|
||||||
|
|
||||||
|
uuid_t agi_uuid; /* uuid of filesystem */
|
||||||
|
__be32 agi_crc; /* crc of agi sector */
|
||||||
|
__be32 agi_pad32;
|
||||||
|
__be64 agi_lsn; /* last write sequence */
|
||||||
|
|
||||||
|
/* structure must be padded to 64 bit alignment */
|
||||||
} xfs_agi_t;
|
} xfs_agi_t;
|
||||||
|
|
||||||
#define XFS_AGI_MAGICNUM 0x00000001
|
#define XFS_AGI_MAGICNUM 0x00000001
|
||||||
|
|
|
@ -47,6 +47,7 @@ extern kmem_zone_t *xfs_buf_item_zone;
|
||||||
#define XFS_BLF_BTREE_BUF (1<<5)
|
#define XFS_BLF_BTREE_BUF (1<<5)
|
||||||
#define XFS_BLF_AGF_BUF (1<<6)
|
#define XFS_BLF_AGF_BUF (1<<6)
|
||||||
#define XFS_BLF_AGFL_BUF (1<<7)
|
#define XFS_BLF_AGFL_BUF (1<<7)
|
||||||
|
#define XFS_BLF_AGI_BUF (1<<8)
|
||||||
|
|
||||||
#define XFS_BLF_TYPE_MASK \
|
#define XFS_BLF_TYPE_MASK \
|
||||||
(XFS_BLF_UDQUOT_BUF | \
|
(XFS_BLF_UDQUOT_BUF | \
|
||||||
|
@ -54,7 +55,8 @@ extern kmem_zone_t *xfs_buf_item_zone;
|
||||||
XFS_BLF_GDQUOT_BUF | \
|
XFS_BLF_GDQUOT_BUF | \
|
||||||
XFS_BLF_BTREE_BUF | \
|
XFS_BLF_BTREE_BUF | \
|
||||||
XFS_BLF_AGF_BUF | \
|
XFS_BLF_AGF_BUF | \
|
||||||
XFS_BLF_AGFL_BUF)
|
XFS_BLF_AGFL_BUF | \
|
||||||
|
XFS_BLF_AGI_BUF)
|
||||||
|
|
||||||
#define XFS_BLF_CHUNK 128
|
#define XFS_BLF_CHUNK 128
|
||||||
#define XFS_BLF_SHIFT 7
|
#define XFS_BLF_SHIFT 7
|
||||||
|
|
|
@ -304,8 +304,11 @@ xfs_growfs_data_private(
|
||||||
agi->agi_freecount = 0;
|
agi->agi_freecount = 0;
|
||||||
agi->agi_newino = cpu_to_be32(NULLAGINO);
|
agi->agi_newino = cpu_to_be32(NULLAGINO);
|
||||||
agi->agi_dirino = cpu_to_be32(NULLAGINO);
|
agi->agi_dirino = cpu_to_be32(NULLAGINO);
|
||||||
|
if (xfs_sb_version_hascrc(&mp->m_sb))
|
||||||
|
uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
|
||||||
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
|
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
|
||||||
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
|
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
|
||||||
|
|
||||||
error = xfs_bwrite(bp);
|
error = xfs_bwrite(bp);
|
||||||
xfs_buf_relse(bp);
|
xfs_buf_relse(bp);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#include "xfs_rtalloc.h"
|
#include "xfs_rtalloc.h"
|
||||||
#include "xfs_error.h"
|
#include "xfs_error.h"
|
||||||
#include "xfs_bmap.h"
|
#include "xfs_bmap.h"
|
||||||
|
#include "xfs_cksum.h"
|
||||||
|
#include "xfs_buf_item.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1453,6 +1455,7 @@ xfs_ialloc_log_agi(
|
||||||
/*
|
/*
|
||||||
* Log the allocation group inode header buffer.
|
* Log the allocation group inode header buffer.
|
||||||
*/
|
*/
|
||||||
|
xfs_trans_buf_set_type(tp, bp, XFS_BLF_AGI_BUF);
|
||||||
xfs_trans_log_buf(tp, bp, first, last);
|
xfs_trans_log_buf(tp, bp, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1470,19 +1473,23 @@ xfs_check_agi_unlinked(
|
||||||
#define xfs_check_agi_unlinked(agi)
|
#define xfs_check_agi_unlinked(agi)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
xfs_agi_verify(
|
xfs_agi_verify(
|
||||||
struct xfs_buf *bp)
|
struct xfs_buf *bp)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = bp->b_target->bt_mount;
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||||
struct xfs_agi *agi = XFS_BUF_TO_AGI(bp);
|
struct xfs_agi *agi = XFS_BUF_TO_AGI(bp);
|
||||||
int agi_ok;
|
|
||||||
|
|
||||||
|
if (xfs_sb_version_hascrc(&mp->m_sb) &&
|
||||||
|
!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_uuid))
|
||||||
|
return false;
|
||||||
/*
|
/*
|
||||||
* Validate the magic number of the agi block.
|
* Validate the magic number of the agi block.
|
||||||
*/
|
*/
|
||||||
agi_ok = agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC) &&
|
if (agi->agi_magicnum != cpu_to_be32(XFS_AGI_MAGIC))
|
||||||
XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
|
return false;
|
||||||
|
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
|
||||||
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* during growfs operations, the perag is not fully initialised,
|
* during growfs operations, the perag is not fully initialised,
|
||||||
|
@ -1490,30 +1497,52 @@ xfs_agi_verify(
|
||||||
* use it by using uncached buffers that don't have the perag attached
|
* use it by using uncached buffers that don't have the perag attached
|
||||||
* so we can detect and avoid this problem.
|
* so we can detect and avoid this problem.
|
||||||
*/
|
*/
|
||||||
if (bp->b_pag)
|
if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno)
|
||||||
agi_ok = agi_ok && be32_to_cpu(agi->agi_seqno) ==
|
return false;
|
||||||
bp->b_pag->pag_agno;
|
|
||||||
|
|
||||||
if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI,
|
|
||||||
XFS_RANDOM_IALLOC_READ_AGI))) {
|
|
||||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agi);
|
|
||||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
||||||
}
|
|
||||||
xfs_check_agi_unlinked(agi);
|
xfs_check_agi_unlinked(agi);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xfs_agi_read_verify(
|
xfs_agi_read_verify(
|
||||||
struct xfs_buf *bp)
|
struct xfs_buf *bp)
|
||||||
{
|
{
|
||||||
xfs_agi_verify(bp);
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||||
|
int agi_ok = 1;
|
||||||
|
|
||||||
|
if (xfs_sb_version_hascrc(&mp->m_sb))
|
||||||
|
agi_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
|
||||||
|
offsetof(struct xfs_agi, agi_crc));
|
||||||
|
agi_ok = agi_ok && xfs_agi_verify(bp);
|
||||||
|
|
||||||
|
if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI,
|
||||||
|
XFS_RANDOM_IALLOC_READ_AGI))) {
|
||||||
|
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
||||||
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xfs_agi_write_verify(
|
xfs_agi_write_verify(
|
||||||
struct xfs_buf *bp)
|
struct xfs_buf *bp)
|
||||||
{
|
{
|
||||||
xfs_agi_verify(bp);
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
||||||
|
struct xfs_buf_log_item *bip = bp->b_fspriv;
|
||||||
|
|
||||||
|
if (!xfs_agi_verify(bp)) {
|
||||||
|
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
||||||
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bip)
|
||||||
|
XFS_BUF_TO_AGI(bp)->agi_lsn = cpu_to_be64(bip->bli_item.li_lsn);
|
||||||
|
xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
|
||||||
|
offsetof(struct xfs_agi, agi_crc));
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct xfs_buf_ops xfs_agi_buf_ops = {
|
const struct xfs_buf_ops xfs_agi_buf_ops = {
|
||||||
|
|
|
@ -1971,6 +1971,14 @@ xlog_recover_do_reg_buffer(
|
||||||
}
|
}
|
||||||
bp->b_ops = &xfs_agfl_buf_ops;
|
bp->b_ops = &xfs_agfl_buf_ops;
|
||||||
break;
|
break;
|
||||||
|
case XFS_BLF_AGI_BUF:
|
||||||
|
if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGI_MAGIC)) {
|
||||||
|
xfs_warn(mp, "Bad AGI block magic!");
|
||||||
|
ASSERT(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp->b_ops = &xfs_agi_buf_ops;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue