|
@@ -432,53 +432,84 @@ xfs_alloc_fixup_trees(
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
+static bool
|
|
|
xfs_agfl_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
-#ifdef WHEN_CRCS_COME_ALONG
|
|
|
- /*
|
|
|
- * we cannot actually do any verification of the AGFL because mkfs does
|
|
|
- * not initialise the AGFL to zero or NULL. Hence the only valid part of
|
|
|
- * the AGFL is what the AGF says is active. We can't get to the AGF, so
|
|
|
- * we can't verify just those entries are valid.
|
|
|
- *
|
|
|
- * This problem goes away when the CRC format change comes along as that
|
|
|
- * requires the AGFL to be initialised by mkfs. At that point, we can
|
|
|
- * verify the blocks in the agfl -active or not- lie within the bounds
|
|
|
- * of the AG. Until then, just leave this check ifdef'd out.
|
|
|
- */
|
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
|
|
|
- int agfl_ok = 1;
|
|
|
-
|
|
|
int i;
|
|
|
|
|
|
+ if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
|
|
|
+ return false;
|
|
|
+ if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
|
|
|
+ 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 && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
|
|
|
+ return false;
|
|
|
+
|
|
|
for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
|
|
|
- if (be32_to_cpu(agfl->agfl_bno[i]) == NULLAGBLOCK ||
|
|
|
+ if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&
|
|
|
be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
|
|
|
- agfl_ok = 0;
|
|
|
+ return false;
|
|
|
}
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+xfs_agfl_read_verify(
|
|
|
+ struct xfs_buf *bp)
|
|
|
+{
|
|
|
+ struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
+ int agfl_ok = 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There is no verification of non-crc AGFLs because mkfs does not
|
|
|
+ * initialise the AGFL to zero or NULL. Hence the only valid part of the
|
|
|
+ * AGFL is what the AGF says is active. We can't get to the AGF, so we
|
|
|
+ * can't verify just those entries are valid.
|
|
|
+ */
|
|
|
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
+ return;
|
|
|
+
|
|
|
+ agfl_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
|
|
|
+ offsetof(struct xfs_agfl, agfl_crc));
|
|
|
+
|
|
|
+ agfl_ok = agfl_ok && xfs_agfl_verify(bp);
|
|
|
|
|
|
if (!agfl_ok) {
|
|
|
- XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agfl);
|
|
|
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
|
}
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
xfs_agfl_write_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_agfl_verify(bp);
|
|
|
-}
|
|
|
+ struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
+ struct xfs_buf_log_item *bip = bp->b_fspriv;
|
|
|
|
|
|
-static void
|
|
|
-xfs_agfl_read_verify(
|
|
|
- struct xfs_buf *bp)
|
|
|
-{
|
|
|
- xfs_agfl_verify(bp);
|
|
|
+ /* no verification of non-crc AGFLs */
|
|
|
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!xfs_agfl_verify(bp)) {
|
|
|
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
|
+ xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bip)
|
|
|
+ XFS_BUF_TO_AGFL(bp)->agfl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
|
|
|
+
|
|
|
+ xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
|
|
|
+ offsetof(struct xfs_agfl, agfl_crc));
|
|
|
}
|
|
|
|
|
|
const struct xfs_buf_ops xfs_agfl_buf_ops = {
|
|
@@ -1984,18 +2015,18 @@ xfs_alloc_get_freelist(
|
|
|
int btreeblk) /* destination is a AGF btree */
|
|
|
{
|
|
|
xfs_agf_t *agf; /* a.g. freespace structure */
|
|
|
- xfs_agfl_t *agfl; /* a.g. freelist structure */
|
|
|
xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */
|
|
|
xfs_agblock_t bno; /* block number returned */
|
|
|
+ __be32 *agfl_bno;
|
|
|
int error;
|
|
|
int logflags;
|
|
|
- xfs_mount_t *mp; /* mount structure */
|
|
|
+ xfs_mount_t *mp = tp->t_mountp;
|
|
|
xfs_perag_t *pag; /* per allocation group data */
|
|
|
|
|
|
- agf = XFS_BUF_TO_AGF(agbp);
|
|
|
/*
|
|
|
* Freelist is empty, give up.
|
|
|
*/
|
|
|
+ agf = XFS_BUF_TO_AGF(agbp);
|
|
|
if (!agf->agf_flcount) {
|
|
|
*bnop = NULLAGBLOCK;
|
|
|
return 0;
|
|
@@ -2003,15 +2034,17 @@ xfs_alloc_get_freelist(
|
|
|
/*
|
|
|
* Read the array of free blocks.
|
|
|
*/
|
|
|
- mp = tp->t_mountp;
|
|
|
- if ((error = xfs_alloc_read_agfl(mp, tp,
|
|
|
- be32_to_cpu(agf->agf_seqno), &agflbp)))
|
|
|
+ error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno),
|
|
|
+ &agflbp);
|
|
|
+ if (error)
|
|
|
return error;
|
|
|
- agfl = XFS_BUF_TO_AGFL(agflbp);
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Get the block number and update the data structures.
|
|
|
*/
|
|
|
- bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
|
|
|
+ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
|
|
|
+ bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
|
|
|
be32_add_cpu(&agf->agf_flfirst, 1);
|
|
|
xfs_trans_brelse(tp, agflbp);
|
|
|
if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
|
|
@@ -2104,12 +2137,13 @@ xfs_alloc_put_freelist(
|
|
|
int btreeblk) /* block came from a AGF btree */
|
|
|
{
|
|
|
xfs_agf_t *agf; /* a.g. freespace structure */
|
|
|
- xfs_agfl_t *agfl; /* a.g. free block array */
|
|
|
__be32 *blockp;/* pointer to array entry */
|
|
|
int error;
|
|
|
int logflags;
|
|
|
xfs_mount_t *mp; /* mount structure */
|
|
|
xfs_perag_t *pag; /* per allocation group data */
|
|
|
+ __be32 *agfl_bno;
|
|
|
+ int startoff;
|
|
|
|
|
|
agf = XFS_BUF_TO_AGF(agbp);
|
|
|
mp = tp->t_mountp;
|
|
@@ -2117,7 +2151,6 @@ xfs_alloc_put_freelist(
|
|
|
if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp,
|
|
|
be32_to_cpu(agf->agf_seqno), &agflbp)))
|
|
|
return error;
|
|
|
- agfl = XFS_BUF_TO_AGFL(agflbp);
|
|
|
be32_add_cpu(&agf->agf_fllast, 1);
|
|
|
if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
|
|
|
agf->agf_fllast = 0;
|
|
@@ -2138,13 +2171,17 @@ xfs_alloc_put_freelist(
|
|
|
xfs_alloc_log_agf(tp, agbp, logflags);
|
|
|
|
|
|
ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
|
|
|
- blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
|
|
|
+
|
|
|
+ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
|
|
|
+ blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)];
|
|
|
*blockp = cpu_to_be32(bno);
|
|
|
+ startoff = (char *)blockp - (char *)agflbp->b_addr;
|
|
|
+
|
|
|
xfs_alloc_log_agf(tp, agbp, logflags);
|
|
|
- xfs_trans_log_buf(tp, agflbp,
|
|
|
- (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
|
|
|
- (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
|
|
|
- sizeof(xfs_agblock_t) - 1));
|
|
|
+
|
|
|
+ xfs_trans_buf_set_type(tp, agflbp, XFS_BLF_AGFL_BUF);
|
|
|
+ xfs_trans_log_buf(tp, agflbp, startoff,
|
|
|
+ startoff + sizeof(xfs_agblock_t) - 1);
|
|
|
return 0;
|
|
|
}
|
|
|
|