diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 53a1997b9866..1fa442b646db 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -353,6 +353,15 @@ static inline bool xfs_inode_has_bigrtalloc(const struct xfs_inode *ip) return XFS_IS_REALTIME_INODE(ip) && ip->i_mount->m_sb.sb_rextsize > 1; } +/* + * Return the type of the group that data for a given inode is allocated from. + */ +static inline enum xfs_group_type +xfs_inode_group_type(const struct xfs_inode *ip) +{ + return XFS_IS_REALTIME_INODE(ip) ? XG_TYPE_RTG : XG_TYPE_AG; +} + /* * Return the buftarg used for data allocations on a given inode. */ diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index d1306e723899..13d61f3a1a24 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -642,19 +642,30 @@ xfs_get_atomic_write_max( * then advertise a maximum size of whatever we can complete through * that means. Hardware support is reported via max_opt, not here. */ - if (XFS_IS_REALTIME_INODE(ip)) - return XFS_FSB_TO_B(mp, mp->m_groups[XG_TYPE_RTG].awu_max); - return XFS_FSB_TO_B(mp, mp->m_groups[XG_TYPE_AG].awu_max); + return XFS_FSB_TO_B(mp, mp->m_groups[xfs_inode_group_type(ip)].awu_max); +} + +static inline xfs_fsize_t xfs_get_atomic_hw_write_align( + const struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + + return XFS_FSB_TO_B( + mp, xfs_calc_group_awu_align_max(mp, xfs_inode_group_type(ip))); } unsigned int xfs_get_atomic_write_max_opt( struct xfs_inode *ip) { - unsigned int awu_max = xfs_get_atomic_write_max(ip); + struct xfs_mount *mp = ip->i_mount; + unsigned int max_opt; + const unsigned int sw_awu_max = xfs_get_atomic_write_max(ip); + const unsigned int hw_awu_max = xfs_inode_buftarg(ip)->bt_awu_max; + const xfs_fsize_t hw_align_max = xfs_get_atomic_hw_write_align(ip); /* if the max is 1x block, then just keep behaviour that opt is 0 */ - if (awu_max <= ip->i_mount->m_sb.sb_blocksize) + if (sw_awu_max <= mp->m_sb.sb_blocksize) return 0; /* @@ -663,7 +674,14 @@ xfs_get_atomic_write_max_opt( * less than our out of place write limit, but we don't want to exceed * the awu_max. */ - return min(awu_max, xfs_inode_buftarg(ip)->bt_awu_max); + max_opt = min(sw_awu_max, hw_awu_max); + + /* + * HW atomic writes also have to be naturally aligned on disk, so we + * cannot promise more than the largest extent that the allocator is + * able to align within a group. + */ + return min_t(xfs_fsize_t, max_opt, hw_align_max); } static void diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 8838eff1f054..60931cb00817 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -681,15 +681,13 @@ static inline xfs_extlen_t xfs_calc_atomic_write_max(struct xfs_mount *mp) } /* - * If the underlying device advertises atomic write support, limit the size of - * atomic writes to the greatest power-of-two factor of the group size so - * that every atomic write unit aligns with the start of every group. This is - * required so that the allocations for an atomic write will always be - * aligned compatibly with the alignment requirements of the storage. + * The largest out of place write is the number of blocks that user files can + * allocate from any group. * - * If the 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 group. + * This is a software limit, so it deliberately does not take the alignment + * requirements of the storage into account. An atomic write that cannot be + * handed to the device as a single naturally aligned REQ_ATOMIC bio is + * completed through the COW fork instead, which has no such requirement. */ static xfs_extlen_t xfs_calc_group_awu_max( @@ -697,15 +695,30 @@ xfs_calc_group_awu_max( enum xfs_group_type type) { struct xfs_groups *g = &mp->m_groups[type]; - struct xfs_buftarg *btp = xfs_group_type_buftarg(mp, type); if (g->blocks == 0) return 0; - if (btp && btp->bt_awu_min > 0) - return max_pow_of_two_factor(g->blocks); return rounddown_pow_of_two(g->blocks); } +/* + * Compute the largest atomic write unit for which the allocator can guarantee + * naturally aligned extents in this group type. + * + * Hardware atomic writes have to be naturally aligned on disk. + */ +xfs_extlen_t +xfs_calc_group_awu_align_max( + struct xfs_mount *mp, + enum xfs_group_type type) +{ + struct xfs_groups *g = &mp->m_groups[type]; + + if (g->blocks == 0) + return 0; + return max_pow_of_two_factor(g->blocks); +} + /* Compute the maximum atomic write unit size for each section. */ static inline void xfs_calc_atomic_write_unit_max( diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 894ff2f4ecbd..cbcfb89c67a4 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -820,6 +820,8 @@ static inline void xfs_mod_sb_delalloc(struct xfs_mount *mp, int64_t delta) int xfs_set_max_atomic_write_opt(struct xfs_mount *mp, unsigned long long new_max_bytes); +xfs_extlen_t xfs_calc_group_awu_align_max(struct xfs_mount *mp, + enum xfs_group_type type); static inline struct xfs_buftarg * xfs_group_type_buftarg(