Skip to content

Commit 81cf931

Browse files
Christoph Hellwigkawasaki
authored andcommitted
iomap: hide ioends from the generic writeback code
Replace the ioend pointer in iomap_writeback_ctx with a void *wb_ctx one to facilitate non-block, non-ioend writeback for use. Rename the submit_ioend method to writeback_submit and make it mandatory so that the generic writeback code stops seeing ioends and bios. Co-developed-by: Joanne Koong <[email protected]> Signed-off-by: Joanne Koong <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Brian Foster <[email protected]> Reviewed-by: "Darrick J. Wong" <[email protected]> Acked-by: Damien Le Moal <[email protected]>
1 parent 6c0c068 commit 81cf931

7 files changed

Lines changed: 100 additions & 90 deletions

File tree

Documentation/filesystems/iomap/operations.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ The ``ops`` structure must be specified and is as follows:
284284
285285
struct iomap_writeback_ops {
286286
int (*writeback_range)(struct iomap_writepage_ctx *wpc,
287-
struct folio *folio, u64 pos, unsigned int len, u64 end_pos);
288-
int (*submit_ioend)(struct iomap_writepage_ctx *wpc, int status);
287+
struct folio *folio, u64 pos, unsigned int len, u64 end_pos);
288+
int (*writeback_submit)(struct iomap_writepage_ctx *wpc, int error);
289289
};
290290
291291
The fields are as follows:
@@ -316,13 +316,15 @@ The fields are as follows:
316316
clean pagecache.
317317
This function must be supplied by the filesystem.
318318

319-
- ``submit_ioend``: Allows the file systems to hook into writeback bio
320-
submission.
319+
- ``writeback_submit``: Submit the previous built writeback context.
320+
Block based file systems should use the iomap_ioend_writeback_submit
321+
helper, other file system can implement their own.
322+
File systems can optionall to hook into writeback bio submission.
321323
This might include pre-write space accounting updates, or installing
322324
a custom ``->bi_end_io`` function for internal purposes, such as
323325
deferring the ioend completion to a workqueue to run metadata update
324326
transactions from process context before submitting the bio.
325-
This function is optional.
327+
This function must be supplied by the filesystem.
326328

327329
Pagecache Writeback Completion
328330
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -336,10 +338,9 @@ If the write failed, it will also set the error bits on the folios and
336338
the address space.
337339
This can happen in interrupt or process context, depending on the
338340
storage device.
339-
340341
Filesystems that need to update internal bookkeeping (e.g. unwritten
341-
extent conversions) should provide a ``->submit_ioend`` function to
342-
set ``struct iomap_end::bio::bi_end_io`` to its own function.
342+
extent conversions) should set their own bi_end_io on the bios
343+
submitted by ``->submit_writeback``
343344
This function should call ``iomap_finish_ioends`` after finishing its
344345
own work (e.g. unwritten extent conversion).
345346

