diff options
Diffstat (limited to 'fs/xfs/xfs_mount.c')
| -rw-r--r-- | fs/xfs/xfs_mount.c | 161 | 
1 files changed, 161 insertions, 0 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 00b53f479ece..29276fe60df9 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -666,6 +666,158 @@ xfs_agbtree_compute_maxlevels(  	mp->m_agbtree_maxlevels = max(levels, mp->m_refc_maxlevels);  } +/* Maximum atomic write IO size that the kernel allows. */ +static inline xfs_extlen_t xfs_calc_atomic_write_max(struct xfs_mount *mp) +{ +	return rounddown_pow_of_two(XFS_B_TO_FSB(mp, MAX_RW_COUNT)); +} + +static inline unsigned int max_pow_of_two_factor(const unsigned int nr) +{ +	return 1 << (ffs(nr) - 1); +} + +/* + * If the data device advertises atomic write support, limit the size of data + * device atomic writes to the greatest power-of-two factor of the AG size so + * that every atomic write unit aligns with the start of every AG.  This is + * required so that the per-AG allocations for an atomic write will always be + * aligned compatibly with the alignment requirements of the storage. + * + * If the data device doesn't advertise atomic writes, then there are no + * alignment restrictions and the largest out-of-place write we can do + * ourselves is the number of blocks that user files can allocate from any AG. + */ +static inline xfs_extlen_t xfs_calc_perag_awu_max(struct xfs_mount *mp) +{ +	if (mp->m_ddev_targp->bt_bdev_awu_min > 0) +		return max_pow_of_two_factor(mp->m_sb.sb_agblocks); +	return rounddown_pow_of_two(mp->m_ag_max_usable); +} + +/* + * Reflink on the realtime device requires rtgroups, and atomic writes require + * reflink. + * + * If the realtime device advertises atomic write support, limit the size of + * data device atomic writes to the greatest power-of-two factor of the rtgroup + * size so that every atomic write unit aligns with the start of every rtgroup. + * This is required so that the per-rtgroup allocations for an atomic write + * will always be aligned compatibly with the alignment requirements of the + * storage. + * + * If the rt device doesn't advertise atomic writes, then there are no + * alignment restrictions and the largest out-of-place write we can do + * ourselves is the number of blocks that user files can allocate from any + * rtgroup. + */ +static inline xfs_extlen_t xfs_calc_rtgroup_awu_max(struct xfs_mount *mp) +{ +	struct xfs_groups	*rgs = &mp->m_groups[XG_TYPE_RTG]; + +	if (rgs->blocks == 0) +		return 0; +	if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_bdev_awu_min > 0) +		return max_pow_of_two_factor(rgs->blocks); +	return rounddown_pow_of_two(rgs->blocks); +} + +/* Compute the maximum atomic write unit size for each section. */ +static inline void +xfs_calc_atomic_write_unit_max( +	struct xfs_mount	*mp) +{ +	struct xfs_groups	*ags = &mp->m_groups[XG_TYPE_AG]; +	struct xfs_groups	*rgs = &mp->m_groups[XG_TYPE_RTG]; + +	const xfs_extlen_t	max_write = xfs_calc_atomic_write_max(mp); +	const xfs_extlen_t	max_ioend = xfs_reflink_max_atomic_cow(mp); +	const xfs_extlen_t	max_agsize = xfs_calc_perag_awu_max(mp); +	const xfs_extlen_t	max_rgsize = xfs_calc_rtgroup_awu_max(mp); + +	ags->awu_max = min3(max_write, max_ioend, max_agsize); +	rgs->awu_max = min3(max_write, max_ioend, max_rgsize); + +	trace_xfs_calc_atomic_write_unit_max(mp, max_write, max_ioend, +			max_agsize, max_rgsize); +} + +/* + * Try to set the atomic write maximum to a new value that we got from + * userspace via mount option. + */ +int +xfs_set_max_atomic_write_opt( +	struct xfs_mount	*mp, +	unsigned long long	new_max_bytes) +{ +	const xfs_filblks_t	new_max_fsbs = XFS_B_TO_FSBT(mp, new_max_bytes); +	const xfs_extlen_t	max_write = xfs_calc_atomic_write_max(mp); +	const xfs_extlen_t	max_group = +		max(mp->m_groups[XG_TYPE_AG].blocks, +		    mp->m_groups[XG_TYPE_RTG].blocks); +	const xfs_extlen_t	max_group_write = +		max(xfs_calc_perag_awu_max(mp), xfs_calc_rtgroup_awu_max(mp)); +	int			error; + +	if (new_max_bytes == 0) +		goto set_limit; + +	ASSERT(max_write <= U32_MAX); + +	/* generic_atomic_write_valid enforces power of two length */ +	if (!is_power_of_2(new_max_bytes)) { +		xfs_warn(mp, + "max atomic write size of %llu bytes is not a power of 2", +				new_max_bytes); +		return -EINVAL; +	} + +	if (new_max_bytes & mp->m_blockmask) { +		xfs_warn(mp, + "max atomic write size of %llu bytes not aligned with fsblock", +				new_max_bytes); +		return -EINVAL; +	} + +	if (new_max_fsbs > max_write) { +		xfs_warn(mp, + "max atomic write size of %lluk cannot be larger than max write size %lluk", +				new_max_bytes >> 10, +				XFS_FSB_TO_B(mp, max_write) >> 10); +		return -EINVAL; +	} + +	if (new_max_fsbs > max_group) { +		xfs_warn(mp, + "max atomic write size of %lluk cannot be larger than allocation group size %lluk", +				new_max_bytes >> 10, +				XFS_FSB_TO_B(mp, max_group) >> 10); +		return -EINVAL; +	} + +	if (new_max_fsbs > max_group_write) { +		xfs_warn(mp, + "max atomic write size of %lluk cannot be larger than max allocation group write size %lluk", +				new_max_bytes >> 10, +				XFS_FSB_TO_B(mp, max_group_write) >> 10); +		return -EINVAL; +	} + +set_limit: +	error = xfs_calc_atomic_write_reservation(mp, new_max_fsbs); +	if (error) { +		xfs_warn(mp, + "cannot support completing atomic writes of %lluk", +				new_max_bytes >> 10); +		return error; +	} + +	xfs_calc_atomic_write_unit_max(mp); +	mp->m_awu_max_bytes = new_max_bytes; +	return 0; +} +  /* Compute maximum possible height for realtime btree types for this fs. */  static inline void  xfs_rtbtree_compute_maxlevels( @@ -1082,6 +1234,15 @@ xfs_mountfs(  		xfs_zone_gc_start(mp);  	} +	/* +	 * Pre-calculate atomic write unit max.  This involves computations +	 * derived from transaction reservations, so we must do this after the +	 * log is fully initialized. +	 */ +	error = xfs_set_max_atomic_write_opt(mp, mp->m_awu_max_bytes); +	if (error) +		goto out_agresv; +  	return 0;   out_agresv:  | 
