diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 49db1611de96f249a02ea9ba828425e9616719fb..d4185b63dcd68c5936f34a41dcf523ee65023958 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -814,6 +814,11 @@ xfs_file_write_iter( return xfs_file_dax_write(iocb, from); if (iocb->ki_flags & IOCB_DIRECT) { + + if (xfs_inode_atomicwrites(ip) && + xfs_has_atomicalways(ip->i_mount) && + !(iocb->ki_flags & IOCB_ATOMIC)) + iocb->ki_flags |= IOCB_ATOMIC; /* * Allow a directio write to fall back to a buffered * write *only* in the case that we're doing a reflink diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 888d6bf9bea7adf2dd30ba73b74e7b2238ce7ed8..6b952ff031b6dea9aa62448419a2a046b69e9194 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -279,6 +279,7 @@ typedef struct xfs_mount { /* Mount features */ +#define XFS_FEAT_ATOMICALWAYS (1ULL << 47) /* convert dio to atomic writes always */ #define XFS_FEAT_NOATTR2 (1ULL << 48) /* disable attr2 creation */ #define XFS_FEAT_NOALIGN (1ULL << 49) /* ignore alignment */ #define XFS_FEAT_ALLOCSIZE (1ULL << 50) /* user specified allocation size */ @@ -365,6 +366,7 @@ __XFS_HAS_FEAT(dax_always, DAX_ALWAYS) __XFS_HAS_FEAT(dax_never, DAX_NEVER) __XFS_HAS_FEAT(norecovery, NORECOVERY) __XFS_HAS_FEAT(nouuid, NOUUID) +__XFS_HAS_FEAT(atomicalways, ATOMICALWAYS) /* * Operational mount state flags diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index f2ff547e760c0b6e1ec547236bf5786c67987f50..451386e21262f72a5d63921c86fe4cd045fc631f 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -116,7 +116,7 @@ enum { Opt_filestreams, Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota, Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce, - Opt_discard, Opt_nodiscard, Opt_dax, Opt_dax_enum, + Opt_discard, Opt_nodiscard, Opt_dax, Opt_dax_enum, Opt_atomicalways, }; static const struct fs_parameter_spec xfs_fs_parameters[] = { @@ -161,6 +161,7 @@ static const struct fs_parameter_spec xfs_fs_parameters[] = { fsparam_flag("nodiscard", Opt_nodiscard), fsparam_flag("dax", Opt_dax), fsparam_enum("dax", Opt_dax_enum, dax_param_enums), + fsparam_flag("atomicalways", Opt_atomicalways), {} }; @@ -189,6 +190,7 @@ xfs_fs_show_options( { XFS_FEAT_LARGE_IOSIZE, ",largeio" }, { XFS_FEAT_DAX_ALWAYS, ",dax=always" }, { XFS_FEAT_DAX_NEVER, ",dax=never" }, + { XFS_FEAT_ATOMICALWAYS, ",atomicalways"}, { 0, NULL } }; struct xfs_mount *mp = XFS_M(root->d_sb); @@ -1361,6 +1363,9 @@ xfs_fc_parse_param( xfs_fs_warn_deprecated(fc, param, XFS_FEAT_NOATTR2, true); parsing_mp->m_features |= XFS_FEAT_NOATTR2; return 0; + case Opt_atomicalways: + parsing_mp->m_features |= XFS_FEAT_ATOMICALWAYS; + return 0; default: xfs_warn(parsing_mp, "unknown mount option [%s].", param->key); return -EINVAL; @@ -1671,9 +1676,33 @@ xfs_fc_fill_super( } - if (xfs_has_atomicwrites(mp)) + if (xfs_has_atomicwrites(mp)) { + if (!xfs_has_forcealign(mp)) { + xfs_alert(mp, + "forcealign should support for atomic writes!"); + error = -EINVAL; + goto out_filestream_unmount; + } + xfs_warn(mp, "EXPERIMENTAL atomicwrites feature in use. Use at your own risk!"); + } + + if (xfs_has_atomicalways(mp)) { + if (!xfs_has_atomicwrites(mp)) { + xfs_alert(mp, + "mounting with \"atomicalways\" option, but fs not support atomic writes!"); + error = -EINVAL; + goto out_filestream_unmount; + } + + if (!bdev_can_atomic_write(mp->m_ddev_targp->bt_bdev)) { + xfs_alert(mp, + "mounting with \"atomicalways\" option, but device not support atomic writes!"); + error = -EINVAL; + goto out_filestream_unmount; + } + } if (xfs_has_reflink(mp)) { if (mp->m_sb.sb_rblocks) {