diff options
Diffstat (limited to 'fs/xfs/xfs_sb.c')
| -rw-r--r-- | fs/xfs/xfs_sb.c | 100 | 
1 files changed, 51 insertions, 49 deletions
diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c index a5b59d92eb7..7703fa6770f 100644 --- a/fs/xfs/xfs_sb.c +++ b/fs/xfs/xfs_sb.c @@ -17,34 +17,26 @@   */  #include "xfs.h"  #include "xfs_fs.h" +#include "xfs_shared.h"  #include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h"  #include "xfs_bit.h" -#include "xfs_log.h" -#include "xfs_inum.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h"  #include "xfs_sb.h"  #include "xfs_ag.h"  #include "xfs_mount.h" -#include "xfs_da_btree.h" -#include "xfs_dir2_format.h" -#include "xfs_dir2.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_dinode.h"  #include "xfs_inode.h" -#include "xfs_btree.h"  #include "xfs_ialloc.h"  #include "xfs_alloc.h" -#include "xfs_rtalloc.h" -#include "xfs_bmap.h"  #include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_fsops.h"  #include "xfs_trace.h"  #include "xfs_cksum.h" +#include "xfs_trans.h"  #include "xfs_buf_item.h" +#include "xfs_dinode.h" +#include "xfs_bmap_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h"  /*   * Physical superblock buffer manipulations. Shared with libxfs in userspace. @@ -209,10 +201,6 @@ xfs_mount_validate_sb(  	 * write validation, we don't need to check feature masks.  	 */  	if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { -		xfs_alert(mp, -"Version 5 superblock detected. This kernel has EXPERIMENTAL support enabled!\n" -"Use of these features in this kernel is at your own risk!"); -  		if (xfs_sb_has_compat_feature(sbp,  					XFS_SB_FEAT_COMPAT_UNKNOWN)) {  			xfs_warn(mp, @@ -249,13 +237,13 @@ xfs_mount_validate_sb(  	if (xfs_sb_version_has_pquotino(sbp)) {  		if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {  			xfs_notice(mp, -			   "Version 5 of Super block has XFS_OQUOTA bits.\n"); +			   "Version 5 of Super block has XFS_OQUOTA bits.");  			return XFS_ERROR(EFSCORRUPTED);  		}  	} else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |  				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {  			xfs_notice(mp, -"Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits.\n"); +"Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits.");  			return XFS_ERROR(EFSCORRUPTED);  	} @@ -296,15 +284,16 @@ xfs_mount_validate_sb(  	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||  	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||  	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		|| +	    sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||  	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||  	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||  	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||  	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||  	    sbp->sb_dblocks == 0					||  	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			|| -	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) { -		XFS_CORRUPTION_ERROR("SB sanity check failed", -				XFS_ERRLEVEL_LOW, mp, sbp); +	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp)			|| +	    sbp->sb_shared_vn != 0)) { +		xfs_notice(mp, "SB sanity check failed");  		return XFS_ERROR(EFSCORRUPTED);  	} @@ -345,15 +334,6 @@ xfs_mount_validate_sb(  		xfs_warn(mp, "Offline file system operation in progress!");  		return XFS_ERROR(EFSCORRUPTED);  	} - -	/* -	 * Version 1 directory format has never worked on Linux. -	 */ -	if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { -		xfs_warn(mp, "file system using version 1 directory format"); -		return XFS_ERROR(ENOSYS); -	} -  	return 0;  } @@ -503,10 +483,16 @@ xfs_sb_quota_to_disk(  	}  	/* -	 * GQUOTINO and PQUOTINO cannot be used together in versions -	 * of superblock that do not have pquotino. from->sb_flags -	 * tells us which quota is active and should be copied to -	 * disk. +	 * GQUOTINO and PQUOTINO cannot be used together in versions of +	 * superblock that do not have pquotino. from->sb_flags tells us which +	 * quota is active and should be copied to disk. If neither are active, +	 * make sure we write NULLFSINO to the sb_gquotino field as a quota +	 * inode value of "0" is invalid when the XFS_SB_VERSION_QUOTA feature +	 * bit is set. +	 * +	 * Note that we don't need to handle the sb_uquotino or sb_pquotino here +	 * as they do not require any translation. Hence the main sb field loop +	 * will write them appropriately from the in-core superblock.  	 */  	if ((*fields & XFS_SB_GQUOTINO) &&  				(from->sb_qflags & XFS_GQUOTA_ACCT)) @@ -514,6 +500,17 @@ xfs_sb_quota_to_disk(  	else if ((*fields & XFS_SB_PQUOTINO) &&  				(from->sb_qflags & XFS_PQUOTA_ACCT))  		to->sb_gquotino = cpu_to_be64(from->sb_pquotino); +	else { +		/* +		 * We can't rely on just the fields being logged to tell us +		 * that it is safe to write NULLFSINO - we should only do that +		 * if quotas are not actually enabled. Hence only write +		 * NULLFSINO if both in-core quota inodes are NULL. +		 */ +		if (from->sb_gquotino == NULLFSINO && +		    from->sb_pquotino == NULLFSINO) +			to->sb_gquotino = cpu_to_be64(NULLFSINO); +	}  	*fields &= ~(XFS_SB_PQUOTINO | XFS_SB_GQUOTINO);  } @@ -596,6 +593,11 @@ xfs_sb_verify(   * single bit error could clear the feature bit and unused parts of the   * superblock are supposed to be zero. Hence a non-null crc field indicates that   * we've potentially lost a feature bit and we should check it anyway. + * + * However, past bugs (i.e. in growfs) left non-zeroed regions beyond the + * last field in V4 secondary superblocks.  So for secondary superblocks, + * we are more forgiving, and ignore CRC failures if the primary doesn't + * indicate that the fs version is V5.   */  static void  xfs_sb_read_verify( @@ -614,19 +616,22 @@ xfs_sb_read_verify(  						XFS_SB_VERSION_5) ||  	     dsb->sb_crc != 0)) { -		if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize), -				      offsetof(struct xfs_sb, sb_crc))) { -			error = EFSCORRUPTED; -			goto out_error; +		if (!xfs_buf_verify_cksum(bp, XFS_SB_CRC_OFF)) { +			/* Only fail bad secondaries on a known V5 filesystem */ +			if (bp->b_bn == XFS_SB_DADDR || +			    xfs_sb_version_hascrc(&mp->m_sb)) { +				error = EFSBADCRC; +				goto out_error; +			}  		}  	}  	error = xfs_sb_verify(bp, true);  out_error:  	if (error) { -		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, -				     mp, bp->b_addr);  		xfs_buf_ioerror(bp, error); +		if (error == EFSCORRUPTED || error == EFSBADCRC) +			xfs_verifier_error(bp);  	}  } @@ -642,7 +647,6 @@ xfs_sb_quiet_read_verify(  {  	struct xfs_dsb	*dsb = XFS_BUF_TO_SBP(bp); -  	if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {  		/* XFS filesystem, verify noisily! */  		xfs_sb_read_verify(bp); @@ -662,9 +666,8 @@ xfs_sb_write_verify(  	error = xfs_sb_verify(bp, false);  	if (error) { -		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, -				     mp, bp->b_addr);  		xfs_buf_ioerror(bp, error); +		xfs_verifier_error(bp);  		return;  	} @@ -674,8 +677,7 @@ xfs_sb_write_verify(  	if (bip)  		XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn); -	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), -			 offsetof(struct xfs_sb, sb_crc)); +	xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF);  }  const struct xfs_buf_ops xfs_sb_buf_ops = {  | 
