aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-12 06:54:07 -0500
committerBen Myers <bpm@sgi.com>2012-11-15 22:34:19 -0500
commitaf133e8606d32c2aed43870491ebbdc56feec8a8 (patch)
treee74ee12057c2703f83a5e455a50ee590d504be70 /fs/xfs
parentbb80c6d79a3b0f9b6c3236a4bec021c72615bfd1 (diff)
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: Dave Chinner <dchinner@redhat.com> Reviewed-by: Phil White <pwhite@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_inode.c100
1 files changed, 51 insertions, 49 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 8d6963010489..514eac913f1c 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -382,6 +382,46 @@ xfs_inobp_check(
382} 382}
383#endif 383#endif
384 384
385static void
386xfs_inode_buf_verify(
387 struct xfs_buf *bp)
388{
389 struct xfs_mount *mp = bp->b_target->bt_mount;
390 int i;
391 int ni;
392
393 /*
394 * Validate the magic number and version of every inode in the buffer
395 */
396 ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
397 for (i = 0; i < ni; i++) {
398 int di_ok;
399 xfs_dinode_t *dip;
400
401 dip = (struct xfs_dinode *)xfs_buf_offset(bp,
402 (i << mp->m_sb.sb_inodelog));
403 di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
404 XFS_DINODE_GOOD_VERSION(dip->di_version);
405 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
406 XFS_ERRTAG_ITOBP_INOTOBP,
407 XFS_RANDOM_ITOBP_INOTOBP))) {
408 xfs_buf_ioerror(bp, EFSCORRUPTED);
409 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
410 mp, dip);
411#ifdef DEBUG
412 xfs_emerg(mp,
413 "bad inode magic/vsn daddr %lld #%d (magic=%x)",
414 (unsigned long long)bp->b_bn, i,
415 be16_to_cpu(dip->di_magic));
416 ASSERT(0);
417#endif
418 }
419 }
420 xfs_inobp_check(mp, bp);
421 bp->b_iodone = NULL;
422 xfs_buf_ioend(bp, 0);
423}
424
385/* 425/*
386 * This routine is called to map an inode to the buffer containing the on-disk 426 * This routine is called to map an inode to the buffer containing the on-disk
387 * version of the inode. It returns a pointer to the buffer containing the 427 * version of the inode. It returns a pointer to the buffer containing the
@@ -396,71 +436,33 @@ xfs_imap_to_bp(
396 struct xfs_mount *mp, 436 struct xfs_mount *mp,
397 struct xfs_trans *tp, 437 struct xfs_trans *tp,
398 struct xfs_imap *imap, 438 struct xfs_imap *imap,
399 struct xfs_dinode **dipp, 439 struct xfs_dinode **dipp,
400 struct xfs_buf **bpp, 440 struct xfs_buf **bpp,
401 uint buf_flags, 441 uint buf_flags,
402 uint iget_flags) 442 uint iget_flags)
403{ 443{
404 struct xfs_buf *bp; 444 struct xfs_buf *bp;
405 int error; 445 int error;
406 int i;
407 int ni;
408 446
409 buf_flags |= XBF_UNMAPPED; 447 buf_flags |= XBF_UNMAPPED;
410 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, 448 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
411 (int)imap->im_len, buf_flags, &bp, NULL); 449 (int)imap->im_len, buf_flags, &bp,
450 xfs_inode_buf_verify);
412 if (error) { 451 if (error) {
413 if (error != EAGAIN) { 452 if (error == EAGAIN) {
414 xfs_warn(mp,
415 "%s: xfs_trans_read_buf() returned error %d.",
416 __func__, error);
417 } else {
418 ASSERT(buf_flags & XBF_TRYLOCK); 453 ASSERT(buf_flags & XBF_TRYLOCK);
454 return error;
419 } 455 }
420 return error;
421 }
422 456
423 /* 457 if (error == EFSCORRUPTED &&
424 * Validate the magic number and version of every inode in the buffer 458 (iget_flags & XFS_IGET_UNTRUSTED))
425 * (if DEBUG kernel) or the first inode in the buffer, otherwise. 459 return XFS_ERROR(EINVAL);
426 */
427#ifdef DEBUG
428 ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
429#else /* usual case */
430 ni = 1;
431#endif
432 460
433 for (i = 0; i < ni; i++) { 461 xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.",
434 int di_ok; 462 __func__, error);
435 xfs_dinode_t *dip; 463 return error;
436
437 dip = (xfs_dinode_t *)xfs_buf_offset(bp,
438 (i << mp->m_sb.sb_inodelog));
439 di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
440 XFS_DINODE_GOOD_VERSION(dip->di_version);
441 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
442 XFS_ERRTAG_ITOBP_INOTOBP,
443 XFS_RANDOM_ITOBP_INOTOBP))) {
444 if (iget_flags & XFS_IGET_UNTRUSTED) {
445 xfs_trans_brelse(tp, bp);
446 return XFS_ERROR(EINVAL);
447 }
448 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
449 mp, dip);
450#ifdef DEBUG
451 xfs_emerg(mp,
452 "bad inode magic/vsn daddr %lld #%d (magic=%x)",
453 (unsigned long long)imap->im_blkno, i,
454 be16_to_cpu(dip->di_magic));
455 ASSERT(0);
456#endif
457 xfs_trans_brelse(tp, bp);
458 return XFS_ERROR(EFSCORRUPTED);
459 }
460 } 464 }
461 465
462 xfs_inobp_check(mp, bp);
463
464 *bpp = bp; 466 *bpp = bp;
465 *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset); 467 *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
466 return 0; 468 return 0;