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@xxxxxxxxxx> cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> cc: David Hildenbrand <david@xxxxxxxxxx> cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> cc: Jens Axboe <axboe@xxxxxxxxx> cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> cc: Jan Kara <jack@xxxxxxx> cc: Jeff Layton <jlayton@xxxxxxxxxx> cc: Jason Gunthorpe <jgg@xxxxxxxxxx> cc: Logan Gunthorpe <logang@xxxxxxxxxxxx> cc: Hillf Danton <hdanton@xxxxxxxx> cc: Christian Brauner <brauner@xxxxxxxxxx> cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> cc: linux-fsdevel@xxxxxxxxxxxxxxx cc: linux-block@xxxxxxxxxxxxxxx cc: linux-kernel@xxxxxxxxxxxxxxx cc: linux-mm@xxxxxxxxx --- include/linux/mm.h | 1 + mm/gup.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) 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) {