|
@@ -2126,6 +2126,17 @@ xlog_recover_validate_buf_type(
|
|
|
__uint16_t magic16;
|
|
|
__uint16_t magicda;
|
|
|
|
|
|
+ /*
|
|
|
+ * We can only do post recovery validation on items on CRC enabled
|
|
|
+ * fielsystems as we need to know when the buffer was written to be able
|
|
|
+ * to determine if we should have replayed the item. If we replay old
|
|
|
+ * metadata over a newer buffer, then it will enter a temporarily
|
|
|
+ * inconsistent state resulting in verification failures. Hence for now
|
|
|
+ * just avoid the verification stage for non-crc filesystems
|
|
|
+ */
|
|
|
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
+ return;
|
|
|
+
|
|
|
magic32 = be32_to_cpu(*(__be32 *)bp->b_addr);
|
|
|
magic16 = be16_to_cpu(*(__be16*)bp->b_addr);
|
|
|
magicda = be16_to_cpu(info->magic);
|
|
@@ -2163,8 +2174,6 @@ xlog_recover_validate_buf_type(
|
|
|
bp->b_ops = &xfs_agf_buf_ops;
|
|
|
break;
|
|
|
case XFS_BLFT_AGFL_BUF:
|
|
|
- if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
- break;
|
|
|
if (magic32 != XFS_AGFL_MAGIC) {
|
|
|
xfs_warn(mp, "Bad AGFL block magic!");
|
|
|
ASSERT(0);
|
|
@@ -2197,10 +2206,6 @@ xlog_recover_validate_buf_type(
|
|
|
#endif
|
|
|
break;
|
|
|
case XFS_BLFT_DINO_BUF:
|
|
|
- /*
|
|
|
- * we get here with inode allocation buffers, not buffers that
|
|
|
- * track unlinked list changes.
|
|
|
- */
|
|
|
if (magic16 != XFS_DINODE_MAGIC) {
|
|
|
xfs_warn(mp, "Bad INODE block magic!");
|
|
|
ASSERT(0);
|
|
@@ -2280,8 +2285,6 @@ xlog_recover_validate_buf_type(
|
|
|
bp->b_ops = &xfs_attr3_leaf_buf_ops;
|
|
|
break;
|
|
|
case XFS_BLFT_ATTR_RMT_BUF:
|
|
|
- if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
- break;
|
|
|
if (magic32 != XFS_ATTR3_RMT_MAGIC) {
|
|
|
xfs_warn(mp, "Bad attr remote magic!");
|
|
|
ASSERT(0);
|
|
@@ -2388,16 +2391,7 @@ xlog_recover_do_reg_buffer(
|
|
|
/* Shouldn't be any more regions */
|
|
|
ASSERT(i == item->ri_total);
|
|
|
|
|
|
- /*
|
|
|
- * We can only do post recovery validation on items on CRC enabled
|
|
|
- * fielsystems as we need to know when the buffer was written to be able
|
|
|
- * to determine if we should have replayed the item. If we replay old
|
|
|
- * metadata over a newer buffer, then it will enter a temporarily
|
|
|
- * inconsistent state resulting in verification failures. Hence for now
|
|
|
- * just avoid the verification stage for non-crc filesystems
|
|
|
- */
|
|
|
- if (xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
- xlog_recover_validate_buf_type(mp, bp, buf_f);
|
|
|
+ xlog_recover_validate_buf_type(mp, bp, buf_f);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2405,8 +2399,11 @@ xlog_recover_do_reg_buffer(
|
|
|
* Simple algorithm: if we have found a QUOTAOFF log item of the same type
|
|
|
* (ie. USR or GRP), then just toss this buffer away; don't recover it.
|
|
|
* Else, treat it as a regular buffer and do recovery.
|
|
|
+ *
|
|
|
+ * Return false if the buffer was tossed and true if we recovered the buffer to
|
|
|
+ * indicate to the caller if the buffer needs writing.
|
|
|
*/
|
|
|
-STATIC void
|
|
|
+STATIC bool
|
|
|
xlog_recover_do_dquot_buffer(
|
|
|
struct xfs_mount *mp,
|
|
|
struct xlog *log,
|
|
@@ -2421,9 +2418,8 @@ xlog_recover_do_dquot_buffer(
|
|
|
/*
|
|
|
* Filesystems are required to send in quota flags at mount time.
|
|
|
*/
|
|
|
- if (mp->m_qflags == 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (!mp->m_qflags)
|
|
|
+ return false;
|
|
|
|
|
|
type = 0;
|
|
|
if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
|
|
@@ -2436,9 +2432,10 @@ xlog_recover_do_dquot_buffer(
|
|
|
* This type of quotas was turned off, so ignore this buffer
|
|
|
*/
|
|
|
if (log->l_quotaoffs_flag & type)
|
|
|
- return;
|
|
|
+ return false;
|
|
|
|
|
|
xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2505,23 +2502,44 @@ xlog_recover_buffer_pass2(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * recover the buffer only if we get an LSN from it and it's less than
|
|
|
+ * Recover the buffer only if we get an LSN from it and it's less than
|
|
|
* the lsn of the transaction we are replaying.
|
|
|
+ *
|
|
|
+ * Note that we have to be extremely careful of readahead here.
|
|
|
+ * Readahead does not attach verfiers to the buffers so if we don't
|
|
|
+ * actually do any replay after readahead because of the LSN we found
|
|
|
+ * in the buffer if more recent than that current transaction then we
|
|
|
+ * need to attach the verifier directly. Failure to do so can lead to
|
|
|
+ * future recovery actions (e.g. EFI and unlinked list recovery) can
|
|
|
+ * operate on the buffers and they won't get the verifier attached. This
|
|
|
+ * can lead to blocks on disk having the correct content but a stale
|
|
|
+ * CRC.
|
|
|
+ *
|
|
|
+ * It is safe to assume these clean buffers are currently up to date.
|
|
|
+ * If the buffer is dirtied by a later transaction being replayed, then
|
|
|
+ * the verifier will be reset to match whatever recover turns that
|
|
|
+ * buffer into.
|
|
|
*/
|
|
|
lsn = xlog_recover_get_buf_lsn(mp, bp);
|
|
|
- if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0)
|
|
|
+ if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
|
|
|
+ xlog_recover_validate_buf_type(mp, bp, buf_f);
|
|
|
goto out_release;
|
|
|
+ }
|
|
|
|
|
|
if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
|
|
|
error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
|
|
|
+ if (error)
|
|
|
+ goto out_release;
|
|
|
} else if (buf_f->blf_flags &
|
|
|
(XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
|
|
|
- xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
|
|
|
+ bool dirty;
|
|
|
+
|
|
|
+ dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
|
|
|
+ if (!dirty)
|
|
|
+ goto out_release;
|
|
|
} else {
|
|
|
xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
|
|
|
}
|
|
|
- if (error)
|
|
|
- goto out_release;
|
|
|
|
|
|
/*
|
|
|
* Perform delayed write on the buffer. Asynchronous writes will be
|
|
@@ -3011,27 +3029,22 @@ xlog_recover_dquot_pass2(
|
|
|
return -EIO;
|
|
|
ASSERT(dq_f->qlf_len == 1);
|
|
|
|
|
|
+ /*
|
|
|
+ * At this point we are assuming that the dquots have been allocated
|
|
|
+ * and hence the buffer has valid dquots stamped in it. It should,
|
|
|
+ * therefore, pass verifier validation. If the dquot is bad, then the
|
|
|
+ * we'll return an error here, so we don't need to specifically check
|
|
|
+ * the dquot in the buffer after the verifier has run.
|
|
|
+ */
|
|
|
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
|
|
|
XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
|
|
|
- NULL);
|
|
|
+ &xfs_dquot_buf_ops);
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
|
ASSERT(bp);
|
|
|
ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset);
|
|
|
|
|
|
- /*
|
|
|
- * At least the magic num portion should be on disk because this
|
|
|
- * was among a chunk of dquots created earlier, and we did some
|
|
|
- * minimal initialization then.
|
|
|
- */
|
|
|
- error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
|
|
|
- "xlog_recover_dquot_pass2");
|
|
|
- if (error) {
|
|
|
- xfs_buf_relse(bp);
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* If the dquot has an LSN in it, recover the dquot only if it's less
|
|
|
* than the lsn of the transaction we are replaying.
|