mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 16:22:46 -04:00
vm: Introduce vm_page_alloc_nofree_domain
This patch adds a reservation-aware bump allocator intended for allocating NOFREE pages. The main goal of this change is to reduce the long-term fragmentation issues caused by pages that are never freed during runtime. The `vm_page_alloc_nofree_domain` routine hands out 0-order pages from a preallocated superpage. Once an active NOFREE superpage fills up, the routine will try to allocate a new one and discard the old one. This routine will get invoked whenever VM_ALLOC_NOFREE is passed to vm_page_alloc_noobj or vm_page_alloc. Differential Revision: https://reviews.freebsd.org/D45863 Reviewed by: alc, kib, markj Tested by: alc
This commit is contained in:
parent
92b9138991
commit
a8693e89e3
2 changed files with 66 additions and 0 deletions
|
|
@ -163,6 +163,7 @@ SYSCTL_PROC(_vm, OID_AUTO, page_blacklist, CTLTYPE_STRING | CTLFLAG_RD |
|
|||
static uma_zone_t fakepg_zone;
|
||||
|
||||
static void vm_page_alloc_check(vm_page_t m);
|
||||
static vm_page_t vm_page_alloc_nofree_domain(int domain, int req);
|
||||
static bool _vm_page_busy_sleep(vm_object_t obj, vm_page_t m,
|
||||
vm_pindex_t pindex, const char *wmesg, int allocflags, bool locked);
|
||||
static void vm_page_clear_dirty_mask(vm_page_t m, vm_page_bits_t pagebits);
|
||||
|
|
@ -2099,6 +2100,11 @@ vm_page_alloc_domain_after(vm_object_t object, vm_pindex_t pindex, int domain,
|
|||
if (!vm_pager_can_alloc_page(object, pindex))
|
||||
return (NULL);
|
||||
again:
|
||||
if (__predict_false((req & VM_ALLOC_NOFREE) != 0)) {
|
||||
m = vm_page_alloc_nofree_domain(domain, req);
|
||||
if (m != NULL)
|
||||
goto found;
|
||||
}
|
||||
#if VM_NRESERVLEVEL > 0
|
||||
/*
|
||||
* Can we allocate the page from a reservation?
|
||||
|
|
@ -2430,6 +2436,12 @@ vm_page_alloc_noobj_domain(int domain, int req)
|
|||
((req & VM_ALLOC_NOFREE) != 0 ? PG_NOFREE : 0);
|
||||
vmd = VM_DOMAIN(domain);
|
||||
again:
|
||||
if (__predict_false((req & VM_ALLOC_NOFREE) != 0)) {
|
||||
m = vm_page_alloc_nofree_domain(domain, req);
|
||||
if (m != NULL)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (vmd->vmd_pgcache[VM_FREEPOOL_DIRECT].zone != NULL) {
|
||||
m = uma_zalloc(vmd->vmd_pgcache[VM_FREEPOOL_DIRECT].zone,
|
||||
M_NOWAIT | M_NOVM);
|
||||
|
|
@ -2480,6 +2492,56 @@ found:
|
|||
return (m);
|
||||
}
|
||||
|
||||
#if VM_NRESERVLEVEL > 1
|
||||
#define VM_NOFREE_IMPORT_ORDER (VM_LEVEL_1_ORDER + VM_LEVEL_0_ORDER)
|
||||
#elif VM_NRESERVLEVEL > 0
|
||||
#define VM_NOFREE_IMPORT_ORDER VM_LEVEL_0_ORDER
|
||||
#else
|
||||
#define VM_NOFREE_IMPORT_ORDER 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate a single NOFREE page.
|
||||
*
|
||||
* This routine hands out NOFREE pages from higher-order
|
||||
* physical memory blocks in order to reduce memory fragmentation.
|
||||
* When a NOFREE for a given domain chunk is used up,
|
||||
* the routine will try to fetch a new one from the freelists
|
||||
* and discard the old one.
|
||||
*/
|
||||
static vm_page_t
|
||||
vm_page_alloc_nofree_domain(int domain, int req)
|
||||
{
|
||||
vm_page_t m;
|
||||
struct vm_domain *vmd;
|
||||
struct vm_nofreeq *nqp;
|
||||
|
||||
KASSERT((req & VM_ALLOC_NOFREE) != 0, ("invalid request %#x", req));
|
||||
|
||||
vmd = VM_DOMAIN(domain);
|
||||
nqp = &vmd->vmd_nofreeq;
|
||||
vm_domain_free_lock(vmd);
|
||||
if (nqp->offs >= (1 << VM_NOFREE_IMPORT_ORDER) || nqp->ma == NULL) {
|
||||
if (!vm_domain_allocate(vmd, req,
|
||||
1 << VM_NOFREE_IMPORT_ORDER)) {
|
||||
vm_domain_free_unlock(vmd);
|
||||
return (NULL);
|
||||
}
|
||||
nqp->ma = vm_phys_alloc_pages(domain, VM_FREEPOOL_DEFAULT,
|
||||
VM_LEVEL_0_ORDER);
|
||||
if (nqp->ma == NULL) {
|
||||
vm_domain_freecnt_inc(vmd, 1 << VM_NOFREE_IMPORT_ORDER);
|
||||
vm_domain_free_unlock(vmd);
|
||||
return (NULL);
|
||||
}
|
||||
nqp->offs = 0;
|
||||
}
|
||||
m = &nqp->ma[nqp->offs++];
|
||||
vm_domain_free_unlock(vmd);
|
||||
|
||||
return (m);
|
||||
}
|
||||
|
||||
vm_page_t
|
||||
vm_page_alloc_noobj(int req)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -246,6 +246,10 @@ struct vm_domain {
|
|||
u_int vmd_domain; /* (c) Domain number. */
|
||||
u_int vmd_page_count; /* (c) Total page count. */
|
||||
long vmd_segs; /* (c) bitmask of the segments */
|
||||
struct vm_nofreeq {
|
||||
vm_page_t ma;
|
||||
int offs;
|
||||
} vmd_nofreeq; /* (f) NOFREE page bump allocator. */
|
||||
u_int __aligned(CACHE_LINE_SIZE) vmd_free_count; /* (a,f) free page count */
|
||||
u_int vmd_pageout_deficit; /* (a) Estimated number of pages deficit */
|
||||
uint8_t vmd_pad[CACHE_LINE_SIZE - (sizeof(u_int) * 2)];
|
||||
|
|
|
|||
Loading…
Reference in a new issue