diff mbox series

[v2,46/46] mm/filemap: Add FGP_STABLE

Message ID 20210622121551.3398730-47-willy@infradead.org (mailing list archive)
State New
Headers show
Series Folio-enabling the page cache | expand

Commit Message

Matthew Wilcox June 22, 2021, 12:15 p.m. UTC
Allow filemap_get_folio() to wait for writeback to complete (if the
filesystem wants that behaviour).  This is the folio equivalent of
grab_cache_page_write_begin(), which is moved into the folio-compat
file as a reminder to migrate all the code using it.  This paves the
way for getting rid of AOP_FLAG_NOFS once grab_cache_page_write_begin()
is removed.

Kernel grows by 11 bytes.  filemap_get_folio() grows by 33 bytes
but grab_cache_page_write_begin() shrinks by 22 bytes to make up
for it.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 include/linux/pagemap.h |  1 +
 mm/filemap.c            | 25 +++----------------------
 mm/folio-compat.c       | 13 +++++++++++++
 3 files changed, 17 insertions(+), 22 deletions(-)

Comments

Christoph Hellwig June 23, 2021, 11:43 a.m. UTC | #1
On Tue, Jun 22, 2021 at 01:15:51PM +0100, Matthew Wilcox (Oracle) wrote:
> Allow filemap_get_folio() to wait for writeback to complete (if the
> filesystem wants that behaviour).  This is the folio equivalent of
> grab_cache_page_write_begin(), which is moved into the folio-compat
> file as a reminder to migrate all the code using it.  This paves the
> way for getting rid of AOP_FLAG_NOFS once grab_cache_page_write_begin()
> is removed.

We actually should kill FGP_NOFS as well by switching everything over
to memalloc_nofs_{save, restore} eventually, given how error prone
all these manual flags settings are.

> diff --git a/mm/folio-compat.c b/mm/folio-compat.c
> index 78365eaee7d3..206bedd621d0 100644
> --- a/mm/folio-compat.c
> +++ b/mm/folio-compat.c
> @@ -115,6 +115,7 @@ void lru_cache_add(struct page *page)
>  }
>  EXPORT_SYMBOL(lru_cache_add);
>  
> +noinline
>  struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
>  		int fgp_flags, gfp_t gfp)

How did that sneak in here?

Otherwise:

Reviewed-by: Christoph Hellwig <hch@lst.de>
Matthew Wilcox June 23, 2021, 12:15 p.m. UTC | #2
On Wed, Jun 23, 2021 at 01:43:30PM +0200, Christoph Hellwig wrote:
> On Tue, Jun 22, 2021 at 01:15:51PM +0100, Matthew Wilcox (Oracle) wrote:
> > Allow filemap_get_folio() to wait for writeback to complete (if the
> > filesystem wants that behaviour).  This is the folio equivalent of
> > grab_cache_page_write_begin(), which is moved into the folio-compat
> > file as a reminder to migrate all the code using it.  This paves the
> > way for getting rid of AOP_FLAG_NOFS once grab_cache_page_write_begin()
> > is removed.
> 
> We actually should kill FGP_NOFS as well by switching everything over
> to memalloc_nofs_{save, restore} eventually, given how error prone
> all these manual flags settings are.

Well, yes, but it's been four years and we still have over 1100 uses of
GFP_NOFS.  Until someone takes on that Augean Stables, we're going to need
FGP_NOFS.  I added that context to the readahead path in f2c817bed58d,
but of course that doesn't let me remove any uses of GFP_NOFS.

> > diff --git a/mm/folio-compat.c b/mm/folio-compat.c
> > index 78365eaee7d3..206bedd621d0 100644
> > --- a/mm/folio-compat.c
> > +++ b/mm/folio-compat.c
> > @@ -115,6 +115,7 @@ void lru_cache_add(struct page *page)
> >  }
> >  EXPORT_SYMBOL(lru_cache_add);
> >  
> > +noinline
> >  struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
> >  		int fgp_flags, gfp_t gfp)
> 
> How did that sneak in here?

Without it, pagecache_get_page() gets inlined by
grab_cache_page_write_begin() which is just too much code.
diff mbox series

Patch

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 669bdebe2861..865b7784e99b 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -301,6 +301,7 @@  pgoff_t page_cache_prev_miss(struct address_space *mapping,
 #define FGP_FOR_MMAP		0x00000040
 #define FGP_HEAD		0x00000080
 #define FGP_ENTRY		0x00000100
+#define FGP_STABLE		0x00000200
 
 struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
 		int fgp_flags, gfp_t gfp);
diff --git a/mm/filemap.c b/mm/filemap.c
index e431461279c3..4951fe8787d8 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1817,6 +1817,7 @@  static struct folio *mapping_get_entry(struct address_space *mapping,
  * * %FGP_WRITE - The page will be written to by the caller.
  * * %FGP_NOFS - __GFP_FS will get cleared in gfp.
  * * %FGP_NOWAIT - Don't get blocked by page lock.
+ * * %FGP_STABLE - Wait for the folio to be stable (finished writeback)
  *
  * If %FGP_LOCK or %FGP_CREAT are specified then the function may sleep even
  * if the %GFP flags specified for %FGP_CREAT are atomic.
@@ -1867,6 +1868,8 @@  struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
 			folio_clear_idle_flag(folio);
 	}
 
+	if (fgp_flags & FGP_STABLE)
+		folio_wait_stable(folio);
 no_page:
 	if (!folio && (fgp_flags & FGP_CREAT)) {
 		int err;
@@ -3590,28 +3593,6 @@  generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
 }
 EXPORT_SYMBOL(generic_file_direct_write);
 
-/*
- * Find or create a page at the given pagecache position. Return the locked
- * page. This function is specifically for buffered writes.
- */
-struct page *grab_cache_page_write_begin(struct address_space *mapping,
-					pgoff_t index, unsigned flags)
-{
-	struct page *page;
-	int fgp_flags = FGP_LOCK|FGP_WRITE|FGP_CREAT;
-
-	if (flags & AOP_FLAG_NOFS)
-		fgp_flags |= FGP_NOFS;
-
-	page = pagecache_get_page(mapping, index, fgp_flags,
-			mapping_gfp_mask(mapping));
-	if (page)
-		wait_for_stable_page(page);
-
-	return page;
-}
-EXPORT_SYMBOL(grab_cache_page_write_begin);
-
 ssize_t generic_perform_write(struct file *file,
 				struct iov_iter *i, loff_t pos)
 {
diff --git a/mm/folio-compat.c b/mm/folio-compat.c
index 78365eaee7d3..206bedd621d0 100644
--- a/mm/folio-compat.c
+++ b/mm/folio-compat.c
@@ -115,6 +115,7 @@  void lru_cache_add(struct page *page)
 }
 EXPORT_SYMBOL(lru_cache_add);
 
+noinline
 struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
 		int fgp_flags, gfp_t gfp)
 {
@@ -126,3 +127,15 @@  struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
 	return folio_file_page(folio, index);
 }
 EXPORT_SYMBOL(pagecache_get_page);
+
+struct page *grab_cache_page_write_begin(struct address_space *mapping,
+					pgoff_t index, unsigned flags)
+{
+	unsigned fgp_flags = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE;
+
+	if (flags & AOP_FLAG_NOFS)
+		fgp_flags |= FGP_NOFS;
+	return pagecache_get_page(mapping, index, fgp_flags,
+			mapping_gfp_mask(mapping));
+}
+EXPORT_SYMBOL(grab_cache_page_write_begin);