block/fops.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ static ssize_t blkdev_writeback_range(struct iomap_writepage_ctx *wpc,
560560

561561
static const struct iomap_writeback_ops blkdev_writeback_ops = {
562562
.writeback_range = blkdev_writeback_range,
563+
.writeback_submit = iomap_ioend_writeback_submit,
563564
};
564565

565566
static int blkdev_writepages(struct address_space *mapping,

fs/gfs2/bmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,4 +2490,5 @@ static ssize_t gfs2_writeback_range(struct iomap_writepage_ctx *wpc,
24902490

24912491
const struct iomap_writeback_ops gfs2_writeback_ops = {
24922492
.writeback_range = gfs2_writeback_range,
2493+
.writeback_submit = iomap_ioend_writeback_submit,
24932494
};

fs/iomap/buffered-io.c

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,7 @@ u32 iomap_finish_ioend_buffered(struct iomap_ioend *ioend)
15741574
return folio_count;
15751575
}
15761576

1577-
static void iomap_writepage_end_bio(struct bio *bio)
1577+
static void ioend_writeback_end_bio(struct bio *bio)
15781578
{
15791579
struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
15801580

@@ -1583,42 +1583,30 @@ static void iomap_writepage_end_bio(struct bio *bio)
15831583
}
15841584

15851585
/*
1586-
* Submit an ioend.
1587-
*
1588-
* If @error is non-zero, it means that we have a situation where some part of
1589-
* the submission process has failed after we've marked pages for writeback.
1590-
* We cannot cancel ioend directly in that case, so call the bio end I/O handler
1591-
* with the error status here to run the normal I/O completion handler to clear
1592-
* the writeback bit and let the file system proess the errors.
1586+
* We cannot cancel the ioend directly in case of an error, so call the bio end
1587+
* I/O handler with the error status here to run the normal I/O completion
1588+
* handler.
15931589
*/
1594-
static int iomap_submit_ioend(struct iomap_writepage_ctx *wpc, int error)
1590+
int iomap_ioend_writeback_submit(struct iomap_writepage_ctx *wpc, int error)
15951591
{
1596-
if (!wpc->ioend)
1597-
return error;
1592+
struct iomap_ioend *ioend = wpc->wb_ctx;
15981593

1599-
/*
1600-
* Let the file systems prepare the I/O submission and hook in an I/O
1601-
* comletion handler. This also needs to happen in case after a
1602-
* failure happened so that the file system end I/O handler gets called
1603-
* to clean up.
1604-
*/
1605-
if (wpc->ops->submit_ioend) {
1606-
error = wpc->ops->submit_ioend(wpc, error);
1607-
} else {
1608-
if (WARN_ON_ONCE(wpc->iomap.flags & IOMAP_F_ANON_WRITE))
1609-
error = -EIO;
1610-
if (!error)
1611-
submit_bio(&wpc->ioend->io_bio);
1612-
}
1594+
if (!ioend->io_bio.bi_end_io)
1595+
ioend->io_bio.bi_end_io = ioend_writeback_end_bio;
1596+
1597+
if (WARN_ON_ONCE(wpc->iomap.flags & IOMAP_F_ANON_WRITE))
1598+
error = -EIO;
16131599

16141600
if (error) {
1615-
wpc->ioend->io_bio.bi_status = errno_to_blk_status(error);
1616-
bio_endio(&wpc->ioend->io_bio);
1601+
ioend->io_bio.bi_status = errno_to_blk_status(error);
1602+
bio_endio(&ioend->io_bio);
1603+
return error;
16171604
}
16181605

1619-
wpc->ioend = NULL;
1620-
return error;
1606+
submit_bio(&ioend->io_bio);
1607+
return 0;
16211608
}
1609+
EXPORT_SYMBOL_GPL(iomap_ioend_writeback_submit);
16221610

16231611
static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16241612
loff_t pos, u16 ioend_flags)
@@ -1629,7 +1617,6 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16291617
REQ_OP_WRITE | wbc_to_write_flags(wpc->wbc),
16301618
GFP_NOFS, &iomap_ioend_bioset);
16311619
bio->bi_iter.bi_sector = iomap_sector(&wpc->iomap, pos);
1632-
bio->bi_end_io = iomap_writepage_end_bio;
16331620
bio->bi_write_hint = wpc->inode->i_write_hint;
16341621
wbc_init_bio(wpc->wbc, bio);
16351622
wpc->nr_folios = 0;
@@ -1639,16 +1626,17 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16391626
static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
16401627
u16 ioend_flags)
16411628
{
1629+
struct iomap_ioend *ioend = wpc->wb_ctx;
1630+
16421631
if (ioend_flags & IOMAP_IOEND_BOUNDARY)
16431632
return false;
16441633
if ((ioend_flags & IOMAP_IOEND_NOMERGE_FLAGS) !=
1645-
(wpc->ioend->io_flags & IOMAP_IOEND_NOMERGE_FLAGS))
1634+
(ioend->io_flags & IOMAP_IOEND_NOMERGE_FLAGS))
16461635
return false;
1647-
if (pos != wpc->ioend->io_offset + wpc->ioend->io_size)
1636+
if (pos != ioend->io_offset + ioend->io_size)
16481637
return false;
16491638
if (!(wpc->iomap.flags & IOMAP_F_ANON_WRITE) &&
1650-
iomap_sector(&wpc->iomap, pos) !=
1651-
bio_end_sector(&wpc->ioend->io_bio))
1639+
iomap_sector(&wpc->iomap, pos) != bio_end_sector(&ioend->io_bio))
16521640
return false;
16531641
/*
16541642
* Limit ioend bio chain lengths to minimise IO completion latency. This
@@ -1674,6 +1662,7 @@ static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
16741662
ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
16751663
loff_t pos, loff_t end_pos, unsigned int dirty_len)
16761664
{
1665+
struct iomap_ioend *ioend = wpc->wb_ctx;
16771666
struct iomap_folio_state *ifs = folio->private;
16781667
size_t poff = offset_in_folio(folio, pos);
16791668
unsigned int ioend_flags = 0;
@@ -1704,15 +1693,17 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
17041693
if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
17051694
ioend_flags |= IOMAP_IOEND_BOUNDARY;
17061695

1707-
if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
1696+
if (!ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
17081697
new_ioend:
1709-
error = iomap_submit_ioend(wpc, 0);
1710-
if (error)
1711-
return error;
1712-
wpc->ioend = iomap_alloc_ioend(wpc, pos, ioend_flags);
1698+
if (ioend) {
1699+
error = wpc->ops->writeback_submit(wpc, 0);
1700+
if (error)
1701+
return error;
1702+
}
1703+
wpc->wb_ctx = ioend = iomap_alloc_ioend(wpc, pos, ioend_flags);
17131704
}
17141705

1715-
if (!bio_add_folio(&wpc->ioend->io_bio, folio, map_len, poff))
1706+
if (!bio_add_folio(&ioend->io_bio, folio, map_len, poff))
17161707
goto new_ioend;
17171708

17181709
if (ifs)
@@ -1759,9 +1750,9 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
17591750
* Note that this defeats the ability to chain the ioends of
17601751
* appending writes.
17611752
*/
1762-
wpc->ioend->io_size += map_len;
1763-
if (wpc->ioend->io_offset + wpc->ioend->io_size > end_pos)
1764-
wpc->ioend->io_size = end_pos - wpc->ioend->io_offset;
1753+
ioend->io_size += map_len;
1754+
if (ioend->io_offset + ioend->io_size > end_pos)
1755+
ioend->io_size = end_pos - ioend->io_offset;
17651756

