Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 983d09ff authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

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: default avatarDave Chinner <dgc@sgi.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Chinner <dgc@redhat.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 77c95bba
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ 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 */
	/*
@@ -159,6 +160,13 @@ typedef struct xfs_agi {
	 * 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
+3 −1
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ 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 | \
@@ -54,7 +55,8 @@ extern kmem_zone_t *xfs_buf_item_zone;
		 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
+3 −0
Original line number Diff line number Diff line
@@ -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)
+43 −14
Original line number Diff line number Diff line
@@ -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"


/*
@@ -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);
}

@@ -1470,19 +1473,23 @@ 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,
@@ -1490,30 +1497,52 @@ xfs_agi_verify(
	 * 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 = {
+8 −0
Original line number Diff line number Diff line
@@ -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;
	}