[RFC,v2,2/3] mm: Provide a function to get an additional pin on a page
Commit Message
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
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
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
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?
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
@@ -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,
@@ -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)
{