|
@@ -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 = {
|