From: Jan Kara <jack@suse.cz>
To: Christoph Hellwig <hch@lst.de>
Cc: linux-mm@kvack.org, Matthew Wilcox <willy@infradead.org>,
Jan Kara <jack@suse.com>, David Howells <dhowells@redhat.com>,
Brian Foster <bfoster@redhat.com>,
Christian Brauner <brauner@kernel.org>,
"Darrick J. Wong" <djwong@kernel.org>,
linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 19/19] writeback: simplify writeback iteration
Date: Tue, 30 Jan 2024 11:46:05 +0100 [thread overview]
Message-ID: <20240130104605.2i6mmdncuhwwwfin@quack3> (raw)
In-Reply-To: <20240125085758.2393327-20-hch@lst.de>
On Thu 25-01-24 09:57:58, Christoph Hellwig wrote:
> Based on the feedback from Jan I've tried to figure out how to
> avoid the error magic in the for_each_writeback_folio. This patch
> tries to implement this by switching to an open while loop over a
> single writeback_iter() function:
>
> while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
> ...
> }
>
> the twist here is that the error value is passed by reference, so that
> the iterator can restore it when breaking out of the loop.
>
> Additionally it moves the AOP_WRITEPAGE_ACTIVATE out of the iterator
> and into the callers, in preparation for eventually killing it off
> with the phase out of write_cache_pages().
>
> To me this form of the loop feels easier to follow, and it has the
> added advantage that writeback_iter() can actually be nicely used in
> nested loops, which should help with further iterizing the iomap
> writeback code.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Looking at it now I'm thinking whether we would not be better off to
completely dump the 'error' argument of writeback_iter() /
writeback_iter_next() and just make all .writepage implementations set
wbc->err directly. But that means touching all the ~20 writepage
implementations we still have...
Couple of comments regarding this implementation below (overall I agree it
seems somewhat easier to follow the code).
> +/**
> + * writepage_iter - iterate folio of a mapping for writeback
> + * @mapping: address space structure to write
> + * @wbc: writeback context
> + * @folio: previously iterated folio (%NULL to start)
> + * @error: in-out pointer for writeback errors (see below)
> + *
> + * This function should be called in a while loop in the ->writepages
> + * implementation and returns the next folio for the writeback operation
> + * described by @wbc on @mapping.
> + *
> + * To start writeback @folio should be passed as NULL, for every following
> + * iteration the folio returned by this function previously should be passed.
> + * @error should contain the error from the previous writeback iteration when
> + * calling writeback_iter.
> + *
> + * Once the writeback described in @wbc has finished, this function will return
> + * %NULL and if there was an error in any iteration restore it to @error.
> + *
> + * Note: callers should not manually break out of the loop using break or goto.
> + */
> +struct folio *writeback_iter(struct address_space *mapping,
> + struct writeback_control *wbc, struct folio *folio, int *error)
> {
> - unsigned long nr = folio_nr_pages(folio);
> + if (folio) {
> + wbc->nr_to_write -= folio_nr_pages(folio);
> + if (*error && !wbc->err)
> + wbc->err = *error;
>
> - wbc->nr_to_write -= nr;
> -
> - /*
> - * Handle the legacy AOP_WRITEPAGE_ACTIVATE magic return value.
> - * Eventually all instances should just unlock the folio themselves and
> - * return 0;
> - */
> - if (error == AOP_WRITEPAGE_ACTIVATE) {
> - folio_unlock(folio);
> - error = 0;
> + /*
> + * For integrity sync we have to keep going until we have
> + * written all the folios we tagged for writeback prior to
> + * entering the writeback loop, even if we run past
> + * wbc->nr_to_write or encounter errors.
> + *
> + * This is because the file system may still have state to clear
> + * for each folio. We'll eventually return the first error
> + * encountered.
> + *
> + * For background writeback just push done_index past this folio
> + * so that we can just restart where we left off and media
> + * errors won't choke writeout for the entire file.
> + */
> + if (wbc->sync_mode == WB_SYNC_NONE &&
> + (wbc->err || wbc->nr_to_write <= 0))
> + goto finish;
I think it would be a bit more comprehensible if we replace the goto with:
folio_batch_release(&wbc->fbatch);
if (wbc->range_cyclic)
mapping->writeback_index =
folio->index + folio_nr_pages(folio);
*error = wbc->err;
return NULL;
> + } else {
> + if (wbc->range_cyclic)
> + wbc->index = mapping->writeback_index; /* prev offset */
> + else
> + wbc->index = wbc->range_start >> PAGE_SHIFT;
> + if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
> + tag_pages_for_writeback(mapping, wbc->index,
> + wbc_end(wbc));
> + folio_batch_init(&wbc->fbatch);
> + wbc->err = 0;
> }
>
> - if (error && !wbc->err)
> - wbc->err = error;
> + folio = writeback_get_folio(mapping, wbc);
> + if (!folio)
> + goto finish;
And here we just need to do:
if (wbc->range_cyclic)
mapping->writeback_index = 0;
*error = wbc->err;
return NULL;
> + return folio;
> +
> +finish:
> + folio_batch_release(&wbc->fbatch);
>
> /*
> - * For integrity sync we have to keep going until we have written all
> - * the folios we tagged for writeback prior to entering the writeback
> - * loop, even if we run past wbc->nr_to_write or encounter errors.
> - * This is because the file system may still have state to clear for
> - * each folio. We'll eventually return the first error encountered.
> + * For range cyclic writeback we need to remember where we stopped so
> + * that we can continue there next time we are called. If we hit the
> + * last page and there is more work to be done, wrap back to the start
> + * of the file.
> *
> - * For background writeback just push done_index past this folio so that
> - * we can just restart where we left off and media errors won't choke
> - * writeout for the entire file.
> + * For non-cyclic writeback we always start looking up at the beginning
> + * of the file if we are called again, which can only happen due to
> + * -ENOMEM from the file system.
> */
> - if (wbc->sync_mode == WB_SYNC_NONE &&
> - (wbc->err || wbc->nr_to_write <= 0)) {
> - writeback_finish(mapping, wbc, folio->index + nr);
> - return NULL;
> + if (wbc->range_cyclic) {
> + WARN_ON_ONCE(wbc->sync_mode != WB_SYNC_NONE);
> + if (wbc->err || wbc->nr_to_write <= 0)
> + mapping->writeback_index =
> + folio->index + folio_nr_pages(folio);
> + else
> + mapping->writeback_index = 0;
> }
> -
> - return writeback_get_folio(mapping, wbc);
> + *error = wbc->err;
> + return NULL;
> }
>
> /**
> @@ -2563,13 +2575,17 @@ static int writeback_use_writepage(struct address_space *mapping,
> struct writeback_control *wbc)
> {
> struct blk_plug plug;
> - struct folio *folio;
> - int err;
> + struct folio *folio = 0;
^^ NULL please
> + int err = 0;
>
> blk_start_plug(&plug);
> - for_each_writeback_folio(mapping, wbc, folio, err) {
> + while ((folio = writeback_iter(mapping, wbc, folio, &err))) {
> err = mapping->a_ops->writepage(&folio->page, wbc);
> mapping_set_error(mapping, err);
> + if (err == AOP_WRITEPAGE_ACTIVATE) {
> + folio_unlock(folio);
> + err = 0;
> + }
> }
> blk_finish_plug(&plug);
>
> @@ -2590,6 +2606,8 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
> ret = mapping->a_ops->writepages(mapping, wbc);
> } else if (mapping->a_ops->writepage) {
> ret = writeback_use_writepage(mapping, wbc);
> + if (!ret)
> + ret = wbc->err;
AFAICT this should not be needed as writeback_iter() made sure wbc->err is
returned when set?
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
next prev parent reply other threads:[~2024-01-30 10:46 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-25 8:57 Convert write_cache_pages() to an iterator v5 Christoph Hellwig
2024-01-25 8:57 ` [PATCH 01/19] writeback: fix done_index when hitting the wbc->nr_to_write Christoph Hellwig
2024-01-25 8:57 ` [PATCH 02/19] writeback: also update wbc->nr_to_write on writeback failure Christoph Hellwig
2024-01-25 8:57 ` [PATCH 03/19] writeback: rework the loop termination condition in write_cache_pages Christoph Hellwig
2024-01-25 8:57 ` [PATCH 04/19] writeback: only update ->writeback_index for range_cyclic writeback Christoph Hellwig
2024-01-25 8:57 ` [PATCH 05/19] writeback: remove a duplicate prototype for tag_pages_for_writeback Christoph Hellwig
2024-01-25 8:57 ` [PATCH 06/19] writeback: Factor out writeback_finish() Christoph Hellwig
2024-01-29 20:13 ` Brian Foster
2024-01-30 14:04 ` Christoph Hellwig
2024-01-30 14:28 ` Brian Foster
2024-01-25 8:57 ` [PATCH 07/19] writeback: Factor writeback_get_batch() out of write_cache_pages() Christoph Hellwig
2024-01-25 8:57 ` [PATCH 08/19] writeback: Factor folio_prepare_writeback() " Christoph Hellwig
2024-01-25 8:57 ` [PATCH 09/19] writeback: Simplify the loops in write_cache_pages() Christoph Hellwig
2024-01-25 8:57 ` [PATCH 10/19] pagevec: Add ability to iterate a queue Christoph Hellwig
2024-01-25 8:57 ` [PATCH 11/19] writeback: Use the folio_batch queue iterator Christoph Hellwig
2024-01-25 8:57 ` [PATCH 12/19] writeback: Factor writeback_iter_init() out of write_cache_pages() Christoph Hellwig
2024-01-25 8:57 ` [PATCH 13/19] writeback: Move the folio_prepare_writeback loop " Christoph Hellwig
2024-01-25 8:57 ` [PATCH 14/19] writeback: Factor writeback_iter_next() " Christoph Hellwig
2024-01-25 8:57 ` [PATCH 15/19] writeback: Add for_each_writeback_folio() Christoph Hellwig
2024-01-25 8:57 ` [PATCH 16/19] writeback: Remove a use of write_cache_pages() from do_writepages() Christoph Hellwig
2024-01-25 8:57 ` [PATCH 17/19] writeback: update the kerneldoc comment for tag_pages_for_writeback Christoph Hellwig
2024-01-25 8:57 ` [PATCH 18/19] iomap: Convert iomap_writepages() to use for_each_writeback_folio() Christoph Hellwig
2024-01-30 10:03 ` Jan Kara
2024-01-25 8:57 ` [PATCH 19/19] writeback: simplify writeback iteration Christoph Hellwig
2024-01-30 10:46 ` Jan Kara [this message]
2024-01-30 14:16 ` Christoph Hellwig
2024-01-30 14:22 ` Christoph Hellwig
2024-01-30 14:32 ` Christoph Hellwig
2024-01-30 21:50 ` Jan Kara
2024-01-31 7:14 ` Christoph Hellwig
2024-01-31 10:40 ` Jan Kara
2024-01-31 10:43 ` Christoph Hellwig
2024-01-31 12:50 ` Brian Foster
2024-01-31 13:01 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240130104605.2i6mmdncuhwwwfin@quack3 \
--to=jack@suse.cz \
--cc=bfoster@redhat.com \
--cc=brauner@kernel.org \
--cc=dhowells@redhat.com \
--cc=djwong@kernel.org \
--cc=hch@lst.de \
--cc=jack@suse.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-xfs@vger.kernel.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.