17661757
wbc_account_cgroup_owner(wpc->wbc, folio, map_len);
17671758
return map_len;
@@ -1956,6 +1947,18 @@ iomap_writepages(struct iomap_writepage_ctx *wpc)
19561947

19571948
while ((folio = writeback_iter(mapping, wpc->wbc, folio, &error)))
19581949
error = iomap_writepage_map(wpc, folio);
1959-
return iomap_submit_ioend(wpc, error);
1950+
1951+
/*
1952+
* If @error is non-zero, it means that we have a situation where some
1953+
* part of the submission process has failed after we've marked pages
1954+
* for writeback.
1955+
*
1956+
* We cannot cancel the writeback directly in that case, so always call
1957+
* ->writeback_submit to run the I/O completion handler to clear the
1958+
* writeback bit and let the file system proess the errors.
1959+
*/
1960+
if (wpc->wb_ctx)
1961+
return wpc->ops->writeback_submit(wpc, error);
1962+
return error;
19601963
}
19611964
EXPORT_SYMBOL_GPL(iomap_writepages);

fs/xfs/xfs_aops.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -514,41 +514,40 @@ xfs_ioend_needs_wq_completion(
514514
}
515515

516516
static int
517-
xfs_submit_ioend(
518-
struct iomap_writepage_ctx *wpc,
519-
int status)
517+
xfs_writeback_submit(
518+
struct iomap_writepage_ctx *wpc,
519+
int error)
520520
{
521-
struct iomap_ioend *ioend = wpc->ioend;
522-
unsigned int nofs_flag;
521+
struct iomap_ioend *ioend = wpc->wb_ctx;
523522

524523
/*
525-
* We can allocate memory here while doing writeback on behalf of
526-
* memory reclaim. To avoid memory allocation deadlocks set the
527-
* task-wide nofs context for the following operations.
524+
* Convert CoW extents to regular.
525+
*
526+
* We can allocate memory here while doing writeback on behalf of memory
527+
* reclaim. To avoid memory allocation deadlocks, set the task-wide
528+
* nofs context.
528529
*/
529-
nofs_flag = memalloc_nofs_save();
530+
if (!error && (ioend->io_flags & IOMAP_IOEND_SHARED)) {
531+
unsigned int nofs_flag;
530532

531-
/* Convert CoW extents to regular */
532-
if (!status && (ioend->io_flags & IOMAP_IOEND_SHARED)) {
533-
status = xfs_reflink_convert_cow(XFS_I(ioend->io_inode),
533+
nofs_flag = memalloc_nofs_save();
534+
error = xfs_reflink_convert_cow(XFS_I(ioend->io_inode),
534535
ioend->io_offset, ioend->io_size);
536+
memalloc_nofs_restore(nofs_flag);
535537
}
536538

537-
memalloc_nofs_restore(nofs_flag);
538-
539-
/* send ioends that might require a transaction to the completion wq */
539+
/*
540+
* Send ioends that might require a transaction to the completion wq.
541+
*/
540542
if (xfs_ioend_needs_wq_completion(ioend))
541543
ioend->io_bio.bi_end_io = xfs_end_bio;
542544

543-
if (status)
544-
return status;
545-
submit_bio(&ioend->io_bio);
546-
return 0;
545+
return iomap_ioend_writeback_submit(wpc, error);
547546
}
548547

549548
static const struct iomap_writeback_ops xfs_writeback_ops = {
550549
.writeback_range = xfs_writeback_range,
551-
.submit_ioend = xfs_submit_ioend,
550+
.writeback_submit = xfs_writeback_submit,
552551
};
553552

554553
struct xfs_zoned_writepage_ctx {
@@ -646,20 +645,25 @@ xfs_zoned_writeback_range(
646645
}
647646

648647
static int
649-
xfs_zoned_submit_ioend(
650-
struct iomap_writepage_ctx *wpc,
651-
int status)
648+
xfs_zoned_writeback_submit(
649+
struct iomap_writepage_ctx *wpc,
650+
int error)
652651
{
653-
wpc->ioend->io_bio.bi_end_io = xfs_end_bio;
654-
if (status)
655-
return status;
656-
xfs_zone_alloc_and_submit(wpc->ioend, &XFS_ZWPC(wpc)->open_zone);
652+
struct iomap_ioend *ioend = wpc->wb_ctx;
653+
654+
ioend->io_bio.bi_end_io = xfs_end_bio;
655+
if (error) {
656+
ioend->io_bio.bi_status = errno_to_blk_status(error);
657+
bio_endio(&ioend->io_bio);
658+
return error;
659+
}
660+
xfs_zone_alloc_and_submit(ioend, &XFS_ZWPC(wpc)->open_zone);
657661
return 0;
658662
}
659663

660664
static const struct iomap_writeback_ops xfs_zoned_writeback_ops = {
661665
.writeback_range = xfs_zoned_writeback_range,
662-
.submit_ioend = xfs_zoned_submit_ioend,
666+
.writeback_submit = xfs_zoned_writeback_submit,
663667
};
664668

665669
STATIC int

fs/zonefs/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static ssize_t zonefs_writeback_range(struct iomap_writepage_ctx *wpc,
151151

152152
static const struct iomap_writeback_ops zonefs_writeback_ops = {
153153
.writeback_range = zonefs_writeback_range,
154+
.writeback_submit = iomap_ioend_writeback_submit,
154155
};
155156

156157
static int zonefs_writepages(struct address_space *mapping,

include/linux/iomap.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,7 @@ sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
391391
/*
392392
* Structure for writeback I/O completions.
393393
*
394-
* File systems implementing ->submit_ioend (for buffered I/O) or ->submit_io
395-
* for direct I/O) can split a bio generated by iomap. In that case the parent
394+
* File systems can split a bio generated by iomap. In that case the parent
396395
* ioend it was split from is recorded in ioend->io_parent.
397396
*/
398397
struct iomap_ioend {
@@ -416,7 +415,7 @@ static inline struct iomap_ioend *iomap_ioend_from_bio(struct bio *bio)
416415

417416
struct iomap_writeback_ops {
418417
/*
419-
* Required, performs writeback on the passed in range
418+
* Performs writeback on the passed in range
420419
*
421420
* Can map arbitrarily large regions, but we need to call into it at
422421
* least once per folio to allow the file systems to synchronize with
@@ -432,23 +431,22 @@ struct iomap_writeback_ops {
432431
u64 end_pos);
433432

434433
/*
435-
* Optional, allows the file systems to hook into bio submission,
436-
* including overriding the bi_end_io handler.
434+
* Submit a writeback context previously build up by ->writeback_range.
437435
*
438-
* Returns 0 if the bio was successfully submitted, or a negative
439-
* error code if status was non-zero or another error happened and
440-
* the bio could not be submitted.
436+
* Returns 0 if the context was successfully submitted, or a negative
437+
* error code if not. If @error is non-zero a failure occurred, and
438+
* the writeback context should be completed with an error.
441439
*/
442-
int (*submit_ioend)(struct iomap_writepage_ctx *wpc, int status);
440+
int (*writeback_submit)(struct iomap_writepage_ctx *wpc, int error);
443441
};
444442

445443
struct iomap_writepage_ctx {
446444
struct iomap iomap;
447445
struct inode *inode;
448446
struct writeback_control *wbc;
449-
struct iomap_ioend *ioend;
450447
const struct iomap_writeback_ops *ops;
451448
u32 nr_folios; /* folios added to the ioend */
449+
void *wb_ctx; /* pending writeback context */
452450
};
453451

454452
struct iomap_ioend *iomap_init_ioend(struct inode *inode, struct bio *bio,
@@ -461,6 +459,7 @@ void iomap_ioend_try_merge(struct iomap_ioend *ioend,
461459
void iomap_sort_ioends(struct list_head *ioend_list);
462460
ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
463461
loff_t pos, loff_t end_pos, unsigned int dirty_len);
462+
int iomap_ioend_writeback_submit(struct iomap_writepage_ctx *wpc, int error);
464463

465464
int iomap_writepages(struct iomap_writepage_ctx *wpc);
466465

0 commit comments

Comments
 (0)