mpage: Provide variant of mpage_writepages() with own optional folio handler

Some filesystems need to treat some folios specially (for example for
inodes with inline data). Doing the handling in their .writepages method
in a race-free manner results in duplicating some of the writeback
internals. So provide generalized version of mpage_writepages() that
allows filesystem to provide a handler called for each folio which can
handle the folio in a special way.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260326140635.15895-3-jack@suse.cz
Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Jan Kara 2026-03-26 15:06:31 +01:00
parent c369299895
commit fffca572f9
2 changed files with 33 additions and 8 deletions

View File

@ -646,17 +646,24 @@ out:
} }
/** /**
* mpage_writepages - walk the list of dirty pages of the given address space & writepage() all of them * __mpage_writepages - walk the list of dirty pages of the given address space
* & writepage() all of them
* @mapping: address space structure to write * @mapping: address space structure to write
* @wbc: subtract the number of written pages from *@wbc->nr_to_write * @wbc: subtract the number of written pages from *@wbc->nr_to_write
* @get_block: the filesystem's block mapper function. * @get_block: the filesystem's block mapper function.
* @write_folio: handler to call for each folio before calling
* mpage_write_folio()
* *
* This is a library function, which implements the writepages() * This is a library function, which implements the writepages()
* address_space_operation. * address_space_operation. It calls @write_folio handler for each folio. If
* the handler returns value > 0, it calls mpage_write_folio() to do the
* folio writeback.
*/ */
int int
mpage_writepages(struct address_space *mapping, __mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block) struct writeback_control *wbc, get_block_t get_block,
int (*write_folio)(struct folio *folio,
struct writeback_control *wbc))
{ {
struct mpage_data mpd = { struct mpage_data mpd = {
.get_block = get_block, .get_block = get_block,
@ -666,11 +673,22 @@ mpage_writepages(struct address_space *mapping,
int error; int error;
blk_start_plug(&plug); blk_start_plug(&plug);
while ((folio = writeback_iter(mapping, wbc, folio, &error))) while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
if (write_folio) {
error = write_folio(folio, wbc);
/*
* == 0 means folio is handled, < 0 means error. In
* both cases hand back control to writeback_iter()
*/
if (error <= 0)
continue;
/* Let mpage_write_folio() handle the folio. */
}
error = mpage_write_folio(wbc, folio, &mpd); error = mpage_write_folio(wbc, folio, &mpd);
}
if (mpd.bio) if (mpd.bio)
mpage_bio_submit_write(mpd.bio); mpage_bio_submit_write(mpd.bio);
blk_finish_plug(&plug); blk_finish_plug(&plug);
return error; return error;
} }
EXPORT_SYMBOL(mpage_writepages); EXPORT_SYMBOL(__mpage_writepages);

View File

@ -17,7 +17,14 @@ struct readahead_control;
void mpage_readahead(struct readahead_control *, get_block_t get_block); void mpage_readahead(struct readahead_control *, get_block_t get_block);
int mpage_read_folio(struct folio *folio, get_block_t get_block); int mpage_read_folio(struct folio *folio, get_block_t get_block);
int mpage_writepages(struct address_space *mapping, int __mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block); struct writeback_control *wbc, get_block_t get_block,
int (*write_folio)(struct folio *folio,
struct writeback_control *wbc));
static inline int mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block)
{
return __mpage_writepages(mapping, wbc, get_block, NULL);
}
#endif #endif