Skip to content

Commit 301363b

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 f1e14b9 commit 301363b

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
@@ -1571,7 +1571,7 @@ u32 iomap_finish_ioend_buffered(struct iomap_ioend *ioend)
15711571
return folio_count;
15721572
}
15731573

1574-
static void iomap_writepage_end_bio(struct bio *bio)
1574+
static void ioend_writeback_end_bio(struct bio *bio)
15751575
{
15761576
struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
15771577

@@ -1580,42 +1580,30 @@ static void iomap_writepage_end_bio(struct bio *bio)
15801580
}
15811581

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

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

16111597
if (error) {
1612-
wpc->ioend->io_bio.bi_status = errno_to_blk_status(error);
1613-
bio_endio(&wpc->ioend->io_bio);
1598+
ioend->io_bio.bi_status = errno_to_blk_status(error);
1599+
bio_endio(&ioend->io_bio);
1600+
return error;
16141601
}
16151602

1616-
wpc->ioend = NULL;
1617-
return error;
1603+
submit_bio(&ioend->io_bio);
1604+
return 0;
16181605
}
1606+
EXPORT_SYMBOL_GPL(iomap_ioend_writeback_submit);
16191607

16201608
static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16211609
loff_t pos, u16 ioend_flags)
@@ -1626,7 +1614,6 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16261614
REQ_OP_WRITE | wbc_to_write_flags(wpc->wbc),
16271615
GFP_NOFS, &iomap_ioend_bioset);
16281616
bio->bi_iter.bi_sector = iomap_sector(&wpc->iomap, pos);
1629-
bio->bi_end_io = iomap_writepage_end_bio;
16301617
bio->bi_write_hint = wpc->inode->i_write_hint;
16311618
wbc_init_bio(wpc->wbc, bio);
16321619
wpc->nr_folios = 0;
@@ -1636,16 +1623,17 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
16361623
static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
16371624
u16 ioend_flags)
16381625
{
1626+
struct iomap_ioend *ioend = wpc->wb_ctx;
1627+
16391628
if (ioend_flags & IOMAP_IOEND_BOUNDARY)
16401629
return false;
16411630
if ((ioend_flags & IOMAP_IOEND_NOMERGE_FLAGS) !=
1642-
(wpc->ioend->io_flags & IOMAP_IOEND_NOMERGE_FLAGS))
1631+
(ioend->io_flags & IOMAP_IOEND_NOMERGE_FLAGS))
16431632
return false;
1644-
if (pos != wpc->ioend->io_offset + wpc->ioend->io_size)
1633+
if (pos != ioend->io_offset + ioend->io_size)
16451634
return false;
16461635
if (!(wpc->iomap.flags & IOMAP_F_ANON_WRITE) &&
1647-
iomap_sector(&wpc->iomap, pos) !=
1648-
bio_end_sector(&wpc->ioend->io_bio))
1636+
iomap_sector(&wpc->iomap, pos) != bio_end_sector(&ioend->io_bio))
16491637
return false;
16501638
/*
16511639
* Limit ioend bio chain lengths to minimise IO completion latency. This
@@ -1671,6 +1659,7 @@ static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
16711659
ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
16721660
loff_t pos, loff_t end_pos, unsigned int dirty_len)
16731661
{
1662+
struct iomap_ioend *ioend = wpc->wb_ctx;
16741663
struct iomap_folio_state *ifs = folio->private;
16751664
size_t poff = offset_in_folio(folio, pos);
16761665
unsigned int ioend_flags = 0;
@@ -1701,15 +1690,17 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
17011690
if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
17021691
ioend_flags |= IOMAP_IOEND_BOUNDARY;
17031692

1704-
if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
1693+
if (!ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
17051694
new_ioend:
1706-
error = iomap_submit_ioend(wpc, 0);
1707-
if (error)
1708-
return error;
1709-
wpc->ioend = iomap_alloc_ioend(wpc, pos, ioend_flags);
1695+
if (ioend) {
1696+
error = wpc->ops->writeback_submit(wpc, 0);
1697+
if (error)
1698+
return error;
1699+
}
1700+
wpc->wb_ctx = ioend = iomap_alloc_ioend(wpc, pos, ioend_flags);
17101701
}
17111702

1712-
if (!bio_add_folio(&wpc->ioend->io_bio, folio, map_len, poff))
1703+
if (!bio_add_folio(&ioend->io_bio, folio, map_len, poff))
17131704
goto new_ioend;
17141705

17151706
if (ifs)
@@ -1756,9 +1747,9 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
17561747
* Note that this defeats the ability to chain the ioends of
17571748
* appending writes.
17581749
*/
1759-
wpc->ioend->io_size += map_len;
1760-
if (wpc->ioend->io_offset + wpc->ioend->io_size > end_pos)
1761-
wpc->ioend->io_size = end_pos - wpc->ioend->io_offset;
1750+
ioend->io_size += map_len;
1751+
if (ioend->io_offset + ioend->io_size > end_pos)
1752+
ioend->io_size = end_pos - ioend->io_offset;
17621753

17631754
wbc_account_cgroup_owner(wpc->wbc, folio, map_len);
17641755
return map_len;
@@ -1953,6 +1944,18 @@ iomap_writepages(struct iomap_writepage_ctx *wpc)
19531944

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