Re: [PATCH 09/12] writeback: Factor writeback_iter_next() out of write_cache_pages()

From: Christoph Hellwig
Date: Tue Jun 27 2023 - 00:43:31 EST


On Mon, Jun 26, 2023 at 06:35:18PM +0100, Matthew Wilcox (Oracle) wrote:
> Pull the post-processing of the writepage_t callback into a
> separate function. That means changing writeback_finish() to
> return NULL, and writeback_get_next() to call writeback_finish()
> when we naturally run out of folios.
>
> Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
> ---
> mm/page-writeback.c | 84 ++++++++++++++++++++++++---------------------
> 1 file changed, 44 insertions(+), 40 deletions(-)
>
> diff --git a/mm/page-writeback.c b/mm/page-writeback.c
> index 659df2b5c7c0..ef61d7006c5e 100644
> --- a/mm/page-writeback.c
> +++ b/mm/page-writeback.c
> @@ -2360,7 +2360,7 @@ void tag_pages_for_writeback(struct address_space *mapping,
> }
> EXPORT_SYMBOL(tag_pages_for_writeback);
>
> -static int writeback_finish(struct address_space *mapping,
> +static struct folio *writeback_finish(struct address_space *mapping,
> struct writeback_control *wbc, bool done)
> {
> folio_batch_release(&wbc->fbatch);
> @@ -2375,7 +2375,7 @@ static int writeback_finish(struct address_space *mapping,
> if (wbc->range_cyclic || (wbc->range_whole && wbc->nr_to_write > 0))
> mapping->writeback_index = wbc->done_index;
>
> - return wbc->err;
> + return NULL;

Having a return value that is always NULL feels a bit weird vs just
doing that return in the caller.

> +static struct folio *writeback_iter_next(struct address_space *mapping,
> + struct writeback_control *wbc, struct folio *folio, int error)
> +{
> + if (unlikely(error)) {
> + /*
> + * Handle errors according to the type of writeback.
> + * There's no need to continue for background writeback.
> + * Just push done_index past this folio so media
> + * errors won't choke writeout for the entire file.
> + * For integrity writeback, we must process the entire
> + * dirty set regardless of errors because the fs may
> + * still have state to clear for each folio. In that
> + * case we continue processing and return the first error.
> + */
> + if (error == AOP_WRITEPAGE_ACTIVATE) {
> + folio_unlock(folio);
> + error = 0;

Note there really shouldn't be any need for this in outside of the
legacy >writepage case. But it might make sense to delay the removal
until after ->writepage is gone to avoid bugs in conversions.

> + } else if (wbc->sync_mode != WB_SYNC_ALL) {
> + wbc->err = error;
> + wbc->done_index = folio->index +
> + folio_nr_pages(folio);

Btw, I wonder if a folio_next_index helper for this might be useful
as it's a pattern we have in a few places.