aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-12 06:54:03 -0500
committerBen Myers <bpm@sgi.com>2012-11-15 22:34:07 -0500
commit98021821a502db347bd9c7671beeee6e8ce07ea6 (patch)
tree1cfb76746a51e6713ff4ba2842ed55c90c4b063b /fs/xfs
parenteab4e63368b4cfa597dbdac66d1a7a836a693b7d (diff)
xfs: verify superblocks as they are read from disk
Add a superblock verify callback function and pass it into the buffer read functions. Remove the now redundant verification code that is currently in use. Adding verification shows that secondary superblocks never have their "sb_inprogress" flag cleared by mkfs.xfs, so when validating the secondary superblocks during a grow operation we have to avoid checking this field. Even if we fix mkfs, we will still have to ignore this field for verification purposes unless a version of mkfs that does not have this bug was used. 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_fsops.c4
-rw-r--r--fs/xfs/xfs_log_recover.c5
-rw-r--r--fs/xfs/xfs_mount.c98
-rw-r--r--fs/xfs/xfs_mount.h3
4 files changed, 69 insertions, 41 deletions
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index f35f8d7731f0..cb65b067ed31 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -444,7 +444,8 @@ xfs_growfs_data_private(
444 if (agno < oagcount) { 444 if (agno < oagcount) {
445 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, 445 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
446 XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), 446 XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
447 XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL); 447 XFS_FSS_TO_BB(mp, 1), 0, &bp,
448 xfs_sb_read_verify);
448 } else { 449 } else {
449 bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, 450 bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp,
450 XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), 451 XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
@@ -462,6 +463,7 @@ xfs_growfs_data_private(
462 break; 463 break;
463 } 464 }
464 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS); 465 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS);
466
465 /* 467 /*
466 * If we get an error writing out the alternate superblocks, 468 * If we get an error writing out the alternate superblocks,
467 * just issue a warning and continue. The real work is 469 * just issue a warning and continue. The real work is
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index eb1e29ff0c7c..924a4bc3d49a 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3692,13 +3692,14 @@ xlog_do_recover(
3692 3692
3693 /* 3693 /*
3694 * Now that we've finished replaying all buffer and inode 3694 * Now that we've finished replaying all buffer and inode
3695 * updates, re-read in the superblock. 3695 * updates, re-read in the superblock and reverify it.
3696 */ 3696 */
3697 bp = xfs_getsb(log->l_mp, 0); 3697 bp = xfs_getsb(log->l_mp, 0);
3698 XFS_BUF_UNDONE(bp); 3698 XFS_BUF_UNDONE(bp);
3699 ASSERT(!(XFS_BUF_ISWRITE(bp))); 3699 ASSERT(!(XFS_BUF_ISWRITE(bp)));
3700 XFS_BUF_READ(bp); 3700 XFS_BUF_READ(bp);
3701 XFS_BUF_UNASYNC(bp); 3701 XFS_BUF_UNASYNC(bp);
3702 bp->b_iodone = xfs_sb_read_verify;
3702 xfsbdstrat(log->l_mp, bp); 3703 xfsbdstrat(log->l_mp, bp);
3703 error = xfs_buf_iowait(bp); 3704 error = xfs_buf_iowait(bp);
3704 if (error) { 3705 if (error) {
@@ -3710,7 +3711,7 @@ xlog_do_recover(
3710 3711
3711 /* Convert superblock from on-disk format */ 3712 /* Convert superblock from on-disk format */
3712 sbp = &log->l_mp->m_sb; 3713 sbp = &log->l_mp->m_sb;
3713 xfs_sb_from_disk(log->l_mp, XFS_BUF_TO_SBP(bp)); 3714 xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
3714 ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC); 3715 ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
3715 ASSERT(xfs_sb_good_version(sbp)); 3716 ASSERT(xfs_sb_good_version(sbp));
3716 xfs_buf_relse(bp); 3717 xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index df6d0b2aade1..bff18d73c610 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -304,9 +304,8 @@ STATIC int
304xfs_mount_validate_sb( 304xfs_mount_validate_sb(
305 xfs_mount_t *mp, 305 xfs_mount_t *mp,
306 xfs_sb_t *sbp, 306 xfs_sb_t *sbp,
307 int flags) 307 bool check_inprogress)
308{ 308{
309 int loud = !(flags & XFS_MFSI_QUIET);
310 309
311 /* 310 /*
312 * If the log device and data device have the 311 * If the log device and data device have the
@@ -316,21 +315,18 @@ xfs_mount_validate_sb(
316 * a volume filesystem in a non-volume manner. 315 * a volume filesystem in a non-volume manner.
317 */ 316 */
318 if (sbp->sb_magicnum != XFS_SB_MAGIC) { 317 if (sbp->sb_magicnum != XFS_SB_MAGIC) {
319 if (loud) 318 xfs_warn(mp, "bad magic number");
320 xfs_warn(mp, "bad magic number");
321 return XFS_ERROR(EWRONGFS); 319 return XFS_ERROR(EWRONGFS);
322 } 320 }
323 321
324 if (!xfs_sb_good_version(sbp)) { 322 if (!xfs_sb_good_version(sbp)) {
325 if (loud) 323 xfs_warn(mp, "bad version");
326 xfs_warn(mp, "bad version");
327 return XFS_ERROR(EWRONGFS); 324 return XFS_ERROR(EWRONGFS);
328 } 325 }
329 326
330 if (unlikely( 327 if (unlikely(
331 sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { 328 sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
332 if (loud) 329 xfs_warn(mp,
333 xfs_warn(mp,
334 "filesystem is marked as having an external log; " 330 "filesystem is marked as having an external log; "
335 "specify logdev on the mount command line."); 331 "specify logdev on the mount command line.");
336 return XFS_ERROR(EINVAL); 332 return XFS_ERROR(EINVAL);
@@ -338,8 +334,7 @@ xfs_mount_validate_sb(
338 334
339 if (unlikely( 335 if (unlikely(
340 sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { 336 sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
341 if (loud) 337 xfs_warn(mp,
342 xfs_warn(mp,
343 "filesystem is marked as having an internal log; " 338 "filesystem is marked as having an internal log; "
344 "do not specify logdev on the mount command line."); 339 "do not specify logdev on the mount command line.");
345 return XFS_ERROR(EINVAL); 340 return XFS_ERROR(EINVAL);
@@ -373,8 +368,7 @@ xfs_mount_validate_sb(
373 sbp->sb_dblocks == 0 || 368 sbp->sb_dblocks == 0 ||
374 sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || 369 sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) ||
375 sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) { 370 sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
376 if (loud) 371 XFS_CORRUPTION_ERROR("SB sanity check failed",
377 XFS_CORRUPTION_ERROR("SB sanity check failed",
378 XFS_ERRLEVEL_LOW, mp, sbp); 372 XFS_ERRLEVEL_LOW, mp, sbp);
379 return XFS_ERROR(EFSCORRUPTED); 373 return XFS_ERROR(EFSCORRUPTED);
380 } 374 }
@@ -383,12 +377,10 @@ xfs_mount_validate_sb(
383 * Until this is fixed only page-sized or smaller data blocks work. 377 * Until this is fixed only page-sized or smaller data blocks work.
384 */ 378 */
385 if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { 379 if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
386 if (loud) { 380 xfs_warn(mp,
387 xfs_warn(mp,
388 "File system with blocksize %d bytes. " 381 "File system with blocksize %d bytes. "
389 "Only pagesize (%ld) or less will currently work.", 382 "Only pagesize (%ld) or less will currently work.",
390 sbp->sb_blocksize, PAGE_SIZE); 383 sbp->sb_blocksize, PAGE_SIZE);
391 }
392 return XFS_ERROR(ENOSYS); 384 return XFS_ERROR(ENOSYS);
393 } 385 }
394 386
@@ -402,23 +394,20 @@ xfs_mount_validate_sb(
402 case 2048: 394 case 2048:
403 break; 395 break;
404 default: 396 default:
405 if (loud) 397 xfs_warn(mp, "inode size of %d bytes not supported",
406 xfs_warn(mp, "inode size of %d bytes not supported",
407 sbp->sb_inodesize); 398 sbp->sb_inodesize);
408 return XFS_ERROR(ENOSYS); 399 return XFS_ERROR(ENOSYS);
409 } 400 }
410 401
411 if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || 402 if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
412 xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { 403 xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
413 if (loud) 404 xfs_warn(mp,
414 xfs_warn(mp,
415 "file system too large to be mounted on this system."); 405 "file system too large to be mounted on this system.");
416 return XFS_ERROR(EFBIG); 406 return XFS_ERROR(EFBIG);
417 } 407 }
418 408
419 if (unlikely(sbp->sb_inprogress)) { 409 if (check_inprogress && sbp->sb_inprogress) {
420 if (loud) 410 xfs_warn(mp, "Offline file system operation in progress!");
421 xfs_warn(mp, "file system busy");
422 return XFS_ERROR(EFSCORRUPTED); 411 return XFS_ERROR(EFSCORRUPTED);
423 } 412 }
424 413
@@ -426,9 +415,7 @@ xfs_mount_validate_sb(
426 * Version 1 directory format has never worked on Linux. 415 * Version 1 directory format has never worked on Linux.
427 */ 416 */
428 if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { 417 if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
429 if (loud) 418 xfs_warn(mp, "file system using version 1 directory format");
430 xfs_warn(mp,
431 "file system using version 1 directory format");
432 return XFS_ERROR(ENOSYS); 419 return XFS_ERROR(ENOSYS);
433 } 420 }
434 421
@@ -521,11 +508,9 @@ out_unwind:
521 508
522void 509void
523xfs_sb_from_disk( 510xfs_sb_from_disk(
524 struct xfs_mount *mp, 511 struct xfs_sb *to,
525 xfs_dsb_t *from) 512 xfs_dsb_t *from)
526{ 513{
527 struct xfs_sb *to = &mp->m_sb;
528
529 to->sb_magicnum = be32_to_cpu(from->sb_magicnum); 514 to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
530 to->sb_blocksize = be32_to_cpu(from->sb_blocksize); 515 to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
531 to->sb_dblocks = be64_to_cpu(from->sb_dblocks); 516 to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
@@ -627,6 +612,50 @@ xfs_sb_to_disk(
627 } 612 }
628} 613}
629 614
615void
616xfs_sb_read_verify(
617 struct xfs_buf *bp)
618{
619 struct xfs_mount *mp = bp->b_target->bt_mount;
620 struct xfs_sb sb;
621 int error;
622
623 xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
624
625 /*
626 * Only check the in progress field for the primary superblock as
627 * mkfs.xfs doesn't clear it from secondary superblocks.
628 */
629 error = xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR);
630 if (error)
631 xfs_buf_ioerror(bp, error);
632 bp->b_iodone = NULL;
633 xfs_buf_ioend(bp, 0);
634}
635
636/*
637 * We may be probed for a filesystem match, so we may not want to emit
638 * messages when the superblock buffer is not actually an XFS superblock.
639 * If we find an XFS superblock, the run a normal, noisy mount because we are
640 * really going to mount it and want to know about errors.
641 */
642void
643xfs_sb_quiet_read_verify(
644 struct xfs_buf *bp)
645{
646 struct xfs_sb sb;
647
648 xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
649
650 if (sb.sb_magicnum == XFS_SB_MAGIC) {
651 /* XFS filesystem, verify noisily! */
652 xfs_sb_read_verify(bp);
653 return;
654 }
655 /* quietly fail */
656 xfs_buf_ioerror(bp, EFSCORRUPTED);
657}
658
630/* 659/*
631 * xfs_readsb 660 * xfs_readsb
632 * 661 *
@@ -652,7 +681,9 @@ xfs_readsb(xfs_mount_t *mp, int flags)
652 681
653reread: 682reread:
654 bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, 683 bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
655 BTOBB(sector_size), 0, NULL); 684 BTOBB(sector_size), 0,
685 loud ? xfs_sb_read_verify
686 : xfs_sb_quiet_read_verify);
656 if (!bp) { 687 if (!bp) {
657 if (loud) 688 if (loud)
658 xfs_warn(mp, "SB buffer read failed"); 689 xfs_warn(mp, "SB buffer read failed");
@@ -667,15 +698,8 @@ reread:
667 698
668 /* 699 /*
669 * Initialize the mount structure from the superblock. 700 * Initialize the mount structure from the superblock.
670 * But first do some basic consistency checking.
671 */ 701 */
672 xfs_sb_from_disk(mp, XFS_BUF_TO_SBP(bp)); 702 xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
673 error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
674 if (error) {
675 if (loud)
676 xfs_warn(mp, "SB validate failed");
677 goto release_buf;
678 }
679 703
680 /* 704 /*
681 * We must be able to do sector-sized and sector-aligned IO. 705 * We must be able to do sector-sized and sector-aligned IO.
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index dc306a09f56f..de9089acc610 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -385,10 +385,11 @@ extern void xfs_set_low_space_thresholds(struct xfs_mount *);
385 385
386#endif /* __KERNEL__ */ 386#endif /* __KERNEL__ */
387 387
388extern void xfs_sb_read_verify(struct xfs_buf *);
388extern void xfs_mod_sb(struct xfs_trans *, __int64_t); 389extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
389extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, 390extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
390 xfs_agnumber_t *); 391 xfs_agnumber_t *);
391extern void xfs_sb_from_disk(struct xfs_mount *, struct xfs_dsb *); 392extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
392extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); 393extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
393 394
394#endif /* __XFS_MOUNT_H__ */ 395#endif /* __XFS_MOUNT_H__ */