diff options
Diffstat (limited to 'fs/xfs/xfs_fsops.c')
| -rw-r--r-- | fs/xfs/xfs_fsops.c | 432 | 
1 files changed, 325 insertions, 107 deletions
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index a7c116e814a..d2295561570 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -17,31 +17,31 @@   */  #include "xfs.h"  #include "xfs_fs.h" -#include "xfs_types.h" -#include "xfs_bit.h" -#include "xfs_inum.h" -#include "xfs_log.h" -#include "xfs_trans.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h"  #include "xfs_sb.h"  #include "xfs_ag.h"  #include "xfs_mount.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_dinode.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h"  #include "xfs_inode.h" +#include "xfs_trans.h"  #include "xfs_inode_item.h" -#include "xfs_btree.h"  #include "xfs_error.h" +#include "xfs_btree.h" +#include "xfs_alloc_btree.h"  #include "xfs_alloc.h"  #include "xfs_ialloc.h"  #include "xfs_fsops.h"  #include "xfs_itable.h"  #include "xfs_trans_space.h"  #include "xfs_rtalloc.h" -#include "xfs_rw.h" -#include "xfs_filestream.h"  #include "xfs_trace.h" +#include "xfs_log.h" +#include "xfs_dinode.h" +#include "xfs_filestream.h"  /*   * File system operations @@ -53,6 +53,9 @@ xfs_fs_geometry(  	xfs_fsop_geom_t		*geo,  	int			new_version)  { + +	memset(geo, 0, sizeof(*geo)); +  	geo->blocksize = mp->m_sb.sb_blocksize;  	geo->rtextsize = mp->m_sb.sb_rextsize;  	geo->agblocks = mp->m_sb.sb_agblocks; @@ -73,23 +76,18 @@ xfs_fs_geometry(  	}  	if (new_version >= 3) {  		geo->version = XFS_FSOP_GEOM_VERSION; -		geo->flags = +		geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK | +			     XFS_FSOP_GEOM_FLAGS_DIRV2 |  			(xfs_sb_version_hasattr(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_ATTR : 0) | -			(xfs_sb_version_hasnlink(&mp->m_sb) ? -				XFS_FSOP_GEOM_FLAGS_NLINK : 0) |  			(xfs_sb_version_hasquota(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_QUOTA : 0) |  			(xfs_sb_version_hasalign(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_IALIGN : 0) |  			(xfs_sb_version_hasdalign(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_DALIGN : 0) | -			(xfs_sb_version_hasshared(&mp->m_sb) ? -				XFS_FSOP_GEOM_FLAGS_SHARED : 0) |  			(xfs_sb_version_hasextflgbit(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) | -			(xfs_sb_version_hasdirv2(&mp->m_sb) ? -				XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |  			(xfs_sb_version_hassector(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |  			(xfs_sb_version_hasasciici(&mp->m_sb) ? @@ -97,11 +95,19 @@ xfs_fs_geometry(  			(xfs_sb_version_haslazysbcount(&mp->m_sb) ?  				XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |  			(xfs_sb_version_hasattr2(&mp->m_sb) ? -				XFS_FSOP_GEOM_FLAGS_ATTR2 : 0); +				XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) | +			(xfs_sb_version_hasprojid32bit(&mp->m_sb) ? +				XFS_FSOP_GEOM_FLAGS_PROJID32 : 0) | +			(xfs_sb_version_hascrc(&mp->m_sb) ? +				XFS_FSOP_GEOM_FLAGS_V5SB : 0) | +			(xfs_sb_version_hasftype(&mp->m_sb) ? +				XFS_FSOP_GEOM_FLAGS_FTYPE : 0) | +			(xfs_sb_version_hasfinobt(&mp->m_sb) ? +				XFS_FSOP_GEOM_FLAGS_FINOBT : 0);  		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?  				mp->m_sb.sb_logsectsize : BBSIZE;  		geo->rtsectsize = mp->m_sb.sb_blocksize; -		geo->dirblocksize = mp->m_dirblksize; +		geo->dirblocksize = mp->m_dir_geo->blksize;  	}  	if (new_version >= 4) {  		geo->flags |= @@ -112,22 +118,44 @@ xfs_fs_geometry(  	return 0;  } +static struct xfs_buf * +xfs_growfs_get_hdr_buf( +	struct xfs_mount	*mp, +	xfs_daddr_t		blkno, +	size_t			numblks, +	int			flags, +	const struct xfs_buf_ops *ops) +{ +	struct xfs_buf		*bp; + +	bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags); +	if (!bp) +		return NULL; + +	xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); +	bp->b_bn = blkno; +	bp->b_maps[0].bm_bn = blkno; +	bp->b_ops = ops; + +	return bp; +} +  static int  xfs_growfs_data_private(  	xfs_mount_t		*mp,		/* mount point for filesystem */  	xfs_growfs_data_t	*in)		/* growfs data input struct */  {  	xfs_agf_t		*agf; +	struct xfs_agfl		*agfl;  	xfs_agi_t		*agi;  	xfs_agnumber_t		agno;  	xfs_extlen_t		agsize;  	xfs_extlen_t		tmpsize;  	xfs_alloc_rec_t		*arec; -	struct xfs_btree_block	*block;  	xfs_buf_t		*bp;  	int			bucket;  	int			dpct; -	int			error; +	int			error, saved_error = 0;  	xfs_agnumber_t		nagcount;  	xfs_agnumber_t		nagimax = 0;  	xfs_rfsblock_t		nb, nb_mod; @@ -144,11 +172,16 @@ xfs_growfs_data_private(  	if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))  		return error;  	dpct = pct - mp->m_sb.sb_imax_pct; -	bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp, +	bp = xfs_buf_read_uncached(mp->m_ddev_targp,  				XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1), -				BBTOB(XFS_FSS_TO_BB(mp, 1)), 0); +				XFS_FSS_TO_BB(mp, 1), 0, NULL);  	if (!bp)  		return EIO; +	if (bp->b_error) { +		error = bp->b_error; +		xfs_buf_relse(bp); +		return error; +	}  	xfs_buf_relse(bp);  	new = nb;	/* use new as a temporary here */ @@ -172,8 +205,9 @@ xfs_growfs_data_private(  	tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);  	tp->t_flags |= XFS_TRANS_RESERVE; -	if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), -			XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) { +	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growdata, +				  XFS_GROWFS_SPACE_RES(mp), 0); +	if (error) {  		xfs_trans_cancel(tp, 0);  		return error;  	} @@ -185,14 +219,21 @@ xfs_growfs_data_private(  	 */  	nfree = 0;  	for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { +		__be32	*agfl_bno; +  		/* -		 * AG freelist header block +		 * AG freespace header block  		 */ -		bp = xfs_buf_get(mp->m_ddev_targp, -				 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), -				 XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED); +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), +				XFS_FSS_TO_BB(mp, 1), 0, +				&xfs_agf_buf_ops); +		if (!bp) { +			error = ENOMEM; +			goto error0; +		} +  		agf = XFS_BUF_TO_AGF(bp); -		memset(agf, 0, mp->m_sb.sb_sectsize);  		agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);  		agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);  		agf->agf_seqno = cpu_to_be32(agno); @@ -213,18 +254,55 @@ xfs_growfs_data_private(  		tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);  		agf->agf_freeblks = cpu_to_be32(tmpsize);  		agf->agf_longest = cpu_to_be32(tmpsize); -		error = xfs_bwrite(mp, bp); -		if (error) { +		if (xfs_sb_version_hascrc(&mp->m_sb)) +			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid); + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error) +			goto error0; + +		/* +		 * AG freelist header block +		 */ +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), +				XFS_FSS_TO_BB(mp, 1), 0, +				&xfs_agfl_buf_ops); +		if (!bp) { +			error = ENOMEM;  			goto error0;  		} + +		agfl = XFS_BUF_TO_AGFL(bp); +		if (xfs_sb_version_hascrc(&mp->m_sb)) { +			agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); +			agfl->agfl_seqno = cpu_to_be32(agno); +			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid); +		} + +		agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); +		for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++) +			agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error) +			goto error0; +  		/*  		 * AG inode header block  		 */ -		bp = xfs_buf_get(mp->m_ddev_targp, -				 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), -				 XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED); +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), +				XFS_FSS_TO_BB(mp, 1), 0, +				&xfs_agi_buf_ops); +		if (!bp) { +			error = ENOMEM; +			goto error0; +		} +  		agi = XFS_BUF_TO_AGI(bp); -		memset(agi, 0, mp->m_sb.sb_sectsize);  		agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);  		agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);  		agi->agi_seqno = cpu_to_be32(agno); @@ -235,75 +313,131 @@ xfs_growfs_data_private(  		agi->agi_freecount = 0;  		agi->agi_newino = cpu_to_be32(NULLAGINO);  		agi->agi_dirino = cpu_to_be32(NULLAGINO); +		if (xfs_sb_version_hascrc(&mp->m_sb)) +			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); +		if (xfs_sb_version_hasfinobt(&mp->m_sb)) { +			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); +			agi->agi_free_level = cpu_to_be32(1); +		}  		for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)  			agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); -		error = xfs_bwrite(mp, bp); -		if (error) { + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error)  			goto error0; -		} +  		/*  		 * BNO btree root block  		 */ -		bp = xfs_buf_get(mp->m_ddev_targp, -				 XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), -				 BTOBB(mp->m_sb.sb_blocksize), -				 XBF_LOCK | XBF_MAPPED); -		block = XFS_BUF_TO_BLOCK(bp); -		memset(block, 0, mp->m_sb.sb_blocksize); -		block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC); -		block->bb_level = 0; -		block->bb_numrecs = cpu_to_be16(1); -		block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); -		block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); -		arec = XFS_ALLOC_REC_ADDR(mp, block, 1); +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), +				BTOBB(mp->m_sb.sb_blocksize), 0, +				&xfs_allocbt_buf_ops); + +		if (!bp) { +			error = ENOMEM; +			goto error0; +		} + +		if (xfs_sb_version_hascrc(&mp->m_sb)) +			xfs_btree_init_block(mp, bp, XFS_ABTB_CRC_MAGIC, 0, 1, +						agno, XFS_BTREE_CRC_BLOCKS); +		else +			xfs_btree_init_block(mp, bp, XFS_ABTB_MAGIC, 0, 1, +						agno, 0); + +		arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);  		arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));  		arec->ar_blockcount = cpu_to_be32(  			agsize - be32_to_cpu(arec->ar_startblock)); -		error = xfs_bwrite(mp, bp); -		if (error) { + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error)  			goto error0; -		} +  		/*  		 * CNT btree root block  		 */ -		bp = xfs_buf_get(mp->m_ddev_targp, -				 XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), -				 BTOBB(mp->m_sb.sb_blocksize), -				 XBF_LOCK | XBF_MAPPED); -		block = XFS_BUF_TO_BLOCK(bp); -		memset(block, 0, mp->m_sb.sb_blocksize); -		block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC); -		block->bb_level = 0; -		block->bb_numrecs = cpu_to_be16(1); -		block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); -		block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); -		arec = XFS_ALLOC_REC_ADDR(mp, block, 1); +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), +				BTOBB(mp->m_sb.sb_blocksize), 0, +				&xfs_allocbt_buf_ops); +		if (!bp) { +			error = ENOMEM; +			goto error0; +		} + +		if (xfs_sb_version_hascrc(&mp->m_sb)) +			xfs_btree_init_block(mp, bp, XFS_ABTC_CRC_MAGIC, 0, 1, +						agno, XFS_BTREE_CRC_BLOCKS); +		else +			xfs_btree_init_block(mp, bp, XFS_ABTC_MAGIC, 0, 1, +						agno, 0); + +		arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);  		arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));  		arec->ar_blockcount = cpu_to_be32(  			agsize - be32_to_cpu(arec->ar_startblock));  		nfree += be32_to_cpu(arec->ar_blockcount); -		error = xfs_bwrite(mp, bp); -		if (error) { + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error)  			goto error0; -		} +  		/*  		 * INO btree root block  		 */ -		bp = xfs_buf_get(mp->m_ddev_targp, -				 XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), -				 BTOBB(mp->m_sb.sb_blocksize), -				 XBF_LOCK | XBF_MAPPED); -		block = XFS_BUF_TO_BLOCK(bp); -		memset(block, 0, mp->m_sb.sb_blocksize); -		block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC); -		block->bb_level = 0; -		block->bb_numrecs = 0; -		block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); -		block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); -		error = xfs_bwrite(mp, bp); -		if (error) { +		bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), +				BTOBB(mp->m_sb.sb_blocksize), 0, +				&xfs_inobt_buf_ops); +		if (!bp) { +			error = ENOMEM;  			goto error0;  		} + +		if (xfs_sb_version_hascrc(&mp->m_sb)) +			xfs_btree_init_block(mp, bp, XFS_IBT_CRC_MAGIC, 0, 0, +						agno, XFS_BTREE_CRC_BLOCKS); +		else +			xfs_btree_init_block(mp, bp, XFS_IBT_MAGIC, 0, 0, +						agno, 0); + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error) +			goto error0; + +		/* +		 * FINO btree root block +		 */ +		if (xfs_sb_version_hasfinobt(&mp->m_sb)) { +			bp = xfs_growfs_get_hdr_buf(mp, +				XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)), +				BTOBB(mp->m_sb.sb_blocksize), 0, +				&xfs_inobt_buf_ops); +			if (!bp) { +				error = ENOMEM; +				goto error0; +			} + +			if (xfs_sb_version_hascrc(&mp->m_sb)) +				xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC, +						     0, 0, agno, +						     XFS_BTREE_CRC_BLOCKS); +			else +				xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0, +						     0, agno, 0); + +			error = xfs_bwrite(bp); +			xfs_buf_relse(bp); +			if (error) +				goto error0; +		} +  	}  	xfs_trans_agblocks_delta(tp, nfree);  	/* @@ -374,34 +508,59 @@ xfs_growfs_data_private(  		mp->m_maxicount = icount << mp->m_sb.sb_inopblog;  	} else  		mp->m_maxicount = 0; +	xfs_set_low_space_thresholds(mp);  	/* update secondary superblocks. */  	for (agno = 1; agno < nagcount; agno++) { -		error = xfs_read_buf(mp, mp->m_ddev_targp, +		error = 0; +		/* +		 * new secondary superblocks need to be zeroed, not read from +		 * disk as the contents of the new area we are growing into is +		 * completely unknown. +		 */ +		if (agno < oagcount) { +			error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,  				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), -				  XFS_FSS_TO_BB(mp, 1), 0, &bp); -		if (error) { -			xfs_fs_cmn_err(CE_WARN, mp, -			"error %d reading secondary superblock for ag %d", -				error, agno); -			break; +				  XFS_FSS_TO_BB(mp, 1), 0, &bp, +				  &xfs_sb_buf_ops); +		} else { +			bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, +				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), +				  XFS_FSS_TO_BB(mp, 1), 0); +			if (bp) { +				bp->b_ops = &xfs_sb_buf_ops; +				xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); +			} else +				error = ENOMEM;  		} -		xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS); +  		/* -		 * If we get an error writing out the alternate superblocks, -		 * just issue a warning and continue.  The real work is -		 * already done and committed. +		 * If we get an error reading or writing alternate superblocks, +		 * continue.  xfs_repair chooses the "best" superblock based +		 * on most matches; if we break early, we'll leave more +		 * superblocks un-updated than updated, and xfs_repair may +		 * pick them over the properly-updated primary.  		 */ -		if (!(error = xfs_bwrite(mp, bp))) { +		if (error) { +			xfs_warn(mp, +		"error %d reading secondary superblock for ag %d", +				error, agno); +			saved_error = error;  			continue; -		} else { -			xfs_fs_cmn_err(CE_WARN, mp, +		} +		xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS); + +		error = xfs_bwrite(bp); +		xfs_buf_relse(bp); +		if (error) { +			xfs_warn(mp,  		"write error %d updating secondary superblock for ag %d",  				error, agno); -			break; /* no point in continuing */ +			saved_error = error; +			continue;  		}  	} -	return 0; +	return saved_error ? saved_error : error;   error0:  	xfs_trans_cancel(tp, XFS_TRANS_ABORT); @@ -611,19 +770,19 @@ out:   *   * We cannot use an inode here for this - that will push dirty state back up   * into the VFS and then periodic inode flushing will prevent log covering from - * making progress. Hence we log a field in the superblock instead. + * making progress. Hence we log a field in the superblock instead and use a + * synchronous transaction to ensure the superblock is immediately unpinned + * and can be written back.   */  int  xfs_fs_log_dummy( -	xfs_mount_t	*mp, -	int		flags) +	xfs_mount_t	*mp)  {  	xfs_trans_t	*tp;  	int		error;  	tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1, KM_SLEEP); -	error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, -					XFS_DEFAULT_LOG_COUNT); +	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0);  	if (error) {  		xfs_trans_cancel(tp, 0);  		return error; @@ -631,8 +790,7 @@ xfs_fs_log_dummy(  	/* log the UUID because it is an unchanging field */  	xfs_mod_sb(tp, XFS_SB_UUID); -	if (flags & SYNC_WAIT) -		xfs_trans_set_sync(tp); +	xfs_trans_set_sync(tp);  	return xfs_trans_commit(tp, 0);  } @@ -665,3 +823,63 @@ xfs_fs_goingdown(  	return 0;  } + +/* + * Force a shutdown of the filesystem instantly while keeping the filesystem + * consistent. We don't do an unmount here; just shutdown the shop, make sure + * that absolutely nothing persistent happens to this filesystem after this + * point. + */ +void +xfs_do_force_shutdown( +	xfs_mount_t	*mp, +	int		flags, +	char		*fname, +	int		lnnum) +{ +	int		logerror; + +	logerror = flags & SHUTDOWN_LOG_IO_ERROR; + +	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { +		xfs_notice(mp, +	"%s(0x%x) called from line %d of file %s.  Return address = 0x%p", +			__func__, flags, lnnum, fname, __return_address); +	} +	/* +	 * No need to duplicate efforts. +	 */ +	if (XFS_FORCED_SHUTDOWN(mp) && !logerror) +		return; + +	/* +	 * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't +	 * queue up anybody new on the log reservations, and wakes up +	 * everybody who's sleeping on log reservations to tell them +	 * the bad news. +	 */ +	if (xfs_log_force_umount(mp, logerror)) +		return; + +	if (flags & SHUTDOWN_CORRUPT_INCORE) { +		xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, +    "Corruption of in-memory data detected.  Shutting down filesystem"); +		if (XFS_ERRLEVEL_HIGH <= xfs_error_level) +			xfs_stack_trace(); +	} else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { +		if (logerror) { +			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, +		"Log I/O Error Detected.  Shutting down filesystem"); +		} else if (flags & SHUTDOWN_DEVICE_REQ) { +			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, +		"All device paths lost.  Shutting down filesystem"); +		} else if (!(flags & SHUTDOWN_REMOTE_REQ)) { +			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, +		"I/O Error Detected. Shutting down filesystem"); +		} +	} +	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { +		xfs_alert(mp, +	"Please umount the filesystem and rectify the problem(s)"); +	} +}  | 
