Skip to content

Commit 794ca29

Browse files
johnpgarrybrauner
authored andcommitted
iomap: Support SW-based atomic writes
Currently atomic write support requires dedicated HW support. This imposes a restriction on the filesystem that disk blocks need to be aligned and contiguously mapped to FS blocks to issue atomic writes. XFS has no method to guarantee FS block alignment for regular, non-RT files. As such, atomic writes are currently limited to 1x FS block there. To deal with the scenario that we are issuing an atomic write over misaligned or discontiguous data blocks - and raise the atomic write size limit - support a SW-based software emulated atomic write mode. For XFS, this SW-based atomic writes would use CoW support to issue emulated untorn writes. It is the responsibility of the FS to detect discontiguous atomic writes and switch to IOMAP_DIO_ATOMIC_SW mode and retry the write. Indeed, SW-based atomic writes could be used always when the mounted bdev does not support HW offload, but this strategy is not initially expected to be used. Reviewed-by: "Darrick J. Wong" <djwong@kernel.org> Signed-off-by: John Garry <john.g.garry@oracle.com> Link: https://lore.kernel.org/r/20250303171120.2837067-6-john.g.garry@oracle.com Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent b4de0e9 commit 794ca29

3 files changed

Lines changed: 24 additions & 4 deletions

File tree

Documentation/filesystems/iomap/operations.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,20 @@ IOMAP_WRITE`` with any combination of the following enhancements:
526526
conversion or copy on write), all updates for the entire file range
527527
must be committed atomically as well.
528528
Only one space mapping is allowed per untorn write.
529-
Untorn writes must be aligned to, and must not be longer than, a
530-
single file block.
529+
Untorn writes may be longer than a single file block. In all cases,
530+
the mapping start disk block must have at least the same alignment as
531+
the write offset.
532+
533+
* ``IOMAP_ATOMIC_SW``: This write is being issued with torn-write
534+
protection via a software mechanism provided by the filesystem.
535+
All the disk block alignment and single bio restrictions which apply
536+
to IOMAP_ATOMIC_HW do not apply here.
537+
SW-based untorn writes would typically be used as a fallback when
538+
HW-based untorn writes may not be issued, e.g. the range of the write
539+
covers multiple extents, meaning that it is not possible to issue
540+
a single bio.
541+
All filesystem metadata updates for the entire file range must be
542+
committed atomically as well.
531543

532544
Callers commonly hold ``i_rwsem`` in shared or exclusive mode before
533545
calling this function.

fs/iomap/direct-io.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,9 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
686686
iomi.flags |= IOMAP_OVERWRITE_ONLY;
687687
}
688688

689-
if (iocb->ki_flags & IOCB_ATOMIC)
689+
if (dio_flags & IOMAP_DIO_ATOMIC_SW)
690+
iomi.flags |= IOMAP_ATOMIC_SW;
691+
else if (iocb->ki_flags & IOCB_ATOMIC)
690692
iomi.flags |= IOMAP_ATOMIC_HW;
691693

692694
/* for data sync or sync, we need sync completion processing */

include/linux/iomap.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,9 @@ struct iomap_folio_ops {
189189
#else
190190
#define IOMAP_DAX 0
191191
#endif /* CONFIG_FS_DAX */
192-
#define IOMAP_ATOMIC_HW (1 << 9)
192+
#define IOMAP_ATOMIC_HW (1 << 9) /* HW-based torn-write protection */
193193
#define IOMAP_DONTCACHE (1 << 10)
194+
#define IOMAP_ATOMIC_SW (1 << 11)/* SW-based torn-write protection */
194195

195196
struct iomap_ops {
196197
/*
@@ -502,6 +503,11 @@ struct iomap_dio_ops {
502503
*/
503504
#define IOMAP_DIO_PARTIAL (1 << 2)
504505

506+
/*
507+
* Use software-based torn-write protection.
508+
*/
509+
#define IOMAP_DIO_ATOMIC_SW (1 << 3)
510+
505511
ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
506512
const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
507513
unsigned int dio_flags, void *private, size_t done_before);

0 commit comments

Comments
 (0)