112e4aaffSMatthew Dillon /*-
212e4aaffSMatthew Dillon * Copyright (c) 1982, 1986, 1993
312e4aaffSMatthew Dillon * The Regents of the University of California. All rights reserved.
412e4aaffSMatthew Dillon *
512e4aaffSMatthew Dillon * Redistribution and use in source and binary forms, with or without
612e4aaffSMatthew Dillon * modification, are permitted provided that the following conditions
712e4aaffSMatthew Dillon * are met:
812e4aaffSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
912e4aaffSMatthew Dillon * notice, this list of conditions and the following disclaimer.
1012e4aaffSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
1112e4aaffSMatthew Dillon * notice, this list of conditions and the following disclaimer in the
1212e4aaffSMatthew Dillon * documentation and/or other materials provided with the distribution.
132c64e990Szrj * 3. Neither the name of the University nor the names of its contributors
1412e4aaffSMatthew Dillon * may be used to endorse or promote products derived from this software
1512e4aaffSMatthew Dillon * without specific prior written permission.
1612e4aaffSMatthew Dillon *
1712e4aaffSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1812e4aaffSMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1912e4aaffSMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2012e4aaffSMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2112e4aaffSMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2212e4aaffSMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2312e4aaffSMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2412e4aaffSMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2512e4aaffSMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2612e4aaffSMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2712e4aaffSMatthew Dillon * SUCH DAMAGE.
2812e4aaffSMatthew Dillon *
2912e4aaffSMatthew Dillon * @(#)vmmeter.h 8.2 (Berkeley) 7/10/94
3012e4aaffSMatthew Dillon * $FreeBSD: src/sys/sys/vmmeter.h,v 1.21.2.2 2002/10/10 19:28:21 dillon Exp $
3112e4aaffSMatthew Dillon */
3212e4aaffSMatthew Dillon
331bd40720SMatthew Dillon #ifndef _VM_VM_PAGE2_H_
341bd40720SMatthew Dillon #define _VM_VM_PAGE2_H_
3512e4aaffSMatthew Dillon
363f397408STomohiro Kusumi #ifdef _KERNEL
373f397408STomohiro Kusumi
3812e4aaffSMatthew Dillon #ifndef _SYS_VMMETER_H_
3912e4aaffSMatthew Dillon #include <sys/vmmeter.h>
4012e4aaffSMatthew Dillon #endif
4110192baeSMatthew Dillon #ifndef _SYS_QUEUE_H_
4210192baeSMatthew Dillon #include <sys/queue.h>
4310192baeSMatthew Dillon #endif
44210a0869SSascha Wildner #ifndef _VM_VM_PAGE_H_
4510192baeSMatthew Dillon #include <vm/vm_page.h>
4610192baeSMatthew Dillon #endif
47b12defdcSMatthew Dillon #ifndef _SYS_SPINLOCK_H_
48b12defdcSMatthew Dillon #include <sys/spinlock.h>
49b12defdcSMatthew Dillon #endif
50b12defdcSMatthew Dillon #ifndef _SYS_SPINLOCK2_H_
51b12defdcSMatthew Dillon #include <sys/spinlock2.h>
52b12defdcSMatthew Dillon #endif
5312e4aaffSMatthew Dillon
5412e4aaffSMatthew Dillon /*
5575979118SMatthew Dillon * SMP NOTE
5675979118SMatthew Dillon *
5775979118SMatthew Dillon * VM fault rates are highly dependent on SMP locking conflicts and, on
5875979118SMatthew Dillon * multi-socket systems, cache mastership changes for globals due to atomic
5975979118SMatthew Dillon * ops (even simple atomic_add_*() calls). Cache mastership changes can
6075979118SMatthew Dillon * limit the aggregate fault rate.
6175979118SMatthew Dillon *
6275979118SMatthew Dillon * For this reason we go through some hoops to access VM statistics for
6375979118SMatthew Dillon * low-memory handling, pageout, and other triggers. Each cpu collects
6475979118SMatthew Dillon * adjustments in gd->gd_vmstats_adj. These get rolled up into the global
6575979118SMatthew Dillon * vmstats structure. The global vmstats structure is then pulled into
6675979118SMatthew Dillon * gd->gd_vmstats by each cpu when it needs it. Critical path checks always
6775979118SMatthew Dillon * use the pcpu gd->gd_vmstats structure.
6875979118SMatthew Dillon */
6975979118SMatthew Dillon /*
7012e4aaffSMatthew Dillon * Return TRUE if we are under our severe low-free-pages threshold
7112e4aaffSMatthew Dillon *
7220479584SMatthew Dillon * This causes user processes to stall to avoid exhausting memory that
7320479584SMatthew Dillon * the kernel might need.
7420479584SMatthew Dillon *
75e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
7612e4aaffSMatthew Dillon */
7712e4aaffSMatthew Dillon static __inline
7812e4aaffSMatthew Dillon int
vm_paging_severe(void)79e91e64c7SMatthew Dillon vm_paging_severe(void)
8012e4aaffSMatthew Dillon {
8175979118SMatthew Dillon globaldata_t gd = mycpu;
8275979118SMatthew Dillon
83e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_severe >
84e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count +
85e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count))
86e91e64c7SMatthew Dillon {
87e91e64c7SMatthew Dillon return 1;
88e91e64c7SMatthew Dillon }
89e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
90e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
91e91e64c7SMatthew Dillon {
92e91e64c7SMatthew Dillon return 1;
93e91e64c7SMatthew Dillon }
94e91e64c7SMatthew Dillon return 0;
9512e4aaffSMatthew Dillon }
9612e4aaffSMatthew Dillon
9712e4aaffSMatthew Dillon /*
98e91e64c7SMatthew Dillon * Return TRUE if we are under our minimum low-free-pages threshold. We
99e91e64c7SMatthew Dillon * will not count (donotcount) free pages as being free (used mainly for
100e91e64c7SMatthew Dillon * hystersis tests).
10112e4aaffSMatthew Dillon *
102e91e64c7SMatthew Dillon * This will cause most normal page faults to block and activate the
103e91e64c7SMatthew Dillon * pageout daemon.
104e91e64c7SMatthew Dillon *
105e91e64c7SMatthew Dillon * The pageout daemon should already be active due to vm_paging_start(n)
106e91e64c7SMatthew Dillon * and will typically continue running until it hits target2
107e91e64c7SMatthew Dillon *
108e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
10912e4aaffSMatthew Dillon */
11012e4aaffSMatthew Dillon static __inline
11112e4aaffSMatthew Dillon int
vm_paging_min_dnc(long donotcount)112e91e64c7SMatthew Dillon vm_paging_min_dnc(long donotcount)
11312e4aaffSMatthew Dillon {
11475979118SMatthew Dillon globaldata_t gd = mycpu;
11575979118SMatthew Dillon
116e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_min + donotcount >
117e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count +
118e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count)))
119e91e64c7SMatthew Dillon {
120e91e64c7SMatthew Dillon return 1;
121e91e64c7SMatthew Dillon }
122e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
123e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
124e91e64c7SMatthew Dillon {
125e91e64c7SMatthew Dillon return 1;
126e91e64c7SMatthew Dillon }
127e91e64c7SMatthew Dillon return 0;
128e91e64c7SMatthew Dillon }
129e91e64c7SMatthew Dillon
130*2198d48dSMatthew Dillon /*
131*2198d48dSMatthew Dillon * Returns TRUE if the number of FREE+CACHE pages falls below vm_paging_wait,
132*2198d48dSMatthew Dillon * based on the nice value the trip point can be between vm_paging_min and
133*2198d48dSMatthew Dillon * vm_paging_wait.
134*2198d48dSMatthew Dillon *
135*2198d48dSMatthew Dillon * Used by vm_fault (see vm_wait_pfault()) to block a process on low-memory
136*2198d48dSMatthew Dillon * based on the process 'nice' value (-20 to +20).
137*2198d48dSMatthew Dillon */
138*2198d48dSMatthew Dillon static __inline
139*2198d48dSMatthew Dillon int
vm_paging_min_nice(int nice)140*2198d48dSMatthew Dillon vm_paging_min_nice(int nice)
141*2198d48dSMatthew Dillon {
142*2198d48dSMatthew Dillon long count;
143*2198d48dSMatthew Dillon long delta;
144*2198d48dSMatthew Dillon
145*2198d48dSMatthew Dillon count = 0;
146*2198d48dSMatthew Dillon if (nice) {
147*2198d48dSMatthew Dillon delta = vmstats.v_paging_wait - vmstats.v_free_min - 1;
148*2198d48dSMatthew Dillon delta = delta >> 1;
149*2198d48dSMatthew Dillon if (delta > 0) {
150*2198d48dSMatthew Dillon /* range 0-40, 0 is high priority, 40 is low */
151*2198d48dSMatthew Dillon count = (nice + 20) * delta / 40;
152*2198d48dSMatthew Dillon }
153*2198d48dSMatthew Dillon }
154*2198d48dSMatthew Dillon return vm_paging_min_dnc(count);
155*2198d48dSMatthew Dillon }
156*2198d48dSMatthew Dillon
157e91e64c7SMatthew Dillon static __inline
158e91e64c7SMatthew Dillon int
vm_paging_min(void)159e91e64c7SMatthew Dillon vm_paging_min(void)
160e91e64c7SMatthew Dillon {
161e91e64c7SMatthew Dillon return vm_paging_min_dnc(0);
16212e4aaffSMatthew Dillon }
16312e4aaffSMatthew Dillon
16412e4aaffSMatthew Dillon /*
165e91e64c7SMatthew Dillon * Return TRUE if nominal userland / VM-system allocations should slow
166e91e64c7SMatthew Dillon * down (but not stop) due to low free pages in the system. This is
167e91e64c7SMatthew Dillon * typically 1/2 way between min and start.
16877d1fb91SMatthew Dillon *
169e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
17012e4aaffSMatthew Dillon */
17112e4aaffSMatthew Dillon static __inline
17212e4aaffSMatthew Dillon int
vm_paging_wait(void)173e91e64c7SMatthew Dillon vm_paging_wait(void)
17412e4aaffSMatthew Dillon {
17575979118SMatthew Dillon globaldata_t gd = mycpu;
17675979118SMatthew Dillon
177e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_paging_wait >
178e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count +
179e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count)))
180e91e64c7SMatthew Dillon {
181e91e64c7SMatthew Dillon return 1;
182e91e64c7SMatthew Dillon }
183e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
184e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
185e91e64c7SMatthew Dillon {
186e91e64c7SMatthew Dillon return 1;
187e91e64c7SMatthew Dillon }
188e91e64c7SMatthew Dillon return 0;
18912e4aaffSMatthew Dillon }
19012e4aaffSMatthew Dillon
19112e4aaffSMatthew Dillon /*
192e91e64c7SMatthew Dillon * Return TRUE if the pageout daemon should be started up or continue
193e91e64c7SMatthew Dillon * running. Available pages have dropped to a level where we need to
194e91e64c7SMatthew Dillon * think about freeing some up.
195cd3c66bdSMatthew Dillon *
196e91e64c7SMatthew Dillon * Also handles edge cases for required 'actually-free' pages.
197cd3c66bdSMatthew Dillon *
198e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
199e91e64c7SMatthew Dillon */
200e91e64c7SMatthew Dillon static __inline
201e91e64c7SMatthew Dillon int
vm_paging_start(int adj)202e91e64c7SMatthew Dillon vm_paging_start(int adj)
203e91e64c7SMatthew Dillon {
204e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
205e91e64c7SMatthew Dillon
206e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_paging_start >
207e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count +
208e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count + adj)))
209e91e64c7SMatthew Dillon {
210e91e64c7SMatthew Dillon return 1;
211e91e64c7SMatthew Dillon }
212e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_min >
213e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count + adj))
214e91e64c7SMatthew Dillon {
215e91e64c7SMatthew Dillon return 1;
216e91e64c7SMatthew Dillon }
217e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
218e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
219e91e64c7SMatthew Dillon {
220e91e64c7SMatthew Dillon return 1;
221e91e64c7SMatthew Dillon }
222e91e64c7SMatthew Dillon return 0;
223e91e64c7SMatthew Dillon }
224e91e64c7SMatthew Dillon
225e91e64c7SMatthew Dillon /*
226e91e64c7SMatthew Dillon * Return TRUE if the pageout daemon has not yet reached its initial target.
227e91e64c7SMatthew Dillon * The pageout daemon works hard to reach target1.
228e91e64c7SMatthew Dillon *
229e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
230e91e64c7SMatthew Dillon */
231e91e64c7SMatthew Dillon static __inline
232e91e64c7SMatthew Dillon int
vm_paging_target1(void)233e91e64c7SMatthew Dillon vm_paging_target1(void)
234e91e64c7SMatthew Dillon {
235e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
236e91e64c7SMatthew Dillon
237e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_paging_target1 >
238e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count +
239e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count)))
240e91e64c7SMatthew Dillon {
241e91e64c7SMatthew Dillon return 1;
242e91e64c7SMatthew Dillon }
243e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
244e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
245e91e64c7SMatthew Dillon {
246e91e64c7SMatthew Dillon return 1;
247e91e64c7SMatthew Dillon }
248e91e64c7SMatthew Dillon return 0;
249e91e64c7SMatthew Dillon }
250e91e64c7SMatthew Dillon
251e91e64c7SMatthew Dillon static __inline
252e91e64c7SMatthew Dillon long
vm_paging_target1_count(void)253e91e64c7SMatthew Dillon vm_paging_target1_count(void)
254e91e64c7SMatthew Dillon {
255e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
256e91e64c7SMatthew Dillon long delta;
257e91e64c7SMatthew Dillon
258e91e64c7SMatthew Dillon delta = gd->gd_vmstats.v_paging_target1 -
259e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count + gd->gd_vmstats.v_cache_count);
260e91e64c7SMatthew Dillon return delta;
261e91e64c7SMatthew Dillon }
262e91e64c7SMatthew Dillon
263e91e64c7SMatthew Dillon /*
264e91e64c7SMatthew Dillon * Return TRUE if the pageout daemon has not yet reached its final target.
265e91e64c7SMatthew Dillon * The pageout daemon takes it easy on its way between target1 and target2.
266e91e64c7SMatthew Dillon *
267e91e64c7SMatthew Dillon * reserved < severe < minimum < wait < start < target1 < target2
268e91e64c7SMatthew Dillon */
269e91e64c7SMatthew Dillon static __inline
270e91e64c7SMatthew Dillon int
vm_paging_target2(void)271e91e64c7SMatthew Dillon vm_paging_target2(void)
272e91e64c7SMatthew Dillon {
273e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
274e91e64c7SMatthew Dillon
275e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_paging_target2 >
276e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count +
277e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count)))
278e91e64c7SMatthew Dillon {
279e91e64c7SMatthew Dillon return 1;
280e91e64c7SMatthew Dillon }
281e91e64c7SMatthew Dillon if (__predict_false(gd->gd_vmstats.v_free_reserved >
282e91e64c7SMatthew Dillon gd->gd_vmstats.v_free_count))
283e91e64c7SMatthew Dillon {
284e91e64c7SMatthew Dillon return 1;
285e91e64c7SMatthew Dillon }
286e91e64c7SMatthew Dillon return 0;
287e91e64c7SMatthew Dillon }
288e91e64c7SMatthew Dillon
289e91e64c7SMatthew Dillon static __inline
290e91e64c7SMatthew Dillon long
vm_paging_target2_count(void)291e91e64c7SMatthew Dillon vm_paging_target2_count(void)
292e91e64c7SMatthew Dillon {
293e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
294e91e64c7SMatthew Dillon long delta;
295e91e64c7SMatthew Dillon
296e91e64c7SMatthew Dillon delta = gd->gd_vmstats.v_paging_target2 -
297e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count + gd->gd_vmstats.v_cache_count);
298e91e64c7SMatthew Dillon return delta;
299e91e64c7SMatthew Dillon }
300e91e64c7SMatthew Dillon
301e91e64c7SMatthew Dillon /*
302e91e64c7SMatthew Dillon * Returns TRUE if additional pages must be deactivated, either during a
303e91e64c7SMatthew Dillon * pageout operation or during the page stats scan.
304e91e64c7SMatthew Dillon *
305e91e64c7SMatthew Dillon * Inactive tests are used in two places. During heavy paging the
306e91e64c7SMatthew Dillon * inactive_target is used to refill the inactive queue in staged.
307e91e64c7SMatthew Dillon * Those pages are then ultimately flushed and moved to the cache or free
308e91e64c7SMatthew Dillon * queues.
309e91e64c7SMatthew Dillon *
310e91e64c7SMatthew Dillon * The inactive queue is also used to manage scans to update page stats
311e91e64c7SMatthew Dillon * (m->act_count). The page stats scan occurs lazily in small batches to
312e91e64c7SMatthew Dillon * update m->act_count for pages in the active queue and to move pages
313e91e64c7SMatthew Dillon * (limited by inactive_target) to the inactive queue. Page stats scanning
314e91e64c7SMatthew Dillon * and active deactivations only run while the inactive queue is below target.
315e91e64c7SMatthew Dillon * After this, additional page stats scanning just to update m->act_count
316e91e64c7SMatthew Dillon * (but not do further deactivations) continues to run for a limited period
317e91e64c7SMatthew Dillon * of time after any pageout daemon activity.
318e91e64c7SMatthew Dillon */
319e91e64c7SMatthew Dillon static __inline
320e91e64c7SMatthew Dillon int
vm_paging_inactive(void)321e91e64c7SMatthew Dillon vm_paging_inactive(void)
322e91e64c7SMatthew Dillon {
323e91e64c7SMatthew Dillon globaldata_t gd = mycpu;
324e91e64c7SMatthew Dillon
325e91e64c7SMatthew Dillon if (__predict_false((gd->gd_vmstats.v_free_count +
326e91e64c7SMatthew Dillon gd->gd_vmstats.v_cache_count +
327e91e64c7SMatthew Dillon gd->gd_vmstats.v_inactive_count) <
328e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_min +
329e91e64c7SMatthew Dillon gd->gd_vmstats.v_inactive_target)))
330e91e64c7SMatthew Dillon {
331e91e64c7SMatthew Dillon return 1;
332e91e64c7SMatthew Dillon }
333e91e64c7SMatthew Dillon return 0;
334e91e64c7SMatthew Dillon }
335e91e64c7SMatthew Dillon
336e91e64c7SMatthew Dillon /*
337e91e64c7SMatthew Dillon * Return number of pages that need to be deactivated to achieve the inactive
338e91e64c7SMatthew Dillon * target as a positive number. A negative number indicates that there are
339e91e64c7SMatthew Dillon * already a sufficient number of inactive pages.
34012e4aaffSMatthew Dillon */
34112e4aaffSMatthew Dillon static __inline
342b7ea2f3fSMatthew Dillon long
vm_paging_inactive_count(void)343e91e64c7SMatthew Dillon vm_paging_inactive_count(void)
34412e4aaffSMatthew Dillon {
34575979118SMatthew Dillon globaldata_t gd = mycpu;
346e91e64c7SMatthew Dillon long delta;
34775979118SMatthew Dillon
348e91e64c7SMatthew Dillon delta = (gd->gd_vmstats.v_free_min + gd->gd_vmstats.v_inactive_target) -
349e91e64c7SMatthew Dillon (gd->gd_vmstats.v_free_count + gd->gd_vmstats.v_cache_count +
350e91e64c7SMatthew Dillon gd->gd_vmstats.v_inactive_count);
35112e4aaffSMatthew Dillon
352e91e64c7SMatthew Dillon return delta;
35312e4aaffSMatthew Dillon }
35412e4aaffSMatthew Dillon
3551a54183bSMatthew Dillon /*
3561a54183bSMatthew Dillon * Clear dirty bits in the VM page but truncate the
3571a54183bSMatthew Dillon * end to a DEV_BSIZE'd boundary.
3581a54183bSMatthew Dillon *
3591a54183bSMatthew Dillon * Used when reading data in, typically via getpages.
3601a54183bSMatthew Dillon * The partial device block at the end of the truncation
3611a54183bSMatthew Dillon * range should not lose its dirty bit.
362cb1cf930SMatthew Dillon *
363cb1cf930SMatthew Dillon * NOTE: This function does not clear the pmap modified bit.
3641a54183bSMatthew Dillon */
3651a54183bSMatthew Dillon static __inline
3661a54183bSMatthew Dillon void
vm_page_clear_dirty_end_nonincl(vm_page_t m,int base,int size)3671a54183bSMatthew Dillon vm_page_clear_dirty_end_nonincl(vm_page_t m, int base, int size)
3681a54183bSMatthew Dillon {
3691a54183bSMatthew Dillon size = (base + size) & ~DEV_BMASK;
3701a54183bSMatthew Dillon if (base < size)
3711a54183bSMatthew Dillon vm_page_clear_dirty(m, base, size - base);
3721a54183bSMatthew Dillon }
3731a54183bSMatthew Dillon
3741a54183bSMatthew Dillon /*
3751a54183bSMatthew Dillon * Clear dirty bits in the VM page but truncate the
3761a54183bSMatthew Dillon * beginning to a DEV_BSIZE'd boundary.
3771a54183bSMatthew Dillon *
3781a54183bSMatthew Dillon * Used when truncating a buffer. The partial device
3791a54183bSMatthew Dillon * block at the beginning of the truncation range
3801a54183bSMatthew Dillon * should not lose its dirty bit.
381cb1cf930SMatthew Dillon *
382cb1cf930SMatthew Dillon * NOTE: This function does not clear the pmap modified bit.
3831a54183bSMatthew Dillon */
3841a54183bSMatthew Dillon static __inline
3851a54183bSMatthew Dillon void
vm_page_clear_dirty_beg_nonincl(vm_page_t m,int base,int size)3861a54183bSMatthew Dillon vm_page_clear_dirty_beg_nonincl(vm_page_t m, int base, int size)
3871a54183bSMatthew Dillon {
3881a54183bSMatthew Dillon size += base;
3891a54183bSMatthew Dillon base = (base + DEV_BMASK) & ~DEV_BMASK;
3901a54183bSMatthew Dillon if (base < size)
3911a54183bSMatthew Dillon vm_page_clear_dirty(m, base, size - base);
3921a54183bSMatthew Dillon }
3931a54183bSMatthew Dillon
394b12defdcSMatthew Dillon static __inline
395b12defdcSMatthew Dillon void
vm_page_spin_lock(vm_page_t m)396b12defdcSMatthew Dillon vm_page_spin_lock(vm_page_t m)
397b12defdcSMatthew Dillon {
3986ba5daf8SMatthew Dillon spin_lock(&m->spin);
399b12defdcSMatthew Dillon }
400b12defdcSMatthew Dillon
401b12defdcSMatthew Dillon static __inline
402b12defdcSMatthew Dillon void
vm_page_spin_unlock(vm_page_t m)403b12defdcSMatthew Dillon vm_page_spin_unlock(vm_page_t m)
404b12defdcSMatthew Dillon {
4056ba5daf8SMatthew Dillon spin_unlock(&m->spin);
406b12defdcSMatthew Dillon }
407b12defdcSMatthew Dillon
408b12defdcSMatthew Dillon /*
409b12defdcSMatthew Dillon * Wire a vm_page that is already wired. Does not require a busied
410b12defdcSMatthew Dillon * page.
411b12defdcSMatthew Dillon */
412b12defdcSMatthew Dillon static __inline
413b12defdcSMatthew Dillon void
vm_page_wire_quick(vm_page_t m)414b12defdcSMatthew Dillon vm_page_wire_quick(vm_page_t m)
415b12defdcSMatthew Dillon {
416b12defdcSMatthew Dillon if (atomic_fetchadd_int(&m->wire_count, 1) == 0)
417b12defdcSMatthew Dillon panic("vm_page_wire_quick: wire_count was 0");
418b12defdcSMatthew Dillon }
419b12defdcSMatthew Dillon
420b12defdcSMatthew Dillon /*
421b12defdcSMatthew Dillon * Unwire a vm_page quickly, does not require a busied page.
422b12defdcSMatthew Dillon *
423b12defdcSMatthew Dillon * This routine refuses to drop the wire_count to 0 and will return
424b12defdcSMatthew Dillon * TRUE if it would have had to (instead of decrementing it to 0).
425b12defdcSMatthew Dillon * The caller can then busy the page and deal with it.
426b12defdcSMatthew Dillon */
427b12defdcSMatthew Dillon static __inline
428b12defdcSMatthew Dillon int
vm_page_unwire_quick(vm_page_t m)429b12defdcSMatthew Dillon vm_page_unwire_quick(vm_page_t m)
430b12defdcSMatthew Dillon {
431b12defdcSMatthew Dillon KKASSERT(m->wire_count > 0);
432b12defdcSMatthew Dillon for (;;) {
433b12defdcSMatthew Dillon u_int wire_count = m->wire_count;
434b12defdcSMatthew Dillon
435b12defdcSMatthew Dillon cpu_ccfence();
436b12defdcSMatthew Dillon if (wire_count == 1)
437b12defdcSMatthew Dillon return TRUE;
438b12defdcSMatthew Dillon if (atomic_cmpset_int(&m->wire_count, wire_count, wire_count - 1))
439b12defdcSMatthew Dillon return FALSE;
440b12defdcSMatthew Dillon }
441b12defdcSMatthew Dillon }
442b12defdcSMatthew Dillon
443a86ce0cdSMatthew Dillon /*
444a86ce0cdSMatthew Dillon * Functions implemented as macros
445a86ce0cdSMatthew Dillon */
446a86ce0cdSMatthew Dillon
447a86ce0cdSMatthew Dillon static __inline void
vm_page_flag_set(vm_page_t m,unsigned int bits)448a86ce0cdSMatthew Dillon vm_page_flag_set(vm_page_t m, unsigned int bits)
449a86ce0cdSMatthew Dillon {
450a86ce0cdSMatthew Dillon atomic_set_int(&(m)->flags, bits);
451a86ce0cdSMatthew Dillon }
452a86ce0cdSMatthew Dillon
453a86ce0cdSMatthew Dillon static __inline void
vm_page_flag_clear(vm_page_t m,unsigned int bits)454a86ce0cdSMatthew Dillon vm_page_flag_clear(vm_page_t m, unsigned int bits)
455a86ce0cdSMatthew Dillon {
456a86ce0cdSMatthew Dillon atomic_clear_int(&(m)->flags, bits);
457a86ce0cdSMatthew Dillon }
458a86ce0cdSMatthew Dillon
459a86ce0cdSMatthew Dillon /*
460a86ce0cdSMatthew Dillon * Wakeup anyone waiting for the page after potentially unbusying
461a86ce0cdSMatthew Dillon * (hard or soft) or doing other work on a page that might make a
462bc0aa189SMatthew Dillon * waiter ready. The setting of PBUSY_WANTED is integrated into the
463a86ce0cdSMatthew Dillon * related flags and it can't be set once the flags are already
464a86ce0cdSMatthew Dillon * clear, so there should be no races here.
465a86ce0cdSMatthew Dillon */
466a86ce0cdSMatthew Dillon static __inline void
vm_page_flash(vm_page_t m)467a86ce0cdSMatthew Dillon vm_page_flash(vm_page_t m)
468a86ce0cdSMatthew Dillon {
469bc0aa189SMatthew Dillon if (m->busy_count & PBUSY_WANTED) {
470bc0aa189SMatthew Dillon atomic_clear_int(&m->busy_count, PBUSY_WANTED);
471bc0aa189SMatthew Dillon wakeup(m);
472bc0aa189SMatthew Dillon }
473bc0aa189SMatthew Dillon }
474bc0aa189SMatthew Dillon
475bc0aa189SMatthew Dillon /*
476bc0aa189SMatthew Dillon * Adjust the soft-busy count on a page. The drop code will issue an
477bc0aa189SMatthew Dillon * integrated wakeup if busy_count becomes 0.
478bc0aa189SMatthew Dillon */
479bc0aa189SMatthew Dillon static __inline void
vm_page_sbusy_hold(vm_page_t m)480bc0aa189SMatthew Dillon vm_page_sbusy_hold(vm_page_t m)
481bc0aa189SMatthew Dillon {
482bc0aa189SMatthew Dillon atomic_add_int(&m->busy_count, 1);
483bc0aa189SMatthew Dillon }
484bc0aa189SMatthew Dillon
485bc0aa189SMatthew Dillon static __inline void
vm_page_sbusy_drop(vm_page_t m)486bc0aa189SMatthew Dillon vm_page_sbusy_drop(vm_page_t m)
487bc0aa189SMatthew Dillon {
488bc0aa189SMatthew Dillon uint32_t ocount;
489bc0aa189SMatthew Dillon
490bc0aa189SMatthew Dillon ocount = atomic_fetchadd_int(&m->busy_count, -1);
491bc0aa189SMatthew Dillon if (ocount - 1 == PBUSY_WANTED) {
492bc0aa189SMatthew Dillon /* WANTED and no longer BUSY or SBUSY */
493bc0aa189SMatthew Dillon atomic_clear_int(&m->busy_count, PBUSY_WANTED);
494a86ce0cdSMatthew Dillon wakeup(m);
495a86ce0cdSMatthew Dillon }
496a86ce0cdSMatthew Dillon }
497a86ce0cdSMatthew Dillon
498a86ce0cdSMatthew Dillon /*
499a86ce0cdSMatthew Dillon * Reduce the protection of a page. This routine never raises the
500a86ce0cdSMatthew Dillon * protection and therefore can be safely called if the page is already
501a86ce0cdSMatthew Dillon * at VM_PROT_NONE (it will be a NOP effectively ).
502a86ce0cdSMatthew Dillon *
503a86ce0cdSMatthew Dillon * VM_PROT_NONE will remove all user mappings of a page. This is often
504a86ce0cdSMatthew Dillon * necessary when a page changes state (for example, turns into a copy-on-write
505a86ce0cdSMatthew Dillon * page or needs to be frozen for write I/O) in order to force a fault, or
506a86ce0cdSMatthew Dillon * to force a page's dirty bits to be synchronized and avoid hardware
507a86ce0cdSMatthew Dillon * (modified/accessed) bit update races with pmap changes.
508a86ce0cdSMatthew Dillon *
509a86ce0cdSMatthew Dillon * Since 'prot' is usually a constant, this inline usually winds up optimizing
510a86ce0cdSMatthew Dillon * out the primary conditional.
511a86ce0cdSMatthew Dillon *
512530e94fcSMatthew Dillon * Must be called with (m) hard-busied.
513530e94fcSMatthew Dillon *
514a86ce0cdSMatthew Dillon * WARNING: VM_PROT_NONE can block, but will loop until all mappings have
515530e94fcSMatthew Dillon * been cleared. Callers should be aware that other page related
516530e94fcSMatthew Dillon * elements might have changed, however.
517a86ce0cdSMatthew Dillon */
518a86ce0cdSMatthew Dillon static __inline void
vm_page_protect(vm_page_t m,int prot)519a86ce0cdSMatthew Dillon vm_page_protect(vm_page_t m, int prot)
520a86ce0cdSMatthew Dillon {
521bc0aa189SMatthew Dillon KKASSERT(m->busy_count & PBUSY_LOCKED);
522a86ce0cdSMatthew Dillon if (prot == VM_PROT_NONE) {
523c2830aa6SMatthew Dillon if (pmap_mapped_sync(m) & (PG_MAPPED | PG_WRITEABLE)) {
524a86ce0cdSMatthew Dillon pmap_page_protect(m, VM_PROT_NONE);
525a86ce0cdSMatthew Dillon /* PG_WRITEABLE & PG_MAPPED cleared by call */
526a86ce0cdSMatthew Dillon }
527e3c330f0SMatthew Dillon } else if ((prot == VM_PROT_READ) &&
528e3c330f0SMatthew Dillon (m->flags & PG_WRITEABLE) &&
529e3c330f0SMatthew Dillon (pmap_mapped_sync(m) & PG_WRITEABLE)) {
530a86ce0cdSMatthew Dillon pmap_page_protect(m, VM_PROT_READ);
531a86ce0cdSMatthew Dillon /* PG_WRITEABLE cleared by call */
532a86ce0cdSMatthew Dillon }
533a86ce0cdSMatthew Dillon }
534a86ce0cdSMatthew Dillon
535a86ce0cdSMatthew Dillon /*
536a86ce0cdSMatthew Dillon * Zero-fill the specified page. The entire contents of the page will be
537a86ce0cdSMatthew Dillon * zero'd out.
538a86ce0cdSMatthew Dillon */
539a86ce0cdSMatthew Dillon static __inline boolean_t
vm_page_zero_fill(vm_page_t m)540a86ce0cdSMatthew Dillon vm_page_zero_fill(vm_page_t m)
541a86ce0cdSMatthew Dillon {
542a86ce0cdSMatthew Dillon pmap_zero_page(VM_PAGE_TO_PHYS(m));
543a86ce0cdSMatthew Dillon return (TRUE);
544a86ce0cdSMatthew Dillon }
545a86ce0cdSMatthew Dillon
546a86ce0cdSMatthew Dillon /*
547a86ce0cdSMatthew Dillon * Copy the contents of src_m to dest_m. The pages must be stable but spl
548a86ce0cdSMatthew Dillon * and other protections depend on context.
549a86ce0cdSMatthew Dillon */
550a86ce0cdSMatthew Dillon static __inline void
vm_page_copy(vm_page_t src_m,vm_page_t dest_m)551a86ce0cdSMatthew Dillon vm_page_copy(vm_page_t src_m, vm_page_t dest_m)
552a86ce0cdSMatthew Dillon {
553a86ce0cdSMatthew Dillon pmap_copy_page(VM_PAGE_TO_PHYS(src_m), VM_PAGE_TO_PHYS(dest_m));
554a86ce0cdSMatthew Dillon dest_m->valid = VM_PAGE_BITS_ALL;
555a86ce0cdSMatthew Dillon dest_m->dirty = VM_PAGE_BITS_ALL;
556a86ce0cdSMatthew Dillon }
557a86ce0cdSMatthew Dillon
558a86ce0cdSMatthew Dillon /*
559a86ce0cdSMatthew Dillon * Free a page. The page must be marked BUSY.
560a86ce0cdSMatthew Dillon */
561a86ce0cdSMatthew Dillon static __inline void
vm_page_free(vm_page_t m)562a86ce0cdSMatthew Dillon vm_page_free(vm_page_t m)
563a86ce0cdSMatthew Dillon {
564a86ce0cdSMatthew Dillon vm_page_free_toq(m);
565a86ce0cdSMatthew Dillon }
566a86ce0cdSMatthew Dillon
567a86ce0cdSMatthew Dillon /*
568a86ce0cdSMatthew Dillon * Free a page to the zerod-pages queue. The caller must ensure that the
569a86ce0cdSMatthew Dillon * page has been zerod.
570a86ce0cdSMatthew Dillon */
571a86ce0cdSMatthew Dillon static __inline void
vm_page_free_zero(vm_page_t m)572a86ce0cdSMatthew Dillon vm_page_free_zero(vm_page_t m)
573a86ce0cdSMatthew Dillon {
574a86ce0cdSMatthew Dillon #ifdef PMAP_DEBUG
575a86ce0cdSMatthew Dillon #ifdef PHYS_TO_DMAP
576a86ce0cdSMatthew Dillon char *p = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
577a86ce0cdSMatthew Dillon int i;
578a86ce0cdSMatthew Dillon
579a86ce0cdSMatthew Dillon for (i = 0; i < PAGE_SIZE; i++) {
580a86ce0cdSMatthew Dillon if (p[i] != 0) {
581a86ce0cdSMatthew Dillon panic("non-zero page in vm_page_free_zero()");
582a86ce0cdSMatthew Dillon }
583a86ce0cdSMatthew Dillon }
584a86ce0cdSMatthew Dillon #endif
585a86ce0cdSMatthew Dillon #endif
586a86ce0cdSMatthew Dillon vm_page_free_toq(m);
587a86ce0cdSMatthew Dillon }
588a86ce0cdSMatthew Dillon
589a86ce0cdSMatthew Dillon /*
590a86ce0cdSMatthew Dillon * Set page to not be dirty. Note: does not clear pmap modify bits .
591a86ce0cdSMatthew Dillon */
592a86ce0cdSMatthew Dillon static __inline void
vm_page_undirty(vm_page_t m)593a86ce0cdSMatthew Dillon vm_page_undirty(vm_page_t m)
594a86ce0cdSMatthew Dillon {
595a86ce0cdSMatthew Dillon m->dirty = 0;
596a86ce0cdSMatthew Dillon }
597a86ce0cdSMatthew Dillon
59812e4aaffSMatthew Dillon #endif /* _KERNEL */
5991bd40720SMatthew Dillon #endif /* _VM_VM_PAGE2_H_ */
60012e4aaffSMatthew Dillon
601