[RFC,v2,2/3] mm: Provide a function to get an additional pin on a page

Message ID 20230525223953.225496-3-dhowells@redhat.com
State New
Headers
Series block: Make old dio use iov_iter_extract_pages() and page pinning |

Commit Message

David Howells May 25, 2023, 10:39 p.m. UTC
  Provide a function to get an additional pin on a page that we already have
a pin on.  This will be used in fs/direct-io.c when dispatching multiple
bios to a page we've extracted from a user-backed iter rather than redoing
the extraction.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Christoph Hellwig <hch@infradead.org>
cc: David Hildenbrand <david@redhat.com>
cc: Andrew Morton <akpm@linux-foundation.org>
cc: Jens Axboe <axboe@kernel.dk>
cc: Al Viro <viro@zeniv.linux.org.uk>
cc: Matthew Wilcox <willy@infradead.org>
cc: Jan Kara <jack@suse.cz>
cc: Jeff Layton <jlayton@kernel.org>
cc: Jason Gunthorpe <jgg@nvidia.com>
cc: Logan Gunthorpe <logang@deltatee.com>
cc: Hillf Danton <hdanton@sina.com>
cc: Christian Brauner <brauner@kernel.org>
cc: Linus Torvalds <torvalds@linux-foundation.org>
cc: linux-fsdevel@vger.kernel.org
cc: linux-block@vger.kernel.org
cc: linux-kernel@vger.kernel.org
cc: linux-mm@kvack.org
---
 include/linux/mm.h |  1 +
 mm/gup.c           | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)
  

Comments

Linus Torvalds May 26, 2023, 2:29 a.m. UTC | #1
On Thu, May 25, 2023 at 3:40 PM David Howells <dhowells@redhat.com> wrote:
>
> +void page_get_additional_pin(struct page *page)
> +{
> +       struct folio *folio = page_folio(page);
> +
> +       if (page == ZERO_PAGE(0))
> +               return;

You added that nice "is_zero_folio()", and then you did the above anyway..

               Linus
  
David Howells May 26, 2023, 5:50 a.m. UTC | #2
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> > +       if (page == ZERO_PAGE(0))
> > +               return;
> 
> You added that nice "is_zero_folio()", and then you did the above anyway..

Bah.  Missed it because it was in a different patch.

David
  
Christoph Hellwig May 26, 2023, 8:20 a.m. UTC | #3
On Thu, May 25, 2023 at 11:39:52PM +0100, David Howells wrote:
> +/**
> + * page_get_additional_pin - Try to get an additional pin on a pinned page
> + * @page: The page to be pinned
> + *
> + * Get an additional pin on a page we already have a pin on.  Makes no change
> + * if the page is the zero_page.
> + */
> +void page_get_additional_pin(struct page *page)

page_get_additional_pin seems like an odd name, mixing the get and
pin terminologies.  What about repin_page?  Or move to a folio interface
from the start can call it folio_repin?
  
David Howells May 26, 2023, 8:31 a.m. UTC | #4
Christoph Hellwig <hch@infradead.org> wrote:

> > +void page_get_additional_pin(struct page *page)
> 
> page_get_additional_pin seems like an odd name, mixing the get and
> pin terminologies.  What about repin_page?

I considered that, though repin_page() suggests putting a pin back in after
one is removed, but I can go with that if no one objects.

> Or move to a folio interface from the start can call it folio_repin?

I also considered this, but the entire gup interface is page-based at the
moment, but I can do that too:-/

David
  

Patch

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 27ce77080c79..931b75dae7ff 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2383,6 +2383,7 @@  int get_user_pages_fast(unsigned long start, int nr_pages,
 			unsigned int gup_flags, struct page **pages);
 int pin_user_pages_fast(unsigned long start, int nr_pages,
 			unsigned int gup_flags, struct page **pages);
+void page_get_additional_pin(struct page *page);
 
 int account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc);
 int __account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc,
diff --git a/mm/gup.c b/mm/gup.c
index 69b002628f5d..4b4353a184ed 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -275,6 +275,35 @@  void unpin_user_page(struct page *page)
 }
 EXPORT_SYMBOL(unpin_user_page);
 
+/**
+ * page_get_additional_pin - Try to get an additional pin on a pinned page
+ * @page: The page to be pinned
+ *
+ * Get an additional pin on a page we already have a pin on.  Makes no change
+ * if the page is the zero_page.
+ */
+void page_get_additional_pin(struct page *page)
+{
+	struct folio *folio = page_folio(page);
+
+	if (page == ZERO_PAGE(0))
+		return;
+
+	/*
+	 * Similar to try_grab_folio(): be sure to *also* increment the normal
+	 * page refcount field at least once, so that the page really is
+	 * pinned.
+	 */
+	if (folio_test_large(folio)) {
+		WARN_ON_ONCE(atomic_read(&folio->_pincount) < 1);
+		folio_ref_add(folio, 1);
+		atomic_add(1, &folio->_pincount);
+	} else {
+		WARN_ON_ONCE(folio_ref_count(folio) < GUP_PIN_COUNTING_BIAS);
+		folio_ref_add(folio, GUP_PIN_COUNTING_BIAS);
+	}
+}
+
 static inline struct folio *gup_folio_range_next(struct page *start,
 		unsigned long npages, unsigned long i, unsigned int *ntails)
 {