Add a VM flag to prevent reclaim on a failed contig allocation

If a M_WAITOK contig alloc fails, the VM subsystem will try to
reclaim contiguous memory twice before actually failing the
request.  On a system with 64GB of RAM I've observed this take
400-500ms before it finally gives up, and I believe that this
will only be worse on systems with even more memory.

In certain contexts this delay is extremely harmful, so add a flag
that will skip reclaim for allocation requests to allow those
paths to opt-out of doing an expensive reclaim.

Sponsored by: Dell Inc
Differential Revision:	https://reviews.freebsd.org/D28422
Reviewed by: markj, kib
This commit is contained in:
Ryan Stone 2021-01-29 16:13:57 -05:00
parent 8727c174b0
commit 660344ca44
3 changed files with 11 additions and 2 deletions

View File

@ -54,6 +54,7 @@
*/
#define M_NOWAIT 0x0001 /* do not block */
#define M_WAITOK 0x0002 /* ok to block */
#define M_NORECLAIM 0x0080 /* do not reclaim after failure */
#define M_ZERO 0x0100 /* bzero the allocation */
#define M_NOVM 0x0200 /* don't ask VM for pages */
#define M_USE_RESERVE 0x0400 /* can alloc out of reserve memory */

View File

@ -177,17 +177,22 @@ kmem_alloc_contig_pages(vm_object_t object, vm_pindex_t pindex, int domain,
{
vm_page_t m;
int tries;
bool wait;
bool wait, reclaim;
VM_OBJECT_ASSERT_WLOCKED(object);
/* Disallow an invalid combination of flags. */
MPASS((pflags & (VM_ALLOC_WAITOK | VM_ALLOC_NORECLAIM)) !=
(VM_ALLOC_WAITOK | VM_ALLOC_NORECLAIM));
wait = (pflags & VM_ALLOC_WAITOK) != 0;
reclaim = (pflags & VM_ALLOC_NORECLAIM) == 0;
pflags &= ~(VM_ALLOC_NOWAIT | VM_ALLOC_WAITOK | VM_ALLOC_WAITFAIL);
pflags |= VM_ALLOC_NOWAIT;
for (tries = wait ? 3 : 1;; tries--) {
m = vm_page_alloc_contig_domain(object, pindex, domain, pflags,
npages, low, high, alignment, boundary, memattr);
if (m != NULL || tries == 0)
if (m != NULL || tries == 0 || !reclaim)
break;
VM_OBJECT_WUNLOCK(object);

View File

@ -541,6 +541,7 @@ vm_page_t PHYS_TO_VM_PAGE(vm_paddr_t pa);
#define VM_ALLOC_WAITFAIL 0x0010 /* (acf) Sleep and return error */
#define VM_ALLOC_WIRED 0x0020 /* (acfgp) Allocate a wired page */
#define VM_ALLOC_ZERO 0x0040 /* (acfgp) Allocate a prezeroed page */
#define VM_ALLOC_NORECLAIM 0x0080 /* (c) Do not reclaim after failure */
#define VM_ALLOC_NOOBJ 0x0100 /* (acg) No associated object */
#define VM_ALLOC_NOBUSY 0x0200 /* (acgp) Do not excl busy the page */
#define VM_ALLOC_NOCREAT 0x0400 /* (gp) Don't create a page */
@ -570,6 +571,8 @@ malloc2vm_flags(int malloc_flags)
pflags |= VM_ALLOC_NOWAIT;
if ((malloc_flags & M_WAITOK))
pflags |= VM_ALLOC_WAITOK;
if ((malloc_flags & M_NORECLAIM))
pflags |= VM_ALLOC_NORECLAIM;
return (pflags);
}
#endif