|
@@ -382,6 +382,46 @@ xfs_inobp_check(
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static void
|
|
|
+xfs_inode_buf_verify(
|
|
|
+ struct xfs_buf *bp)
|
|
|
+{
|
|
|
+ struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
+ int i;
|
|
|
+ int ni;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Validate the magic number and version of every inode in the buffer
|
|
|
+ */
|
|
|
+ ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
|
|
|
+ for (i = 0; i < ni; i++) {
|
|
|
+ int di_ok;
|
|
|
+ xfs_dinode_t *dip;
|
|
|
+
|
|
|
+ dip = (struct xfs_dinode *)xfs_buf_offset(bp,
|
|
|
+ (i << mp->m_sb.sb_inodelog));
|
|
|
+ di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
|
|
|
+ XFS_DINODE_GOOD_VERSION(dip->di_version);
|
|
|
+ if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
|
|
|
+ XFS_ERRTAG_ITOBP_INOTOBP,
|
|
|
+ XFS_RANDOM_ITOBP_INOTOBP))) {
|
|
|
+ xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
|
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
|
|
|
+ mp, dip);
|
|
|
+#ifdef DEBUG
|
|
|
+ xfs_emerg(mp,
|
|
|
+ "bad inode magic/vsn daddr %lld #%d (magic=%x)",
|
|
|
+ (unsigned long long)bp->b_bn, i,
|
|
|
+ be16_to_cpu(dip->di_magic));
|
|
|
+ ASSERT(0);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+ xfs_inobp_check(mp, bp);
|
|
|
+ bp->b_iodone = NULL;
|
|
|
+ xfs_buf_ioend(bp, 0);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This routine is called to map an inode to the buffer containing the on-disk
|
|
|
* version of the inode. It returns a pointer to the buffer containing the
|
|
@@ -396,71 +436,33 @@ xfs_imap_to_bp(
|
|
|
struct xfs_mount *mp,
|
|
|
struct xfs_trans *tp,
|
|
|
struct xfs_imap *imap,
|
|
|
- struct xfs_dinode **dipp,
|
|
|
+ struct xfs_dinode **dipp,
|
|
|
struct xfs_buf **bpp,
|
|
|
uint buf_flags,
|
|
|
uint iget_flags)
|
|
|
{
|
|
|
struct xfs_buf *bp;
|
|
|
int error;
|
|
|
- int i;
|
|
|
- int ni;
|
|
|
|
|
|
buf_flags |= XBF_UNMAPPED;
|
|
|
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
|
|
|
- (int)imap->im_len, buf_flags, &bp, NULL);
|
|
|
+ (int)imap->im_len, buf_flags, &bp,
|
|
|
+ xfs_inode_buf_verify);
|
|
|
if (error) {
|
|
|
- if (error != EAGAIN) {
|
|
|
- xfs_warn(mp,
|
|
|
- "%s: xfs_trans_read_buf() returned error %d.",
|
|
|
- __func__, error);
|
|
|
- } else {
|
|
|
+ if (error == EAGAIN) {
|
|
|
ASSERT(buf_flags & XBF_TRYLOCK);
|
|
|
+ return error;
|
|
|
}
|
|
|
- return error;
|
|
|
- }
|
|
|
|
|
|
- /*
|
|
|
- * Validate the magic number and version of every inode in the buffer
|
|
|
- * (if DEBUG kernel) or the first inode in the buffer, otherwise.
|
|
|
- */
|
|
|
-#ifdef DEBUG
|
|
|
- ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
|
|
|
-#else /* usual case */
|
|
|
- ni = 1;
|
|
|
-#endif
|
|
|
+ if (error == EFSCORRUPTED &&
|
|
|
+ (iget_flags & XFS_IGET_UNTRUSTED))
|
|
|
+ return XFS_ERROR(EINVAL);
|
|
|
|
|
|
- for (i = 0; i < ni; i++) {
|
|
|
- int di_ok;
|
|
|
- xfs_dinode_t *dip;
|
|
|
-
|
|
|
- dip = (xfs_dinode_t *)xfs_buf_offset(bp,
|
|
|
- (i << mp->m_sb.sb_inodelog));
|
|
|
- di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
|
|
|
- XFS_DINODE_GOOD_VERSION(dip->di_version);
|
|
|
- if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
|
|
|
- XFS_ERRTAG_ITOBP_INOTOBP,
|
|
|
- XFS_RANDOM_ITOBP_INOTOBP))) {
|
|
|
- if (iget_flags & XFS_IGET_UNTRUSTED) {
|
|
|
- xfs_trans_brelse(tp, bp);
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
- }
|
|
|
- XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
|
|
|
- mp, dip);
|
|
|
-#ifdef DEBUG
|
|
|
- xfs_emerg(mp,
|
|
|
- "bad inode magic/vsn daddr %lld #%d (magic=%x)",
|
|
|
- (unsigned long long)imap->im_blkno, i,
|
|
|
- be16_to_cpu(dip->di_magic));
|
|
|
- ASSERT(0);
|
|
|
-#endif
|
|
|
- xfs_trans_brelse(tp, bp);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
- }
|
|
|
+ xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.",
|
|
|
+ __func__, error);
|
|
|
+ return error;
|
|
|
}
|
|
|
|
|
|
- xfs_inobp_check(mp, bp);
|
|
|
-
|
|
|
*bpp = bp;
|
|
|
*dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
|
|
|
return 0;
|