mirror of
https://github.com/openbsd/src.git
synced 2026-04-15 09:44:36 +00:00
When the pagedaemon is triggered to create free memory, there may be
sleeping pmemrange allocations with multi-page alignment requirements which can't be satisfied by the simplistic freeing of (solo) pages which the pagedaemon performs. As we near starvation, fragmentation is the main problem. Our free list could be large enough that the pagedaemon sees no reason to do more work, but also too fragmented to satisfy a pending allocation request with complex requirements (imagine asking for 512K of physically linear memory which is DMA reachable). When the requirement isn't satisfied, the pagedaemon is told to try again, but again doesn't mean harder because it has no mechanism to try harder. It's tracking variables do not show the fragmentation problem. It spins a lot. Often this becomes a deadlock. Time to change strategy: Overshoot creation of (both) inactive and free pages each time through the loop. After inspecting existing variables, we generate minumum 128 inactive pages (which may be dynamically drawn down asyncronously by accesses), and then try to convert minumum 128 inactives into free pages (different pages get freed different ways, including via swapcluster which has been improved in previous uvm_swap.c commit to absorb more pressure and indicate when it is full). As we mow through the freelist, this will eventually create some (physical address space) defragmention and satisfy these complex requirements. Maybe not on the first round, but it will keep trying. Before this change, it was not trying at all. ok kettenis kirill beck
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: uvm_pdaemon.c,v 1.155 2026/04/11 01:36:23 deraadt Exp $ */
|
||||
/* $OpenBSD: uvm_pdaemon.c,v 1.156 2026/04/11 01:57:22 deraadt Exp $ */
|
||||
/* $NetBSD: uvm_pdaemon.c,v 1.23 2000/08/20 10:24:14 bjh21 Exp $ */
|
||||
|
||||
/*
|
||||
@@ -202,6 +202,14 @@ struct uvm_pmalloc nowait_pma;
|
||||
|
||||
/*
|
||||
* uvm_pageout: the main loop for the pagedaemon
|
||||
*
|
||||
* Sleeping pmemrange allocations may have multi-page alignment
|
||||
* requirements which can't be satisfied by the simplistic freeing of
|
||||
* pages. Our free list could be large enough that we don't need to
|
||||
* free more, but too fragmented to satisfy a pending allocation. So
|
||||
* we overshoot creation of inactive and free pages each time through
|
||||
* the loop, which will eventually create some defragmention and
|
||||
* satisfy the complex requirement.
|
||||
*/
|
||||
void
|
||||
uvm_pageout(void *arg)
|
||||
@@ -240,6 +248,8 @@ uvm_pageout(void *arg)
|
||||
} else {
|
||||
constraint = no_constraint;
|
||||
}
|
||||
size = MAX(size, 128);
|
||||
|
||||
/* How many pages do we need to free during this round? */
|
||||
shortage = uvmexp.freetarg - atomic_load_sint(&uvmexp.free) +
|
||||
BUFPAGES_DEFICIT;
|
||||
@@ -263,8 +273,6 @@ uvm_pageout(void *arg)
|
||||
/* Reclaim pages from the buffer cache if possible. */
|
||||
if (shortage > 0)
|
||||
size += shortage;
|
||||
if (size == 0)
|
||||
size = 16; /* XXX */
|
||||
|
||||
shortage -= bufbackoff(&constraint, size * 2);
|
||||
#if NDRM > 0
|
||||
@@ -274,16 +282,11 @@ uvm_pageout(void *arg)
|
||||
if (shortage > 0)
|
||||
shortage -= uvm_pmr_cache_drain();
|
||||
|
||||
/* XXX remove shortage as parameter below */
|
||||
if (shortage < 0)
|
||||
shortage = 0;
|
||||
inactive_shortage = MAX(inactive_shortage, size * 2);
|
||||
shortage = MAX(shortage, size);
|
||||
|
||||
/*
|
||||
* scan if needed
|
||||
*/
|
||||
uvm_lock_pageq();
|
||||
if (pma || shortage > 0 || inactive_shortage > 0)
|
||||
uvmpd_scan(&constraint, shortage, inactive_shortage);
|
||||
uvmpd_scan(&constraint, shortage, inactive_shortage);
|
||||
|
||||
/*
|
||||
* if there's any free memory to be had,
|
||||
|
||||
Reference in New Issue
Block a user