Skip to content

Commit

Permalink
xfs: add CRC checks to the AGI
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Apr 21, 2013
1 parent 77c95bb commit 983d09f
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 15 deletions.
8 changes: 8 additions & 0 deletions fs/xfs/xfs_ag.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,21 @@ typedef struct xfs_agi {
__be32 agi_root; /* root of inode btree */
__be32 agi_level; /* levels in inode btree */
__be32 agi_freecount; /* number of free inodes */

__be32 agi_newino; /* new inode just allocated */
__be32 agi_dirino; /* last directory inode chunk */
/*
* Hash table of inodes which have been unlinked but are
* still being referenced.
*/
__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;

#define XFS_AGI_MAGICNUM 0x00000001
Expand Down
4 changes: 3 additions & 1 deletion fs/xfs/xfs_buf_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ extern kmem_zone_t *xfs_buf_item_zone;
#define XFS_BLF_BTREE_BUF (1<<5)
#define XFS_BLF_AGF_BUF (1<<6)
#define XFS_BLF_AGFL_BUF (1<<7)
#define XFS_BLF_AGI_BUF (1<<8)

#define XFS_BLF_TYPE_MASK \
(XFS_BLF_UDQUOT_BUF | \
XFS_BLF_PDQUOT_BUF | \
XFS_BLF_GDQUOT_BUF | \
XFS_BLF_BTREE_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_SHIFT 7
Expand Down
3 changes: 3 additions & 0 deletions fs/xfs/xfs_fsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,11 @@ xfs_growfs_data_private(
agi->agi_freecount = 0;
agi->agi_newino = 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++)
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);

error = xfs_bwrite(bp);
xfs_buf_relse(bp);
if (error)
Expand Down
57 changes: 43 additions & 14 deletions fs/xfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_bmap.h"
#include "xfs_cksum.h"
#include "xfs_buf_item.h"


/*
Expand Down Expand Up @@ -1453,6 +1455,7 @@ xfs_ialloc_log_agi(
/*
* 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);
}

Expand All @@ -1470,50 +1473,76 @@ xfs_check_agi_unlinked(
#define xfs_check_agi_unlinked(agi)
#endif

static void
static bool
xfs_agi_verify(
struct xfs_buf *bp)
{
struct xfs_mount *mp = bp->b_target->bt_mount;
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.
*/
agi_ok = agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC) &&
XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
if (agi->agi_magicnum != cpu_to_be32(XFS_AGI_MAGIC))
return false;
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
return false;

/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't
* use it by using uncached buffers that don't have the perag attached
* so we can detect and avoid this problem.
*/
if (bp->b_pag)
agi_ok = agi_ok && be32_to_cpu(agi->agi_seqno) ==
bp->b_pag->pag_agno;
if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno)
return false;

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);
return true;
}

static void
xfs_agi_read_verify(
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
xfs_agi_write_verify(
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 = {
Expand Down
8 changes: 8 additions & 0 deletions fs/xfs/xfs_log_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,14 @@ xlog_recover_do_reg_buffer(
}
bp->b_ops = &xfs_agfl_buf_ops;
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:
break;
}
Expand Down

0 comments on commit 983d09f

Please sign in to comment.