diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r-- | fs/xfs/xfs_inode.c | 100 |
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 | ||
385 | static void | ||
386 | xfs_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; |