diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 7d0d82353a745..b14761ec96b87 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -3351,6 +3351,17 @@ xfs_bmap_btalloc_accounting(
 		args->len);
 }
 
+static inline bool
+xfs_bmap_use_forcealign(
+	const struct xfs_bmalloca	*ap)
+{
+	if (!xfs_inode_force_align(ap->ip))
+		return false;
+
+	return  (ap->flags & XFS_BMAPI_COWFORK) ||
+		(ap->datatype & XFS_ALLOC_USERDATA);
+}
+
 static int
 xfs_bmap_compute_alignments(
 	struct xfs_bmalloca	*ap,
@@ -3366,6 +3377,17 @@ xfs_bmap_compute_alignments(
 	else if (mp->m_dalign)
 		stripe_align = mp->m_dalign;
 
+	/*
+	 * File data mappings with forced alignment can use the stripe
+	 * alignment if it's a multiple of the forcealign value.  Otherwise,
+	 * use the regular forcealign value.
+	 */
+	if (xfs_bmap_use_forcealign(ap)) {
+		if (!stripe_align || stripe_align % mp->m_sb.sb_rextsize)
+			stripe_align = mp->m_sb.sb_rextsize;
+		args->alignment = stripe_align;
+	}
+
 	if (ap->flags & XFS_BMAPI_COWFORK)
 		align = xfs_get_cowextsz_hint(ap->ip);
 	else if (ap->datatype & XFS_ALLOC_USERDATA)
@@ -3438,6 +3460,9 @@ xfs_bmap_exact_minlen_extent_alloc(
 
 	ASSERT(ap->length);
 
+	if (xfs_inode_force_align(ap->ip))
+		return -ENOSPC;
+
 	if (ap->minlen != 1) {
 		ap->blkno = NULLFSBLOCK;
 		ap->length = 0;
@@ -3511,6 +3536,7 @@ xfs_bmap_btalloc_at_eof(
 {
 	struct xfs_mount	*mp = args->mp;
 	struct xfs_perag	*caller_pag = args->pag;
+	int			orig_alignment = args->alignment;
 	int			error;
 
 	/*
@@ -3585,10 +3611,10 @@ xfs_bmap_btalloc_at_eof(
 
 	/*
 	 * Allocation failed, so turn return the allocation args to their
-	 * original non-aligned state so the caller can proceed on allocation
-	 * failure as if this function was never called.
+	 * original state so the caller can proceed on allocation failure as
+	 * if this function was never called.
 	 */
-	args->alignment = 1;
+	args->alignment = orig_alignment;
 	return 0;
 }
 
@@ -3611,6 +3637,10 @@ xfs_bmap_btalloc_low_space(
 {
 	int			error;
 
+	/* Don't try unaligned last-chance allocations with forcealign */
+	if (xfs_inode_force_align(ap->ip))
+		return -ENOSPC;
+
 	if (args->minlen > ap->minlen) {
 		args->minlen = ap->minlen;
 		error = xfs_alloc_vextent_start_ag(args, ap->blkno);
@@ -4115,7 +4145,9 @@ xfs_bmap_alloc_userdata(
 		if (bma->offset == 0)
 			bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
 
-		if (mp->m_dalign && bma->length >= mp->m_dalign) {
+		/* forcealign mode reuses the stripe unit alignment code */
+		if (xfs_inode_force_align(bma->ip) ||
+		    (mp->m_dalign && bma->length >= mp->m_dalign)) {
 			error = xfs_bmap_isaeof(bma, whichfork);
 			if (error)
 				return error;
@@ -6381,6 +6413,10 @@ xfs_extlen_t
 xfs_get_extsz_hint(
 	struct xfs_inode	*ip)
 {
+	/* forcealign means we align to rextsize */
+	if (xfs_inode_force_align(ip))
+		return ip->i_mount->m_sb.sb_rextsize;
+
 	/*
 	 * No point in aligning allocations if we need to COW to actually
 	 * write to them.
@@ -6405,6 +6441,10 @@ xfs_get_cowextsz_hint(
 {
 	xfs_extlen_t		a, b;
 
+	/* forcealign means we align to rextsize */
+	if (xfs_inode_force_align(ip))
+		return ip->i_mount->m_sb.sb_rextsize;
+
 	a = 0;
 	if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
 		a = ip->i_cowextsize;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 559e8e7855952..3bfbcbed1bd68 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -185,7 +185,9 @@ xfs_eof_alignment(
 		 * If mounted with the "-o swalloc" option the alignment is
 		 * increased from the strip unit size to the stripe width.
 		 */
-		if (mp->m_swidth && xfs_has_swalloc(mp))
+		if (xfs_inode_force_align(ip))
+			align = xfs_get_extsz_hint(ip);
+		else if (mp->m_swidth && xfs_has_swalloc(mp))
 			align = mp->m_swidth;
 		else if (mp->m_dalign)
 			align = mp->m_dalign;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 0c54522404963..da39da13fcd7d 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1803,6 +1803,10 @@ xfs_reflink_remap_prep(
 	if (IS_DAX(inode_in) != IS_DAX(inode_out))
 		goto out_unlock;
 
+	/* XXX Can't reflink forcealign files for now */
+	if (xfs_inode_force_align(src) || xfs_inode_force_align(dest))
+		goto out_unlock;
+
 	/* Check non-power of two alignment issues, if necessary. */
 	if (XFS_IS_REALTIME_INODE(dest) && !is_power_of_2(alloc_unit)) {
 		ret = xfs_reflink_remap_check_rtalign(src, pos_in, dest,
