diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_fsops.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 98 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 3 |
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 | |||
304 | xfs_mount_validate_sb( | 304 | xfs_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 | ||
522 | void | 509 | void |
523 | xfs_sb_from_disk( | 510 | xfs_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 | ||
615 | void | ||
616 | xfs_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 | */ | ||
642 | void | ||
643 | xfs_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 | ||
653 | reread: | 682 | reread: |
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 | ||
388 | extern void xfs_sb_read_verify(struct xfs_buf *); | ||
388 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); | 389 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); |
389 | extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, | 390 | extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, |
390 | xfs_agnumber_t *); | 391 | xfs_agnumber_t *); |
391 | extern void xfs_sb_from_disk(struct xfs_mount *, struct xfs_dsb *); | 392 | extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); |
392 | extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); | 393 | extern 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__ */ |