Update the checks in vm_page_zone_import().

- Remove the cnt == 1 check.  UMA passes cnt == 1 when it has disabled
  per-CPU caching.  In this case we might as well just allocate a single
  page and return it to the caller, since the caller is going to do
  exactly that anyway if the UMA cache allocation attempt fails.
- Don't replenish caches if the domain is severely short on free pages.
  With large buckets we may otherwise quickly exacerbate a situation
  where the page daemon is failing to keep up.
- Don't replenish caches if the calling thread belongs to the page
  daemon, which should avoid creating extra memory pressure when it is
  trying to free memory.  Virtually all such allocations while occur in
  the context of laundering, where the laundry thread must allocate
  slabs for various swap and I/O-related UMA zones.

Reviewed by:	kib
Discussed with:	alc, jeff
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D22394
This commit is contained in:
markj 2019-11-22 16:31:10 +00:00
parent 58afbd3942
commit e25228e838

View File

@ -1829,21 +1829,14 @@ vm_page_alloc_after(vm_object_t object, vm_pindex_t pindex,
* Returns true if the number of free pages exceeds the minimum * Returns true if the number of free pages exceeds the minimum
* for the request class and false otherwise. * for the request class and false otherwise.
*/ */
int static int
vm_domain_allocate(struct vm_domain *vmd, int req, int npages) _vm_domain_allocate(struct vm_domain *vmd, int req_class, int npages)
{ {
u_int limit, old, new; u_int limit, old, new;
req = req & VM_ALLOC_CLASS_MASK; if (req_class == VM_ALLOC_INTERRUPT)
/*
* The page daemon is allowed to dig deeper into the free page list.
*/
if (curproc == pageproc && req != VM_ALLOC_INTERRUPT)
req = VM_ALLOC_SYSTEM;
if (req == VM_ALLOC_INTERRUPT)
limit = 0; limit = 0;
else if (req == VM_ALLOC_SYSTEM) else if (req_class == VM_ALLOC_SYSTEM)
limit = vmd->vmd_interrupt_free_min; limit = vmd->vmd_interrupt_free_min;
else else
limit = vmd->vmd_free_reserved; limit = vmd->vmd_free_reserved;
@ -1871,6 +1864,20 @@ vm_domain_allocate(struct vm_domain *vmd, int req, int npages)
return (1); return (1);
} }
int
vm_domain_allocate(struct vm_domain *vmd, int req, int npages)
{
int req_class;
/*
* The page daemon is allowed to dig deeper into the free page list.
*/
req_class = req & VM_ALLOC_CLASS_MASK;
if (curproc == pageproc && req_class != VM_ALLOC_INTERRUPT)
req_class = VM_ALLOC_SYSTEM;
return (_vm_domain_allocate(vmd, req_class, npages));
}
vm_page_t vm_page_t
vm_page_alloc_domain_after(vm_object_t object, vm_pindex_t pindex, int domain, vm_page_alloc_domain_after(vm_object_t object, vm_pindex_t pindex, int domain,
int req, vm_page_t mpred) int req, vm_page_t mpred)
@ -2316,8 +2323,13 @@ vm_page_zone_import(void *arg, void **store, int cnt, int domain, int flags)
pgcache = arg; pgcache = arg;
vmd = VM_DOMAIN(pgcache->domain); vmd = VM_DOMAIN(pgcache->domain);
/* Only import if we can bring in a full bucket. */
if (cnt == 1 || !vm_domain_allocate(vmd, VM_ALLOC_NORMAL, cnt)) /*
* The page daemon should avoid creating extra memory pressure since its
* main purpose is to replenish the store of free pages.
*/
if (vmd->vmd_severeset || curproc == pageproc ||
!_vm_domain_allocate(vmd, VM_ALLOC_NORMAL, cnt))
return (0); return (0);
domain = vmd->vmd_domain; domain = vmd->vmd_domain;
vm_domain_free_lock(vmd); vm_domain_free_lock(vmd);