Home | History | Annotate | Line # | Download | only in uvm
      1 /*	$NetBSD: uvm_pdpolicy_clock.c,v 1.43 2026/09/05 16:53:05 tls Exp $	*/
      2 /*	NetBSD: uvm_pdaemon.c,v 1.72 2006/01/05 10:47:33 yamt Exp $	*/
      3 
      4 /*-
      5  * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to The NetBSD Foundation
      9  * by Andrew Doran.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Copyright (c) 1997 Charles D. Cranor and Washington University.
     35  * Copyright (c) 1991, 1993, The Regents of the University of California.
     36  *
     37  * All rights reserved.
     38  *
     39  * This code is derived from software contributed to Berkeley by
     40  * The Mach Operating System project at Carnegie-Mellon University.
     41  *
     42  * Redistribution and use in source and binary forms, with or without
     43  * modification, are permitted provided that the following conditions
     44  * are met:
     45  * 1. Redistributions of source code must retain the above copyright
     46  *    notice, this list of conditions and the following disclaimer.
     47  * 2. Redistributions in binary form must reproduce the above copyright
     48  *    notice, this list of conditions and the following disclaimer in the
     49  *    documentation and/or other materials provided with the distribution.
     50  * 3. Neither the name of the University nor the names of its contributors
     51  *    may be used to endorse or promote products derived from this software
     52  *    without specific prior written permission.
     53  *
     54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     64  * SUCH DAMAGE.
     65  *
     66  *	@(#)vm_pageout.c        8.5 (Berkeley) 2/14/94
     67  * from: Id: uvm_pdaemon.c,v 1.1.2.32 1998/02/06 05:26:30 chs Exp
     68  *
     69  *
     70  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
     71  * All rights reserved.
     72  *
     73  * Permission to use, copy, modify and distribute this software and
     74  * its documentation is hereby granted, provided that both the copyright
     75  * notice and this permission notice appear in all copies of the
     76  * software, derivative works or modified versions, and any portions
     77  * thereof, and that both notices appear in supporting documentation.
     78  *
     79  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     80  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     81  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     82  *
     83  * Carnegie Mellon requests users of this software to return to
     84  *
     85  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     86  *  School of Computer Science
     87  *  Carnegie Mellon University
     88  *  Pittsburgh PA 15213-3890
     89  *
     90  * any improvements or extensions that they make and grant Carnegie the
     91  * rights to redistribute these changes.
     92  */
     93 
     94 #if defined(PDSIM)
     95 
     96 #include "pdsim.h"
     97 
     98 #else /* defined(PDSIM) */
     99 
    100 #include <sys/cdefs.h>
    101 __KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.43 2026/09/05 16:53:05 tls Exp $");
    102 
    103 #include <sys/param.h>
    104 #include <sys/proc.h>
    105 #include <sys/systm.h>
    106 #include <sys/kernel.h>
    107 #include <sys/kmem.h>
    108 #include <sys/atomic.h>
    109 
    110 #include <uvm/uvm.h>
    111 #include <uvm/uvm_pdpolicy.h>
    112 #include <uvm/uvm_pdpolicy_impl.h>
    113 #include <uvm/uvm_stat.h>
    114 
    115 #endif /* defined(PDSIM) */
    116 
    117 /*
    118  * per-CPU queue of pending page status changes.  128 entries makes for a
    119  * 1kB queue on _LP64 and has been found to be a reasonable compromise that
    120  * keeps lock contention events and wait times low, while not using too much
    121  * memory nor allowing global state to fall too far behind.
    122  */
    123 #if !defined(CLOCK_PDQ_SIZE)
    124 #define	CLOCK_PDQ_SIZE	128
    125 #endif /* !defined(CLOCK_PDQ_SIZE) */
    126 
    127 #define PQ_INACTIVE	0x00000010	/* page is in inactive list */
    128 #define PQ_ACTIVE	0x00000020	/* page is in active list */
    129 
    130 #if !defined(CLOCK_INACTIVEPCT)
    131 #define	CLOCK_INACTIVEPCT	33
    132 #endif /* !defined(CLOCK_INACTIVEPCT) */
    133 
    134 struct uvmpdpol_globalstate {
    135 	kmutex_t lock;			/* lock on state */
    136 					/* <= compiler pads here */
    137 	struct pglist s_activeq		/* allocated pages, in use */
    138 	    __aligned(COHERENCY_UNIT);
    139 	struct pglist s_inactiveq;	/* pages between the clock hands */
    140 	int s_active;
    141 	int s_inactive;
    142 	int s_inactarg;
    143 	struct uvm_pctparam s_anonmin;
    144 	struct uvm_pctparam s_filemin;
    145 	struct uvm_pctparam s_execmin;
    146 	struct uvm_pctparam s_anonmax;
    147 	struct uvm_pctparam s_filemax;
    148 	struct uvm_pctparam s_execmax;
    149 	struct uvm_pctparam s_inactivepct;
    150 };
    151 
    152 struct uvmpdpol_scanstate {
    153 	bool ss_anonreact, ss_filereact, ss_execreact;
    154 	struct vm_page ss_marker;
    155 };
    156 
    157 static void	uvmpdpol_pageactivate_locked(struct vm_page *);
    158 static void	uvmpdpol_pagedeactivate_locked(struct vm_page *);
    159 static void	uvmpdpol_pagedequeue_locked(struct vm_page *);
    160 static bool	uvmpdpol_pagerealize_locked(struct vm_page *);
    161 static struct uvm_cpu *uvmpdpol_flush(void);
    162 
    163 static struct uvmpdpol_globalstate pdpol_state __cacheline_aligned;
    164 static struct uvmpdpol_scanstate pdpol_scanstate;
    165 
    166 PDPOL_EVCNT_DEFINE(reactexec)
    167 PDPOL_EVCNT_DEFINE(reactfile)
    168 PDPOL_EVCNT_DEFINE(reactanon)
    169 
    170 static void
    171 clock_tune(void)
    172 {
    173 	struct uvmpdpol_globalstate *s = &pdpol_state;
    174 
    175 	s->s_inactarg = UVM_PCTPARAM_APPLY(&s->s_inactivepct,
    176 	    s->s_active + s->s_inactive);
    177 	if (s->s_inactarg <= uvmexp.freetarg) {
    178 		s->s_inactarg = uvmexp.freetarg + 1;
    179 	}
    180 }
    181 
    182 void
    183 uvmpdpol_scaninit(void)
    184 {
    185 	struct uvmpdpol_globalstate *s = &pdpol_state;
    186 	struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
    187 	int t;
    188 	bool anonunder, fileunder, execunder;
    189 	bool anonover, fileover, execover;
    190 	bool anonreact, filereact, execreact;
    191 	int64_t freepg, anonpg, filepg, execpg;
    192 
    193 	/*
    194 	 * decide which types of pages we want to reactivate instead of freeing
    195 	 * to keep usage within the minimum and maximum usage limits.
    196 	 * uvm_availmem() will sync the counters.
    197 	 */
    198 
    199 	freepg = uvm_availmem(false);
    200 	anonpg = cpu_count_get(CPU_COUNT_ANONCLEAN) +
    201 	    cpu_count_get(CPU_COUNT_ANONDIRTY) +
    202 	    cpu_count_get(CPU_COUNT_ANONUNKNOWN);
    203 	execpg = cpu_count_get(CPU_COUNT_EXECPAGES);
    204 	filepg = cpu_count_get(CPU_COUNT_FILECLEAN) +
    205 	    cpu_count_get(CPU_COUNT_FILEDIRTY) +
    206 	    cpu_count_get(CPU_COUNT_FILEUNKNOWN) -
    207 	    execpg;
    208 
    209 	mutex_enter(&s->lock);
    210 	t = s->s_active + s->s_inactive + freepg;
    211 	anonunder = anonpg <= UVM_PCTPARAM_APPLY(&s->s_anonmin, t);
    212 	fileunder = filepg <= UVM_PCTPARAM_APPLY(&s->s_filemin, t);
    213 	execunder = execpg <= UVM_PCTPARAM_APPLY(&s->s_execmin, t);
    214 	anonover = anonpg > UVM_PCTPARAM_APPLY(&s->s_anonmax, t);
    215 	fileover = filepg > UVM_PCTPARAM_APPLY(&s->s_filemax, t);
    216 	execover = execpg > UVM_PCTPARAM_APPLY(&s->s_execmax, t);
    217 	anonreact = anonunder || (!anonover && (fileover || execover));
    218 	filereact = fileunder || (!fileover && (anonover || execover));
    219 	execreact = execunder || (!execover && (anonover || fileover));
    220 	if (filereact && execreact && (anonreact || uvm_swapisfull())) {
    221 		anonreact = filereact = execreact = false;
    222 	}
    223 	ss->ss_anonreact = anonreact;
    224 	ss->ss_filereact = filereact;
    225 	ss->ss_execreact = execreact;
    226 	memset(&ss->ss_marker, 0, sizeof(ss->ss_marker));
    227 	ss->ss_marker.flags = PG_MARKER;
    228 	TAILQ_INSERT_HEAD(&pdpol_state.s_inactiveq, &ss->ss_marker, pdqueue);
    229 	mutex_exit(&s->lock);
    230 }
    231 
    232 void
    233 uvmpdpol_scanfini(void)
    234 {
    235 	struct uvmpdpol_globalstate *s = &pdpol_state;
    236 	struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
    237 
    238 	mutex_enter(&s->lock);
    239 	TAILQ_REMOVE(&pdpol_state.s_inactiveq, &ss->ss_marker, pdqueue);
    240 	mutex_exit(&s->lock);
    241 }
    242 
    243 struct vm_page *
    244 uvmpdpol_selectvictim(krwlock_t **plock)
    245 {
    246 	struct uvmpdpol_globalstate *s = &pdpol_state;
    247 	struct uvmpdpol_scanstate *ss = &pdpol_scanstate;
    248 	struct vm_page *pg;
    249 	krwlock_t *lock;
    250 
    251 	mutex_enter(&s->lock);
    252 	while (/* CONSTCOND */ 1) {
    253 		struct vm_anon *anon;
    254 		struct uvm_object *uobj;
    255 
    256 		pg = TAILQ_NEXT(&ss->ss_marker, pdqueue);
    257 		if (pg == NULL) {
    258 			break;
    259 		}
    260 		KASSERT((pg->flags & PG_MARKER) == 0);
    261 		uvmexp.pdscans++;
    262 
    263 		/*
    264 		 * acquire interlock to stabilize page identity.
    265 		 * if we have caught the page in a state of flux
    266 		 * deal with it and retry.
    267 		 */
    268 		mutex_enter(&pg->interlock);
    269 		if (uvmpdpol_pagerealize_locked(pg)) {
    270 			mutex_exit(&pg->interlock);
    271 			continue;
    272 		}
    273 
    274 		/*
    275 		 * now prepare to move on to the next page.
    276 		 */
    277 		TAILQ_REMOVE(&pdpol_state.s_inactiveq, &ss->ss_marker,
    278 		    pdqueue);
    279 		TAILQ_INSERT_AFTER(&pdpol_state.s_inactiveq, pg,
    280 		    &ss->ss_marker, pdqueue);
    281 
    282 		/*
    283 		 * enforce the minimum thresholds on different
    284 		 * types of memory usage.  if reusing the current
    285 		 * page would reduce that type of usage below its
    286 		 * minimum, reactivate the page instead and move
    287 		 * on to the next page.
    288 		 */
    289 		anon = pg->uanon;
    290 		uobj = pg->uobject;
    291 		if (uobj && UVM_OBJ_IS_VTEXT(uobj) && ss->ss_execreact) {
    292 			uvmpdpol_pageactivate_locked(pg);
    293 			mutex_exit(&pg->interlock);
    294 			PDPOL_EVCNT_INCR(reactexec);
    295 			continue;
    296 		}
    297 		if (uobj && UVM_OBJ_IS_VNODE(uobj) &&
    298 		    !UVM_OBJ_IS_VTEXT(uobj) && ss->ss_filereact) {
    299 			uvmpdpol_pageactivate_locked(pg);
    300 			mutex_exit(&pg->interlock);
    301 			PDPOL_EVCNT_INCR(reactfile);
    302 			continue;
    303 		}
    304 		if ((anon || UVM_OBJ_IS_AOBJ(uobj)) && ss->ss_anonreact) {
    305 			uvmpdpol_pageactivate_locked(pg);
    306 			mutex_exit(&pg->interlock);
    307 			PDPOL_EVCNT_INCR(reactanon);
    308 			continue;
    309 		}
    310 
    311 		/*
    312 		 * try to lock the object that owns the page.
    313 		 *
    314 		 * with the page interlock held, we can drop s->lock, which
    315 		 * could otherwise serve as a barrier to us getting the
    316 		 * object locked, because the owner of the object's lock may
    317 		 * be blocked on s->lock (i.e. a deadlock).
    318 		 *
    319 		 * whatever happens, uvmpd_trylockowner() will release the
    320 		 * interlock.  with the interlock dropped we can then
    321 		 * re-acquire our own lock.  the order is:
    322 		 *
    323 		 *	object -> pdpol -> interlock.
    324 	         */
    325 	        mutex_exit(&s->lock);
    326         	lock = uvmpd_trylockowner(pg);
    327         	/* pg->interlock now released */
    328         	mutex_enter(&s->lock);
    329 		if (lock == NULL) {
    330 			/* didn't get it - try the next page. */
    331 			continue;
    332 		}
    333 
    334 		/*
    335 		 * There was a very brief interval with interlock and
    336 		 * s_lock dropped.  Check we would not now be scribbling
    337 		 * on someone else's work.
    338 		 */
    339 		mutex_enter(&pg->interlock);
    340 		if (uvmpdpol_pagerealize_locked(pg) ||
    341 		    (pg->pqflags & PQ_INACTIVE) == 0 ||
    342 		    pg->wire_count != 0) {
    343 		    mutex_exit(&pg->interlock);
    344 		    rw_exit(lock);
    345 		    continue;
    346 		}
    347 		mutex_exit(&pg->interlock);
    348 
    349 		/*
    350 		 * move referenced pages back to active queue and skip to
    351 		 * next page.
    352 		 */
    353 		if (pmap_is_referenced(pg)) {
    354 			mutex_enter(&pg->interlock);
    355 			uvmpdpol_pageactivate_locked(pg);
    356 			mutex_exit(&pg->interlock);
    357 			uvmexp.pdreact++;
    358 			rw_exit(lock);
    359 			continue;
    360 		}
    361 
    362 		/* we have a potential victim. */
    363 		*plock = lock;
    364 		break;
    365 	}
    366 	mutex_exit(&s->lock);
    367 	return pg;
    368 }
    369 
    370 void
    371 uvmpdpol_balancequeue(int swap_shortage)
    372 {
    373 	struct uvmpdpol_globalstate *s = &pdpol_state;
    374 	int inactive_shortage;
    375 	struct vm_page *p, marker;
    376 	krwlock_t *lock;
    377 
    378 	/*
    379 	 * we have done the scan to get free pages.   now we work on meeting
    380 	 * our inactive target.
    381 	 */
    382 
    383 	memset(&marker, 0, sizeof(marker));
    384 	marker.flags = PG_MARKER;
    385 
    386 	mutex_enter(&s->lock);
    387 	TAILQ_INSERT_HEAD(&pdpol_state.s_activeq, &marker, pdqueue);
    388 	for (;;) {
    389 		inactive_shortage =
    390 		    pdpol_state.s_inactarg - pdpol_state.s_inactive;
    391 		if (inactive_shortage <= 0 && swap_shortage <= 0) {
    392 			break;
    393 		}
    394 		p = TAILQ_NEXT(&marker, pdqueue);
    395 		if (p == NULL) {
    396 			break;
    397 		}
    398 		KASSERT((p->flags & PG_MARKER) == 0);
    399 
    400 		/*
    401 		 * acquire interlock to stabilize page identity.
    402 		 * if we have caught the page in a state of flux
    403 		 * deal with it and retry.
    404 		 */
    405 		mutex_enter(&p->interlock);
    406 		if (uvmpdpol_pagerealize_locked(p)) {
    407 			mutex_exit(&p->interlock);
    408 			continue;
    409 		}
    410 
    411 		/*
    412 		 * now prepare to move on to the next page.
    413 		 */
    414 		TAILQ_REMOVE(&pdpol_state.s_activeq, &marker, pdqueue);
    415 		TAILQ_INSERT_AFTER(&pdpol_state.s_activeq, p, &marker,
    416 		    pdqueue);
    417 
    418 		/*
    419 		 * try to lock the object that owns the page.  see comments
    420 		 * in uvmpdpol_selectvictim().
    421 	         */
    422 	        mutex_exit(&s->lock);
    423         	lock = uvmpd_trylockowner(p);
    424         	/* p->interlock now released */
    425         	mutex_enter(&s->lock);
    426 		if (lock == NULL) {
    427 			/* didn't get it - try the next page. */
    428 			continue;
    429 		}
    430 
    431 		/*
    432 		 * As in selectvictim, check we would not now be scribbling
    433 		 * on someone else's work.
    434 		 */
    435 		mutex_enter(&p->interlock);
    436 		if (uvmpdpol_pagerealize_locked(p) ||
    437 		    (p->pqflags & PQ_ACTIVE) == 0 ||
    438 		    p->wire_count != 0) {
    439 		    mutex_exit(&p->interlock);
    440 		    rw_exit(lock);
    441 		    continue;
    442 		}
    443 		mutex_exit(&p->interlock);
    444 
    445 		/*
    446 		 * if there's a shortage of swap slots, try to free it.
    447 		 */
    448 		if (swap_shortage > 0 && (p->flags & PG_SWAPBACKED) != 0 &&
    449 		    (p->flags & PG_BUSY) == 0) {
    450 			if (uvmpd_dropswap(p)) {
    451 				swap_shortage--;
    452 			}
    453 		}
    454 
    455 		/*
    456 		 * if there's a shortage of inactive pages, deactivate.
    457 		 */
    458 		if (inactive_shortage > 0) {
    459 			pmap_clear_reference(p);
    460 			mutex_enter(&p->interlock);
    461 			uvmpdpol_pagedeactivate_locked(p);
    462 			mutex_exit(&p->interlock);
    463 			uvmexp.pddeact++;
    464 			inactive_shortage--;
    465 		}
    466 		rw_exit(lock);
    467 	}
    468 	TAILQ_REMOVE(&pdpol_state.s_activeq, &marker, pdqueue);
    469 	mutex_exit(&s->lock);
    470 }
    471 
    472 static void
    473 uvmpdpol_pagedeactivate_locked(struct vm_page *pg)
    474 {
    475 	struct uvmpdpol_globalstate *s __diagused = &pdpol_state;
    476 
    477 	KASSERT(mutex_owned(&s->lock));
    478 	KASSERT(mutex_owned(&pg->interlock));
    479 	KASSERT((pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) !=
    480 	    (PQ_INTENT_D | PQ_INTENT_SET));
    481 
    482 	if (pg->pqflags & PQ_ACTIVE) {
    483 		TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pdqueue);
    484 		KASSERT(pdpol_state.s_active > 0);
    485 		pdpol_state.s_active--;
    486 	}
    487 	if ((pg->pqflags & PQ_INACTIVE) == 0) {
    488 		KASSERT(pg->wire_count == 0);
    489 		TAILQ_INSERT_TAIL(&pdpol_state.s_inactiveq, pg, pdqueue);
    490 		pdpol_state.s_inactive++;
    491 	}
    492 	pg->pqflags &= ~(PQ_ACTIVE | PQ_INTENT_SET);
    493 	pg->pqflags |= PQ_INACTIVE;
    494 }
    495 
    496 void
    497 uvmpdpol_pagedeactivate(struct vm_page *pg)
    498 {
    499 
    500 	KASSERT(uvm_page_owner_locked_p(pg, false));
    501 	KASSERT(mutex_owned(&pg->interlock));
    502 
    503 	/*
    504 	 * we have to clear the reference bit now, as when it comes time to
    505 	 * realize the intent we won't have the object locked any more.
    506 	 */
    507 	pmap_clear_reference(pg);
    508 	uvmpdpol_set_intent(pg, PQ_INTENT_I);
    509 }
    510 
    511 static void
    512 uvmpdpol_pageactivate_locked(struct vm_page *pg)
    513 {
    514 	struct uvmpdpol_globalstate *s __diagused = &pdpol_state;
    515 
    516 	KASSERT(mutex_owned(&s->lock));
    517 	KASSERT(mutex_owned(&pg->interlock));
    518 	KASSERT((pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) !=
    519 	    (PQ_INTENT_D | PQ_INTENT_SET));
    520 
    521 	uvmpdpol_pagedequeue_locked(pg);
    522 	TAILQ_INSERT_TAIL(&pdpol_state.s_activeq, pg, pdqueue);
    523 	pdpol_state.s_active++;
    524 	pg->pqflags &= ~(PQ_INACTIVE | PQ_INTENT_SET);
    525 	pg->pqflags |= PQ_ACTIVE;
    526 }
    527 
    528 void
    529 uvmpdpol_pageactivate(struct vm_page *pg)
    530 {
    531 
    532 	KASSERT(uvm_page_owner_locked_p(pg, false));
    533 	KASSERT(mutex_owned(&pg->interlock));
    534 
    535 	uvmpdpol_set_intent(pg, PQ_INTENT_A);
    536 }
    537 
    538 static void
    539 uvmpdpol_pagedequeue_locked(struct vm_page *pg)
    540 {
    541 	struct uvmpdpol_globalstate *s __diagused = &pdpol_state;
    542 
    543 	KASSERT(mutex_owned(&s->lock));
    544 	KASSERT(mutex_owned(&pg->interlock));
    545 
    546 	if (pg->pqflags & PQ_ACTIVE) {
    547 		TAILQ_REMOVE(&pdpol_state.s_activeq, pg, pdqueue);
    548 		KASSERT((pg->pqflags & PQ_INACTIVE) == 0);
    549 		KASSERT(pdpol_state.s_active > 0);
    550 		pdpol_state.s_active--;
    551 	} else if (pg->pqflags & PQ_INACTIVE) {
    552 		TAILQ_REMOVE(&pdpol_state.s_inactiveq, pg, pdqueue);
    553 		KASSERT(pdpol_state.s_inactive > 0);
    554 		pdpol_state.s_inactive--;
    555 	}
    556 	pg->pqflags &= ~(PQ_ACTIVE | PQ_INACTIVE | PQ_INTENT_SET);
    557 }
    558 
    559 void
    560 uvmpdpol_pagedequeue(struct vm_page *pg)
    561 {
    562 
    563 	KASSERT(uvm_page_owner_locked_p(pg, true));
    564 	KASSERT(mutex_owned(&pg->interlock));
    565 
    566 	uvmpdpol_set_intent(pg, PQ_INTENT_D);
    567 }
    568 
    569 void
    570 uvmpdpol_pageenqueue(struct vm_page *pg)
    571 {
    572 
    573 	KASSERT(uvm_page_owner_locked_p(pg, false));
    574 	KASSERT(mutex_owned(&pg->interlock));
    575 
    576 	uvmpdpol_set_intent(pg, PQ_INTENT_E);
    577 }
    578 
    579 void
    580 uvmpdpol_anfree(struct vm_anon *an)
    581 {
    582 }
    583 
    584 bool
    585 uvmpdpol_pageisqueued_p(struct vm_page *pg)
    586 {
    587 	uint32_t pqflags;
    588 
    589 	/*
    590 	 * if there's an intent set, we have to consider it.  otherwise,
    591 	 * return the actual state.  we may be called unlocked for the
    592 	 * purpose of assertions, which is safe due to the page lifecycle.
    593 	 */
    594 	pqflags = atomic_load_relaxed(&pg->pqflags);
    595 	if ((pqflags & PQ_INTENT_SET) != 0) {
    596 		return (pqflags & PQ_INTENT_MASK) != PQ_INTENT_D;
    597 	} else {
    598 		return (pqflags & (PQ_ACTIVE | PQ_INACTIVE)) != 0;
    599 	}
    600 }
    601 
    602 bool
    603 uvmpdpol_pageactivate_p(struct vm_page *pg)
    604 {
    605 	uint32_t pqflags;
    606 
    607 	/* consider intent in preference to actual state. */
    608 	pqflags = atomic_load_relaxed(&pg->pqflags);
    609 	if ((pqflags & PQ_INTENT_SET) != 0) {
    610 		pqflags &= PQ_INTENT_MASK;
    611 		return pqflags != PQ_INTENT_A && pqflags != PQ_INTENT_E;
    612 	} else {
    613 		/*
    614 		 * TODO: Enabling this may be too much of a big hammer,
    615 		 * since we do get useful information from activations.
    616 		 * Think about it more and maybe come up with a heuristic
    617 		 * or something.
    618 		 *
    619 		 * return (pqflags & PQ_ACTIVE) == 0;
    620 		 */
    621 		return true;
    622 	}
    623 }
    624 
    625 void
    626 uvmpdpol_estimatepageable(int *active, int *inactive)
    627 {
    628 	struct uvmpdpol_globalstate *s = &pdpol_state;
    629 
    630 	/*
    631 	 * Don't take any locks here.  This can be called from DDB, and in
    632 	 * any case the numbers are stale the instant the lock is dropped,
    633 	 * so it just doesn't matter.
    634 	 */
    635 	if (active) {
    636 		*active = s->s_active;
    637 	}
    638 	if (inactive) {
    639 		*inactive = s->s_inactive;
    640 	}
    641 }
    642 
    643 #if !defined(PDSIM)
    644 static int
    645 min_check(struct uvm_pctparam *pct, int t)
    646 {
    647 	struct uvmpdpol_globalstate *s = &pdpol_state;
    648 	int total = t;
    649 
    650 	if (pct != &s->s_anonmin) {
    651 		total += uvm_pctparam_get(&s->s_anonmin);
    652 	}
    653 	if (pct != &s->s_filemin) {
    654 		total += uvm_pctparam_get(&s->s_filemin);
    655 	}
    656 	if (pct != &s->s_execmin) {
    657 		total += uvm_pctparam_get(&s->s_execmin);
    658 	}
    659 	if (total > 95) {
    660 		return EINVAL;
    661 	}
    662 	return 0;
    663 }
    664 #endif /* !defined(PDSIM) */
    665 
    666 void
    667 uvmpdpol_init(void)
    668 {
    669 	struct uvmpdpol_globalstate *s = &pdpol_state;
    670 
    671 	mutex_init(&s->lock, MUTEX_DEFAULT, IPL_NONE);
    672 	TAILQ_INIT(&s->s_activeq);
    673 	TAILQ_INIT(&s->s_inactiveq);
    674 	uvm_pctparam_init(&s->s_inactivepct, CLOCK_INACTIVEPCT, NULL);
    675 	uvm_pctparam_init(&s->s_anonmin, 10, min_check);
    676 	uvm_pctparam_init(&s->s_filemin, 10, min_check);
    677 	uvm_pctparam_init(&s->s_execmin,  5, min_check);
    678 	uvm_pctparam_init(&s->s_anonmax, 80, NULL);
    679 	uvm_pctparam_init(&s->s_filemax, 50, NULL);
    680 	uvm_pctparam_init(&s->s_execmax, 30, NULL);
    681 }
    682 
    683 void
    684 uvmpdpol_init_cpu(struct uvm_cpu *ucpu)
    685 {
    686 
    687 	ucpu->pdq =
    688 	    kmem_alloc(CLOCK_PDQ_SIZE * sizeof(struct vm_page *), KM_SLEEP);
    689 	ucpu->pdqhead = CLOCK_PDQ_SIZE;
    690 	ucpu->pdqtail = CLOCK_PDQ_SIZE;
    691 }
    692 
    693 void
    694 uvmpdpol_reinit(void)
    695 {
    696 }
    697 
    698 bool
    699 uvmpdpol_needsscan_p(void)
    700 {
    701 
    702 	/*
    703 	 * this must be an unlocked check: can be called from interrupt.
    704 	 */
    705 	return pdpol_state.s_inactive < pdpol_state.s_inactarg;
    706 }
    707 
    708 void
    709 uvmpdpol_tune(void)
    710 {
    711 	struct uvmpdpol_globalstate *s = &pdpol_state;
    712 
    713 	mutex_enter(&s->lock);
    714 	clock_tune();
    715 	mutex_exit(&s->lock);
    716 }
    717 
    718 /*
    719  * uvmpdpol_pagerealize_locked: take the intended state set on a page and
    720  * make it real.  return true if any work was done.
    721  */
    722 static bool
    723 uvmpdpol_pagerealize_locked(struct vm_page *pg)
    724 {
    725 	struct uvmpdpol_globalstate *s __diagused = &pdpol_state;
    726 
    727 	KASSERT(mutex_owned(&s->lock));
    728 	KASSERT(mutex_owned(&pg->interlock));
    729 
    730 	switch (pg->pqflags & (PQ_INTENT_MASK | PQ_INTENT_SET)) {
    731 	case PQ_INTENT_A | PQ_INTENT_SET:
    732 	case PQ_INTENT_E | PQ_INTENT_SET:
    733 		uvmpdpol_pageactivate_locked(pg);
    734 		return true;
    735 	case PQ_INTENT_I | PQ_INTENT_SET:
    736 		uvmpdpol_pagedeactivate_locked(pg);
    737 		return true;
    738 	case PQ_INTENT_D | PQ_INTENT_SET:
    739 		uvmpdpol_pagedequeue_locked(pg);
    740 		return true;
    741 	default:
    742 		return false;
    743 	}
    744 }
    745 
    746 /*
    747  * uvmpdpol_flush: return the current uvm_cpu with all of its pending
    748  * updates flushed to the global queues.  this routine may block, and
    749  * so can switch cpu.  the idea is to empty to queue on whatever cpu
    750  * we finally end up on.
    751  * Must be called at splsoftbio()
    752  */
    753 static struct uvm_cpu *
    754 uvmpdpol_flush(void)
    755 {
    756 	struct uvmpdpol_globalstate *s __diagused = &pdpol_state;
    757 	struct uvm_cpu *ucpu;
    758 	struct vm_page *pg;
    759 
    760 	KASSERT(kpreempt_disabled());
    761 
    762 	mutex_enter(&s->lock);
    763 	for (;;) {
    764 		/*
    765 		 * prefer scanning forwards (even though mutex_enter() is
    766 		 * serializing) so as to not defeat any prefetch logic in
    767 		 * the CPU.  that means elsewhere enqueuing backwards, like
    768 		 * a stack, but not so important there as pages are being
    769 		 * added singularly.
    770 		 *
    771 		 * prefetch the next "struct vm_page" while working on the
    772 		 * current one.  this has a measurable and very positive
    773 		 * effect in reducing the amount of time spent here under
    774 		 * the global lock.
    775 		 */
    776 		ucpu = curcpu()->ci_data.cpu_uvm;
    777 		KASSERT(ucpu->pdqhead <= ucpu->pdqtail);
    778 		if (__predict_false(ucpu->pdqhead == ucpu->pdqtail)) {
    779 			break;
    780 		}
    781 		pg = ucpu->pdq[ucpu->pdqhead++];
    782 		if (__predict_true(ucpu->pdqhead != ucpu->pdqtail)) {
    783 			__builtin_prefetch(ucpu->pdq[ucpu->pdqhead]);
    784 		}
    785 		mutex_enter(&pg->interlock);
    786 		pg->pqflags &= ~PQ_INTENT_QUEUED;
    787 		(void)uvmpdpol_pagerealize_locked(pg);
    788 		mutex_exit(&pg->interlock);
    789 	}
    790 	mutex_exit(&s->lock);
    791 	return ucpu;
    792 }
    793 
    794 /*
    795  * uvmpdpol_pagerealize: realize any intent set on the page.  in this
    796  * implementation, that means putting the page on a per-CPU queue to be
    797  * dealt with later.
    798  */
    799 void
    800 uvmpdpol_pagerealize(struct vm_page *pg)
    801 {
    802 	struct uvm_cpu *ucpu;
    803 	int s;
    804 
    805 	/*
    806 	 * drain the per per-CPU queue if full, then enter the page.
    807 	 */
    808 	s = splsoftbio();
    809 	ucpu = curcpu()->ci_data.cpu_uvm;
    810 	while (__predict_false(ucpu->pdqhead == 0)) {
    811 		ucpu = uvmpdpol_flush();
    812 	}
    813 	ucpu->pdq[--(ucpu->pdqhead)] = pg;
    814 	splx(s);
    815 }
    816 
    817 /*
    818  * uvmpdpol_idle: called from the system idle loop.  periodically purge any
    819  * pending updates back to the global queues.
    820  */
    821 void
    822 uvmpdpol_idle(struct uvm_cpu *ucpu)
    823 {
    824 	struct uvmpdpol_globalstate *s = &pdpol_state;
    825 	struct vm_page *pg;
    826 	int s_spl;
    827 
    828 	KASSERT(kpreempt_disabled());
    829 
    830 	/*
    831 	 * if no pages in the queue, we have nothing to do.
    832 	 */
    833 	if (ucpu->pdqhead == ucpu->pdqtail) {
    834 		ucpu->pdqtime = getticks();
    835 		return;
    836 	}
    837 
    838 	/*
    839 	 * don't do this more than ~8 times a second as it would needlessly
    840 	 * exert pressure.
    841 	 */
    842 	if (getticks() - ucpu->pdqtime < (hz >> 3)) {
    843 		return;
    844 	}
    845 
    846 	/*
    847 	 * the idle LWP can't block, so we have to try for the lock.  if we
    848 	 * get it, purge the per-CPU pending update queue.  continually
    849 	 * check for a pending resched: in that case exit immediately.
    850 	 */
    851 	if (mutex_tryenter(&s->lock)) {
    852 		s_spl = splsoftbio();
    853 		while (ucpu->pdqhead != ucpu->pdqtail) {
    854 			pg = ucpu->pdq[ucpu->pdqhead];
    855 			if (!mutex_tryenter(&pg->interlock)) {
    856 				break;
    857 			}
    858 			ucpu->pdqhead++;
    859 			pg->pqflags &= ~PQ_INTENT_QUEUED;
    860 			(void)uvmpdpol_pagerealize_locked(pg);
    861 			mutex_exit(&pg->interlock);
    862 			if (curcpu()->ci_want_resched) {
    863 				break;
    864 			}
    865 		}
    866 		if (ucpu->pdqhead == ucpu->pdqtail) {
    867 			ucpu->pdqtime = getticks();
    868 		}
    869 		splx(s_spl);
    870 		mutex_exit(&s->lock);
    871 	}
    872 }
    873 
    874 #if !defined(PDSIM)
    875 
    876 #include <sys/sysctl.h>	/* XXX SYSCTL_DESCR */
    877 
    878 void
    879 uvmpdpol_sysctlsetup(void)
    880 {
    881 	struct uvmpdpol_globalstate *s = &pdpol_state;
    882 
    883 	uvm_pctparam_createsysctlnode(&s->s_anonmin, "anonmin",
    884 	    SYSCTL_DESCR("Percentage of physical memory reserved "
    885 	    "for anonymous application data"));
    886 	uvm_pctparam_createsysctlnode(&s->s_filemin, "filemin",
    887 	    SYSCTL_DESCR("Percentage of physical memory reserved "
    888 	    "for cached file data"));
    889 	uvm_pctparam_createsysctlnode(&s->s_execmin, "execmin",
    890 	    SYSCTL_DESCR("Percentage of physical memory reserved "
    891 	    "for cached executable data"));
    892 
    893 	uvm_pctparam_createsysctlnode(&s->s_anonmax, "anonmax",
    894 	    SYSCTL_DESCR("Percentage of physical memory which will "
    895 	    "be reclaimed from other usage for "
    896 	    "anonymous application data"));
    897 	uvm_pctparam_createsysctlnode(&s->s_filemax, "filemax",
    898 	    SYSCTL_DESCR("Percentage of physical memory which will "
    899 	    "be reclaimed from other usage for cached "
    900 	    "file data"));
    901 	uvm_pctparam_createsysctlnode(&s->s_execmax, "execmax",
    902 	    SYSCTL_DESCR("Percentage of physical memory which will "
    903 	    "be reclaimed from other usage for cached "
    904 	    "executable data"));
    905 
    906 	uvm_pctparam_createsysctlnode(&s->s_inactivepct, "inactivepct",
    907 	    SYSCTL_DESCR("Percentage of inactive queue of "
    908 	    "the entire (active + inactive) queue"));
    909 }
    910 
    911 #endif /* !defined(PDSIM) */
    912 
    913 #if defined(PDSIM)
    914 void
    915 pdsim_dump(const char *id)
    916 {
    917 #if defined(DEBUG)
    918 	/* XXX */
    919 #endif /* defined(DEBUG) */
    920 }
    921 #endif /* defined(PDSIM) */
    922