Skip to content

Commit 9dffc58

Browse files
johnpgarryDarrick J. Wong
authored andcommitted
xfs: update atomic write limits
Update the limits returned from xfs_get_atomic_write_{min, max, max_opt)(). No reflink support always means no CoW-based atomic writes. For updating xfs_get_atomic_write_min(), we support blocksize only and that depends on HW or reflink support. For updating xfs_get_atomic_write_max(), for no reflink, we are limited to blocksize but only if HW support. Otherwise we are limited to combined limit in mp->m_atomic_write_unit_max. For updating xfs_get_atomic_write_max_opt(), ultimately we are limited by the bdev atomic write limit. If xfs_get_atomic_write_max() does not report > 1x blocksize, then just continue to report 0 as before. Reviewed-by: Darrick J. Wong <[email protected]> [djwong: update comments in the helper functions] Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: John Garry <[email protected]>
1 parent 0c438dc commit 9dffc58

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

fs/xfs/xfs_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1557,7 +1557,7 @@ xfs_file_open(
15571557
if (xfs_is_shutdown(XFS_M(inode->i_sb)))
15581558
return -EIO;
15591559
file->f_mode |= FMODE_NOWAIT | FMODE_CAN_ODIRECT;
1560-
if (xfs_inode_can_hw_atomic_write(XFS_I(inode)))
1560+
if (xfs_get_atomic_write_min(XFS_I(inode)) > 0)
15611561
file->f_mode |= FMODE_CAN_ATOMIC_WRITE;
15621562
return generic_file_open(inode, file);
15631563
}

fs/xfs/xfs_iops.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,27 +605,67 @@ unsigned int
605605
xfs_get_atomic_write_min(
606606
struct xfs_inode *ip)
607607
{
608-
if (!xfs_inode_can_hw_atomic_write(ip))
609-
return 0;
608+
struct xfs_mount *mp = ip->i_mount;
609+
610+
/*
611+
* If we can complete an atomic write via atomic out of place writes,
612+
* then advertise a minimum size of one fsblock. Without this
613+
* mechanism, we can only guarantee atomic writes up to a single LBA.
614+
*
615+
* If out of place writes are not available, we can guarantee an atomic
616+
* write of exactly one single fsblock if the bdev will make that
617+
* guarantee for us.
618+
*/
619+
if (xfs_inode_can_hw_atomic_write(ip) || xfs_can_sw_atomic_write(mp))
620+
return mp->m_sb.sb_blocksize;
610621

611-
return ip->i_mount->m_sb.sb_blocksize;
622+
return 0;
612623
}
613624

614625
unsigned int
615626
xfs_get_atomic_write_max(
616627
struct xfs_inode *ip)
617628
{
618-
if (!xfs_inode_can_hw_atomic_write(ip))
629+
struct xfs_mount *mp = ip->i_mount;
630+
631+
/*
632+
* If out of place writes are not available, we can guarantee an atomic
633+
* write of exactly one single fsblock if the bdev will make that
634+
* guarantee for us.
635+
*/
636+
if (!xfs_can_sw_atomic_write(mp)) {
637+
if (xfs_inode_can_hw_atomic_write(ip))
638+
return mp->m_sb.sb_blocksize;
619639
return 0;
640+
}
620641

621-
return ip->i_mount->m_sb.sb_blocksize;
642+
/*
643+
* If we can complete an atomic write via atomic out of place writes,
644+
* then advertise a maximum size of whatever we can complete through
645+
* that means. Hardware support is reported via max_opt, not here.
646+
*/
647+
if (XFS_IS_REALTIME_INODE(ip))
648+
return XFS_FSB_TO_B(mp, mp->m_groups[XG_TYPE_RTG].awu_max);
649+
return XFS_FSB_TO_B(mp, mp->m_groups[XG_TYPE_AG].awu_max);
622650
}
623651

624652
unsigned int
625653
xfs_get_atomic_write_max_opt(
626654
struct xfs_inode *ip)
627655
{
628-
return 0;
656+
unsigned int awu_max = xfs_get_atomic_write_max(ip);
657+
658+
/* if the max is 1x block, then just keep behaviour that opt is 0 */
659+
if (awu_max <= ip->i_mount->m_sb.sb_blocksize)
660+
return 0;
661+
662+
/*
663+
* Advertise the maximum size of an atomic write that we can tell the
664+
* block device to perform for us. In general the bdev limit will be
665+
* less than our out of place write limit, but we don't want to exceed
666+
* the awu_max.
667+
*/
668+
return min(awu_max, xfs_inode_buftarg(ip)->bt_bdev_awu_max);
629669
}
630670

631671
static void

0 commit comments

Comments
 (0)