Skip to content

Commit c7be0d7

Browse files
committed
Merge patch series "iomap preliminaries for large atomic write for xfs with CoW"
Bring in the iomap changes required for xfs to support large atomic write with CoW. * patches from https://lore.kernel.org/r/20250303171120.2837067-1-john.g.garry@oracle.com: iomap: Lift blocksize restriction on atomic writes iomap: Support SW-based atomic writes iomap: Rename IOMAP_ATOMIC -> IOMAP_ATOMIC_HW Link: https://lore.kernel.org/r/20250303171120.2837067-1-john.g.garry@oracle.com Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 1743d38 + 786e308 commit c7be0d7

File tree

5 files changed

+36
-16
lines changed

5 files changed

+36
-16
lines changed

Documentation/filesystems/iomap/operations.rst

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,8 @@ IOMAP_WRITE`` with any combination of the following enhancements:
514514
if the mapping is unwritten and the filesystem cannot handle zeroing
515515
the unaligned regions without exposing stale contents.
516516

517-
* ``IOMAP_ATOMIC``: This write is being issued with torn-write
518-
protection.
517+
* ``IOMAP_ATOMIC_HW``: This write is being issued with torn-write
518+
protection based on HW-offload support.
519519
Only a single bio can be created for the write, and the write must
520520
not be split into multiple I/O requests, i.e. flag REQ_ATOMIC must be
521521
set.
@@ -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/ext4/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3467,7 +3467,7 @@ static inline bool ext4_want_directio_fallback(unsigned flags, ssize_t written)
34673467
return false;
34683468

34693469
/* atomic writes are all-or-nothing */
3470-
if (flags & IOMAP_ATOMIC)
3470+
if (flags & IOMAP_ATOMIC_HW)
34713471
return false;
34723472

34733473
/* can only try again if we wrote nothing */

fs/iomap/direct-io.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ static int iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio,
317317
* clearing the WRITE_THROUGH flag in the dio request.
318318
*/
319319
static inline blk_opf_t iomap_dio_bio_opflags(struct iomap_dio *dio,
320-
const struct iomap *iomap, bool use_fua, bool atomic)
320+
const struct iomap *iomap, bool use_fua, bool atomic_hw)
321321
{
322322
blk_opf_t opflags = REQ_SYNC | REQ_IDLE;
323323

@@ -329,7 +329,7 @@ static inline blk_opf_t iomap_dio_bio_opflags(struct iomap_dio *dio,
329329
opflags |= REQ_FUA;
330330
else
331331
dio->flags &= ~IOMAP_DIO_WRITE_THROUGH;
332-
if (atomic)
332+
if (atomic_hw)
333333
opflags |= REQ_ATOMIC;
334334

335335
return opflags;
@@ -340,8 +340,8 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
340340
const struct iomap *iomap = &iter->iomap;
341341
struct inode *inode = iter->inode;
342342
unsigned int fs_block_size = i_blocksize(inode), pad;
343+
bool atomic_hw = iter->flags & IOMAP_ATOMIC_HW;
343344
const loff_t length = iomap_length(iter);
344-
bool atomic = iter->flags & IOMAP_ATOMIC;
345345
loff_t pos = iter->pos;
346346
blk_opf_t bio_opf;
347347
struct bio *bio;
@@ -351,7 +351,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
351351
u64 copied = 0;
352352
size_t orig_count;
353353

354-
if (atomic && length != fs_block_size)
354+
if (atomic_hw && length != iter->len)
355355
return -EINVAL;
356356

357357
if ((pos | length) & (bdev_logical_block_size(iomap->bdev) - 1) ||
@@ -428,7 +428,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
428428
goto out;
429429
}
430430

431-
bio_opf = iomap_dio_bio_opflags(dio, iomap, use_fua, atomic);
431+
bio_opf = iomap_dio_bio_opflags(dio, iomap, use_fua, atomic_hw);
432432

433433
nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS);
434434
do {
@@ -461,7 +461,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
461461
}
462462

463463
n = bio->bi_iter.bi_size;
464-
if (WARN_ON_ONCE(atomic && n != length)) {
464+
if (WARN_ON_ONCE(atomic_hw && n != length)) {
465465
/*
466466
* This bio should have covered the complete length,
467467
* which it doesn't, so error. We may need to zero out
@@ -652,9 +652,6 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
652652
if (iocb->ki_flags & IOCB_NOWAIT)
653653
iomi.flags |= IOMAP_NOWAIT;
654654

655-
if (iocb->ki_flags & IOCB_ATOMIC)
656-
iomi.flags |= IOMAP_ATOMIC;
657-
658655
if (iov_iter_rw(iter) == READ) {
659656
/* reads can always complete inline */
660657
dio->flags |= IOMAP_DIO_INLINE_COMP;
@@ -689,6 +686,11 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
689686
iomi.flags |= IOMAP_OVERWRITE_ONLY;
690687
}
691688

689+
if (dio_flags & IOMAP_DIO_ATOMIC_SW)
690+
iomi.flags |= IOMAP_ATOMIC_SW;
691+
else if (iocb->ki_flags & IOCB_ATOMIC)
692+
iomi.flags |= IOMAP_ATOMIC_HW;
693+
692694
/* for data sync or sync, we need sync completion processing */
693695
if (iocb_is_dsync(iocb)) {
694696
dio->flags |= IOMAP_DIO_NEED_SYNC;

fs/iomap/trace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ DEFINE_RANGE_EVENT(iomap_dio_rw_queued);
9999
{ IOMAP_FAULT, "FAULT" }, \
100100
{ IOMAP_DIRECT, "DIRECT" }, \
101101
{ IOMAP_NOWAIT, "NOWAIT" }, \
102-
{ IOMAP_ATOMIC, "ATOMIC" }
102+
{ IOMAP_ATOMIC_HW, "ATOMIC_HW" }
103103

104104
#define IOMAP_F_FLAGS_STRINGS \
105105
{ IOMAP_F_NEW, "NEW" }, \

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 (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)