Commit af133e86 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers

xfs: verify inode buffers as they are read from disk

Add an inode buffer verify callback function and pass it into the
buffer read functions. Inodes are special in that the verbose checks
will be done when reading the inode, but we still need to sanity
check the buffer when that is first read. Always verify the magic
numbers in all inodes in the buffer, rather than jus ton debug
kernels.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarPhil White <pwhite@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent bb80c6d7
...@@ -382,6 +382,46 @@ xfs_inobp_check( ...@@ -382,6 +382,46 @@ xfs_inobp_check(
} }
#endif #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 * 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 * version of the inode. It returns a pointer to the buffer containing the
...@@ -396,71 +436,33 @@ xfs_imap_to_bp( ...@@ -396,71 +436,33 @@ xfs_imap_to_bp(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_imap *imap, struct xfs_imap *imap,
struct xfs_dinode **dipp, struct xfs_dinode **dipp,
struct xfs_buf **bpp, struct xfs_buf **bpp,
uint buf_flags, uint buf_flags,
uint iget_flags) uint iget_flags)
{ {
struct xfs_buf *bp; struct xfs_buf *bp;
int error; int error;
int i;
int ni;
buf_flags |= XBF_UNMAPPED; buf_flags |= XBF_UNMAPPED;
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, 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) {
if (error != EAGAIN) { if (error == EAGAIN) {
xfs_warn(mp,
"%s: xfs_trans_read_buf() returned error %d.",
__func__, error);
} else {
ASSERT(buf_flags & XBF_TRYLOCK); ASSERT(buf_flags & XBF_TRYLOCK);
return error;
} }
return error;
}
/* if (error == EFSCORRUPTED &&
* Validate the magic number and version of every inode in the buffer (iget_flags & XFS_IGET_UNTRUSTED))
* (if DEBUG kernel) or the first inode in the buffer, otherwise. return XFS_ERROR(EINVAL);
*/
#ifdef DEBUG
ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
#else /* usual case */
ni = 1;
#endif
for (i = 0; i < ni; i++) { xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.",
int di_ok; __func__, error);
xfs_dinode_t *dip; return error;
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_inobp_check(mp, bp);
*bpp = bp; *bpp = bp;
*dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset); *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment