On Sun, Jan 08, 2023 at 08:40:28PM +0100, Andreas Gruenbacher wrote: > Add an iomap_get_folio() helper that gets a folio reference based on > an iomap iterator and an offset into the address space. Use it in > iomap_write_begin(). > > Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx> > Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> > Reviewed-by: Christoph Hellwig <hch@xxxxxx> > --- > fs/iomap/buffered-io.c | 39 ++++++++++++++++++++++++++++++--------- > include/linux/iomap.h | 1 + > 2 files changed, 31 insertions(+), 9 deletions(-) > > diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c > index d4b444e44861..de4a8e5f721a 100644 > --- a/fs/iomap/buffered-io.c > +++ b/fs/iomap/buffered-io.c > @@ -457,6 +457,33 @@ bool iomap_is_partially_uptodate(struct folio *folio, size_t from, size_t count) > } > EXPORT_SYMBOL_GPL(iomap_is_partially_uptodate); > > +/** > + * iomap_get_folio - get a folio reference for writing > + * @iter: iteration structure > + * @pos: start offset of write > + * > + * Returns a locked reference to the folio at @pos, or an error pointer if the > + * folio could not be obtained. > + */ > +struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos) > +{ > + unsigned fgp = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE | FGP_NOFS; > + struct folio *folio; > + > + if (iter->flags & IOMAP_NOWAIT) > + fgp |= FGP_NOWAIT; > + > + folio = __filemap_get_folio(iter->inode->i_mapping, pos >> PAGE_SHIFT, > + fgp, mapping_gfp_mask(iter->inode->i_mapping)); > + if (folio) > + return folio; > + > + if (iter->flags & IOMAP_NOWAIT) > + return ERR_PTR(-EAGAIN); > + return ERR_PTR(-ENOMEM); > +} > +EXPORT_SYMBOL_GPL(iomap_get_folio); Hmmmm. This is where things start to get complex. I have sent a patch to fix a problem with iomap_zero_range() failing to zero cached dirty pages over UNWRITTEN extents, and that requires making FGP_CREAT optional. This is an iomap bug, and needs to be fixed in the core iomap code: https://lore.kernel.org/linux-xfs/20221201005214.3836105-1-david@xxxxxxxxxxxxx/ Essentially, we need to pass fgp flags to iomap_write_begin() need so the callers can supply a 0 or FGP_CREAT appropriately. This allows iomap_write_begin() to act only on pre-cached pages rather than always instantiating a new page if one does not exist in cache. This allows that iomap_write_begin() to return a NULL folio successfully, and this is perfectly OK for callers that pass in fgp = 0 as they are expected to handle a NULL folio return indicating there was no cached data over the range... Exposing the folio allocation as an external interface makes bug fixes like this rather messy - it's taking a core abstraction (iomap hides all the folio and page cache manipulations from the filesystem) and punching a big hole in it by requiring filesystems to actually allocation page cache folios on behalf of the iomap core. Given that I recently got major push-back for fixing an XFS-only bug by walking the page cache directly instead of abstracting it via the iomap core, punching an even bigger hole in the abstraction layer to fix a GFS2-only problem is just as bad.... -Dave. -- Dave Chinner david@xxxxxxxxxxxxx