diff options
Diffstat (limited to 'fs/xfs/xfs_mount.c')
| -rw-r--r-- | fs/xfs/xfs_mount.c | 206 | 
1 files changed, 103 insertions, 103 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 29c2f83d414..da508463ff1 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -42,6 +42,7 @@  #include "xfs_fsops.h"  #include "xfs_utils.h"  #include "xfs_trace.h" +#include "xfs_icache.h"  #ifdef HAVE_PERCPU_SB @@ -303,9 +304,8 @@ STATIC int  xfs_mount_validate_sb(  	xfs_mount_t	*mp,  	xfs_sb_t	*sbp, -	int		flags) +	bool		check_inprogress)  { -	int		loud = !(flags & XFS_MFSI_QUIET);  	/*  	 * If the log device and data device have the @@ -315,21 +315,18 @@ xfs_mount_validate_sb(  	 * a volume filesystem in a non-volume manner.  	 */  	if (sbp->sb_magicnum != XFS_SB_MAGIC) { -		if (loud) -			xfs_warn(mp, "bad magic number"); +		xfs_warn(mp, "bad magic number");  		return XFS_ERROR(EWRONGFS);  	}  	if (!xfs_sb_good_version(sbp)) { -		if (loud) -			xfs_warn(mp, "bad version"); +		xfs_warn(mp, "bad version");  		return XFS_ERROR(EWRONGFS);  	}  	if (unlikely(  	    sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { -		if (loud) -			xfs_warn(mp, +		xfs_warn(mp,  		"filesystem is marked as having an external log; "  		"specify logdev on the mount command line.");  		return XFS_ERROR(EINVAL); @@ -337,8 +334,7 @@ xfs_mount_validate_sb(  	if (unlikely(  	    sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { -		if (loud) -			xfs_warn(mp, +		xfs_warn(mp,  		"filesystem is marked as having an internal log; "  		"do not specify logdev on the mount command line.");  		return XFS_ERROR(EINVAL); @@ -372,8 +368,7 @@ xfs_mount_validate_sb(  	    sbp->sb_dblocks == 0					||  	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||  	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) { -		if (loud) -			XFS_CORRUPTION_ERROR("SB sanity check failed", +		XFS_CORRUPTION_ERROR("SB sanity check failed",  				XFS_ERRLEVEL_LOW, mp, sbp);  		return XFS_ERROR(EFSCORRUPTED);  	} @@ -382,12 +377,10 @@ xfs_mount_validate_sb(  	 * Until this is fixed only page-sized or smaller data blocks work.  	 */  	if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { -		if (loud) { -			xfs_warn(mp, +		xfs_warn(mp,  		"File system with blocksize %d bytes. "  		"Only pagesize (%ld) or less will currently work.",  				sbp->sb_blocksize, PAGE_SIZE); -		}  		return XFS_ERROR(ENOSYS);  	} @@ -401,23 +394,20 @@ xfs_mount_validate_sb(  	case 2048:  		break;  	default: -		if (loud) -			xfs_warn(mp, "inode size of %d bytes not supported", +		xfs_warn(mp, "inode size of %d bytes not supported",  				sbp->sb_inodesize);  		return XFS_ERROR(ENOSYS);  	}  	if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||  	    xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { -		if (loud) -			xfs_warn(mp, +		xfs_warn(mp,  		"file system too large to be mounted on this system.");  		return XFS_ERROR(EFBIG);  	} -	if (unlikely(sbp->sb_inprogress)) { -		if (loud) -			xfs_warn(mp, "file system busy"); +	if (check_inprogress && sbp->sb_inprogress) { +		xfs_warn(mp, "Offline file system operation in progress!");  		return XFS_ERROR(EFSCORRUPTED);  	} @@ -425,9 +415,7 @@ xfs_mount_validate_sb(  	 * Version 1 directory format has never worked on Linux.  	 */  	if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { -		if (loud) -			xfs_warn(mp, -				"file system using version 1 directory format"); +		xfs_warn(mp, "file system using version 1 directory format");  		return XFS_ERROR(ENOSYS);  	} @@ -440,7 +428,7 @@ xfs_initialize_perag(  	xfs_agnumber_t	agcount,  	xfs_agnumber_t	*maxagi)  { -	xfs_agnumber_t	index, max_metadata; +	xfs_agnumber_t	index;  	xfs_agnumber_t	first_initialised = 0;  	xfs_perag_t	*pag;  	xfs_agino_t	agino; @@ -500,43 +488,10 @@ xfs_initialize_perag(  	else  		mp->m_flags &= ~XFS_MOUNT_32BITINODES; -	if (mp->m_flags & XFS_MOUNT_32BITINODES) { -		/* -		 * Calculate how much should be reserved for inodes to meet -		 * the max inode percentage. -		 */ -		if (mp->m_maxicount) { -			__uint64_t	icount; - -			icount = sbp->sb_dblocks * sbp->sb_imax_pct; -			do_div(icount, 100); -			icount += sbp->sb_agblocks - 1; -			do_div(icount, sbp->sb_agblocks); -			max_metadata = icount; -		} else { -			max_metadata = agcount; -		} - -		for (index = 0; index < agcount; index++) { -			ino = XFS_AGINO_TO_INO(mp, index, agino); -			if (ino > XFS_MAXINUMBER_32) { -				index++; -				break; -			} - -			pag = xfs_perag_get(mp, index); -			pag->pagi_inodeok = 1; -			if (index < max_metadata) -				pag->pagf_metadata = 1; -			xfs_perag_put(pag); -		} -	} else { -		for (index = 0; index < agcount; index++) { -			pag = xfs_perag_get(mp, index); -			pag->pagi_inodeok = 1; -			xfs_perag_put(pag); -		} -	} +	if (mp->m_flags & XFS_MOUNT_32BITINODES) +		index = xfs_set_inode32(mp); +	else +		index = xfs_set_inode64(mp);  	if (maxagi)  		*maxagi = index; @@ -553,11 +508,9 @@ out_unwind:  void  xfs_sb_from_disk( -	struct xfs_mount	*mp, +	struct xfs_sb	*to,  	xfs_dsb_t	*from)  { -	struct xfs_sb *to = &mp->m_sb; -  	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);  	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);  	to->sb_dblocks = be64_to_cpu(from->sb_dblocks); @@ -659,6 +612,72 @@ xfs_sb_to_disk(  	}  } +static void +xfs_sb_verify( +	struct xfs_buf	*bp) +{ +	struct xfs_mount *mp = bp->b_target->bt_mount; +	struct xfs_sb	sb; +	int		error; + +	xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp)); + +	/* +	 * Only check the in progress field for the primary superblock as +	 * mkfs.xfs doesn't clear it from secondary superblocks. +	 */ +	error = xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR); +	if (error) +		xfs_buf_ioerror(bp, error); +} + +static void +xfs_sb_read_verify( +	struct xfs_buf	*bp) +{ +	xfs_sb_verify(bp); +} + +/* + * We may be probed for a filesystem match, so we may not want to emit + * messages when the superblock buffer is not actually an XFS superblock. + * If we find an XFS superblock, the run a normal, noisy mount because we are + * really going to mount it and want to know about errors. + */ +static void +xfs_sb_quiet_read_verify( +	struct xfs_buf	*bp) +{ +	struct xfs_sb	sb; + +	xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp)); + +	if (sb.sb_magicnum == XFS_SB_MAGIC) { +		/* XFS filesystem, verify noisily! */ +		xfs_sb_read_verify(bp); +		return; +	} +	/* quietly fail */ +	xfs_buf_ioerror(bp, EFSCORRUPTED); +} + +static void +xfs_sb_write_verify( +	struct xfs_buf	*bp) +{ +	xfs_sb_verify(bp); +} + +const struct xfs_buf_ops xfs_sb_buf_ops = { +	.verify_read = xfs_sb_read_verify, +	.verify_write = xfs_sb_write_verify, +}; + +static const struct xfs_buf_ops xfs_sb_quiet_buf_ops = { +	.verify_read = xfs_sb_quiet_read_verify, +	.verify_write = xfs_sb_write_verify, +}; +  /*   * xfs_readsb   * @@ -684,26 +703,27 @@ xfs_readsb(xfs_mount_t *mp, int flags)  reread:  	bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, -					BTOBB(sector_size), 0); +				   BTOBB(sector_size), 0, +				   loud ? &xfs_sb_buf_ops +				        : &xfs_sb_quiet_buf_ops);  	if (!bp) {  		if (loud)  			xfs_warn(mp, "SB buffer read failed");  		return EIO;  	} - -	/* -	 * Initialize the mount structure from the superblock. -	 * But first do some basic consistency checking. -	 */ -	xfs_sb_from_disk(mp, XFS_BUF_TO_SBP(bp)); -	error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags); -	if (error) { +	if (bp->b_error) { +		error = bp->b_error;  		if (loud)  			xfs_warn(mp, "SB validate failed");  		goto release_buf;  	}  	/* +	 * Initialize the mount structure from the superblock. +	 */ +	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp)); + +	/*  	 * We must be able to do sector-sized and sector-aligned IO.  	 */  	if (sector_size > mp->m_sb.sb_sectsize) { @@ -1034,7 +1054,7 @@ xfs_check_sizes(xfs_mount_t *mp)  	}  	bp = xfs_buf_read_uncached(mp->m_ddev_targp,  					d - XFS_FSS_TO_BB(mp, 1), -					XFS_FSS_TO_BB(mp, 1), 0); +					XFS_FSS_TO_BB(mp, 1), 0, NULL);  	if (!bp) {  		xfs_warn(mp, "last sector read failed");  		return EIO; @@ -1049,7 +1069,7 @@ xfs_check_sizes(xfs_mount_t *mp)  		}  		bp = xfs_buf_read_uncached(mp->m_logdev_targp,  					d - XFS_FSB_TO_BB(mp, 1), -					XFS_FSB_TO_BB(mp, 1), 0); +					XFS_FSB_TO_BB(mp, 1), 0, NULL);  		if (!bp) {  			xfs_warn(mp, "log device read failed");  			return EIO; @@ -1460,6 +1480,8 @@ xfs_unmountfs(  	__uint64_t		resblks;  	int			error; +	cancel_delayed_work_sync(&mp->m_eofblocks_work); +  	xfs_qm_unmount_quotas(mp);  	xfs_rtunmount_inodes(mp);  	IRELE(mp->m_rootip); @@ -1483,21 +1505,16 @@ xfs_unmountfs(  	/*  	 * And reclaim all inodes.  At this point there should be no dirty -	 * inode, and none should be pinned or locked, but use synchronous -	 * reclaim just to be sure. +	 * inodes and none should be pinned or locked, but use synchronous +	 * reclaim just to be sure. We can stop background inode reclaim +	 * here as well if it is still running.  	 */ +	cancel_delayed_work_sync(&mp->m_reclaim_work);  	xfs_reclaim_inodes(mp, SYNC_WAIT);  	xfs_qm_unmount(mp);  	/* -	 * Flush out the log synchronously so that we know for sure -	 * that nothing is pinned.  This is important because bflush() -	 * will skip pinned buffers. -	 */ -	xfs_log_force(mp, XFS_LOG_SYNC); - -	/*  	 * Unreserve any blocks we have so that when we unmount we don't account  	 * the reserved free space as used. This is really only necessary for  	 * lazy superblock counting because it trusts the incore superblock @@ -1522,23 +1539,6 @@ xfs_unmountfs(  		xfs_warn(mp, "Unable to update superblock counters. "  				"Freespace may not be correct on next mount."); -	/* -	 * At this point we might have modified the superblock again and thus -	 * added an item to the AIL, thus flush it again. -	 */ -	xfs_ail_push_all_sync(mp->m_ail); -	xfs_wait_buftarg(mp->m_ddev_targp); - -	/* -	 * The superblock buffer is uncached and xfsaild_push() will lock and -	 * set the XBF_ASYNC flag on the buffer. We cannot do xfs_buf_iowait() -	 * here but a lock on the superblock buffer will block until iodone() -	 * has completed. -	 */ -	xfs_buf_lock(mp->m_sb_bp); -	xfs_buf_unlock(mp->m_sb_bp); - -	xfs_log_unmount_write(mp);  	xfs_log_unmount(mp);  	xfs_uuid_unmount(mp);  |