aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
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__ */