commit 53ba78de064b ("mm/gup: introduce check_and_migrate_movable_folios()") created a new constraint on the pin_user_pages*() API family: a potentially large allocation must now occur, internally. A user-visible consequence has now appeared: user space can no longer pin more than 2GB of memory anymore on x86_64. That's because, on a 4KB PAGE_SIZE system, when user space tries to (indirectly, via a device driver that calls pin_user_pages()) pin 2GB, this requires an allocation of a folio pointers array of MAX_PAGE_ORDER size, which is the limit for kmalloc(). Fix this (restore the original behavior), by using replacing kmalloc_array() with kvmalloc_array(), which falls back to vmalloc() for larger allocations. Fixes: 53ba78de064b ("mm/gup: introduce check_and_migrate_movable_folios()") Cc: linux-stable@xxxxxxxxxxxxxxx Cc: Vivek Kasireddy <vivek.kasireddy@xxxxxxxxx> Cc: David Hildenbrand <david@xxxxxxxxxx> Cc: Dave Airlie <airlied@xxxxxxxxxx> Cc: Gerd Hoffmann <kraxel@xxxxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> Cc: Jason Gunthorpe <jgg@xxxxxxxxxx> Cc: Peter Xu <peterx@xxxxxxxxxx> Cc: Arnd Bergmann <arnd@xxxxxxxx> Cc: Daniel Vetter <daniel.vetter@xxxxxxxx> Cc: Dongwon Kim <dongwon.kim@xxxxxxxxx> Cc: Hugh Dickins <hughd@xxxxxxxxxx> Cc: Junxiao Chang <junxiao.chang@xxxxxxxxx> Cc: Mike Kravetz <mike.kravetz@xxxxxxxxxx> Cc: Oscar Salvador <osalvador@xxxxxxx> Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx> --- This applies to mm-hotfixes-unstable (only), because it relies on my earlier patch to this exact same location: commit 255231c75dcd mm/gup: stop leaking pinned pages in low memory conditions. thanks, John Hubbard mm/gup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 4637dab7b54f..346186788a49 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -21,6 +21,7 @@ #include <linux/pagevec.h> #include <linux/sched/mm.h> #include <linux/shmem_fs.h> +#include <linux/vmalloc.h> #include <asm/mmu_context.h> #include <asm/tlbflush.h> @@ -2439,7 +2440,7 @@ static long check_and_migrate_movable_pages(unsigned long nr_pages, struct folio **folios; long i, ret; - folios = kmalloc_array(nr_pages, sizeof(*folios), GFP_KERNEL); + folios = kvmalloc_array(nr_pages, sizeof(*folios), GFP_KERNEL); if (!folios) { unpin_user_pages(pages, nr_pages); return -ENOMEM; @@ -2450,7 +2451,7 @@ static long check_and_migrate_movable_pages(unsigned long nr_pages, ret = check_and_migrate_movable_folios(nr_pages, folios); - kfree(folios); + kvfree(folios); return ret; } #else base-commit: b70a32bbebeae216a3e846e01965880b309ca173 -- 2.47.0