2 * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mutex.h>
45 #include <sys/queue.h>
46 #include <sys/rwlock.h>
48 #include <sys/sysctl.h>
50 #include <sys/vmmeter.h>
56 #include <vm/vm_param.h>
57 #include <vm/vm_kern.h>
58 #include <vm/vm_object.h>
59 #include <vm/vm_page.h>
60 #include <vm/vm_phys.h>
62 #include <vm/vm_domain.h>
65 vm_domain_rr_selectdomain(int skip_domain)
73 td->td_dom_rr_idx %= vm_ndomains;
76 * If skip_domain is provided then skip over that
77 * domain. This is intended for round robin variants
78 * which first try a fixed domain.
80 if ((skip_domain > -1) && (td->td_dom_rr_idx == skip_domain)) {
82 td->td_dom_rr_idx %= vm_ndomains;
84 return (td->td_dom_rr_idx);
91 * This implements a very simple set of VM domain memory allocation
92 * policies and iterators.
96 * A VM domain policy represents a desired VM domain policy.
97 * Iterators implement searching through VM domains in a specific
102 * When setting a policy, the caller must establish their own
103 * exclusive write protection for the contents of the domain
107 vm_domain_policy_init(struct vm_domain_policy *vp)
110 bzero(vp, sizeof(*vp));
111 vp->p.policy = VM_POLICY_NONE;
117 vm_domain_policy_set(struct vm_domain_policy *vp,
118 vm_domain_policy_type_t vt, int domain)
121 seq_write_begin(&vp->seq);
123 vp->p.domain = domain;
124 seq_write_end(&vp->seq);
129 * Take a local copy of a policy.
131 * The destination policy isn't write-barriered; this is used
132 * for doing local copies into something that isn't shared.
135 vm_domain_policy_localcopy(struct vm_domain_policy *dst,
136 const struct vm_domain_policy *src)
141 seq = seq_read(&src->seq);
143 if (seq_consistent(&src->seq, seq))
150 * Take a write-barrier copy of a policy.
152 * The destination policy is write -barriered; this is used
153 * for doing copies into policies that may be read by other
157 vm_domain_policy_copy(struct vm_domain_policy *dst,
158 const struct vm_domain_policy *src)
161 struct vm_domain_policy d;
164 seq = seq_read(&src->seq);
166 if (seq_consistent(&src->seq, seq)) {
167 seq_write_begin(&dst->seq);
168 dst->p.domain = d.p.domain;
169 dst->p.policy = d.p.policy;
170 seq_write_end(&dst->seq);
178 vm_domain_policy_validate(const struct vm_domain_policy *vp)
181 switch (vp->p.policy) {
183 case VM_POLICY_ROUND_ROBIN:
184 case VM_POLICY_FIRST_TOUCH:
185 case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
186 if (vp->p.domain == -1)
189 case VM_POLICY_FIXED_DOMAIN:
190 case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
192 if (vp->p.domain >= 0 && vp->p.domain < vm_ndomains)
195 if (vp->p.domain == 0)
206 vm_domain_policy_cleanup(struct vm_domain_policy *vp)
214 vm_domain_iterator_init(struct vm_domain_iterator *vi)
217 /* Nothing to do for now */
222 * Manually setup an iterator with the given details.
225 vm_domain_iterator_set(struct vm_domain_iterator *vi,
226 vm_domain_policy_type_t vt, int domain)
231 case VM_POLICY_FIXED_DOMAIN:
232 vi->policy = VM_POLICY_FIXED_DOMAIN;
236 case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
237 vi->policy = VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN;
241 case VM_POLICY_FIRST_TOUCH:
242 vi->policy = VM_POLICY_FIRST_TOUCH;
243 vi->domain = PCPU_GET(domain);
246 case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
247 vi->policy = VM_POLICY_FIRST_TOUCH_ROUND_ROBIN;
248 vi->domain = PCPU_GET(domain);
251 case VM_POLICY_ROUND_ROBIN:
253 vi->policy = VM_POLICY_ROUND_ROBIN;
266 * Setup an iterator based on the given policy.
269 _vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
270 const struct vm_domain_policy *vt)
275 * Initialise the iterator.
277 * For first-touch, the initial domain is set
278 * via the current thread CPU domain.
280 * For fixed-domain, it's assumed that the
281 * caller has initialised the specific domain
284 switch (vt->p.policy) {
285 case VM_POLICY_FIXED_DOMAIN:
286 vi->policy = vt->p.policy;
287 vi->domain = vt->p.domain;
290 case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
291 vi->policy = vt->p.policy;
292 vi->domain = vt->p.domain;
295 case VM_POLICY_FIRST_TOUCH:
296 vi->policy = vt->p.policy;
297 vi->domain = PCPU_GET(domain);
300 case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
301 vi->policy = vt->p.policy;
302 vi->domain = PCPU_GET(domain);
305 case VM_POLICY_ROUND_ROBIN:
308 * Default to round-robin policy.
310 vi->policy = VM_POLICY_ROUND_ROBIN;
322 vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
323 const struct vm_domain_policy *vt)
326 struct vm_domain_policy vt_lcl;
329 seq = seq_read(&vt->seq);
331 if (seq_consistent(&vt->seq, seq)) {
332 _vm_domain_iterator_set_policy(vi, &vt_lcl);
340 * Return the next VM domain to use.
342 * Returns 0 w/ domain set to the next domain to use, or
343 * -1 to indicate no more domains are available.
346 vm_domain_iterator_run(struct vm_domain_iterator *vi, int *domain)
349 /* General catch-all */
354 switch (vi->policy) {
355 case VM_POLICY_FIXED_DOMAIN:
356 case VM_POLICY_FIRST_TOUCH:
357 *domain = vi->domain;
360 case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
361 case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
363 * XXX TODO: skip over the rr'ed domain
364 * if it equals the one we started with.
366 if (vi->n == vm_ndomains)
367 *domain = vi->domain;
369 *domain = vm_domain_rr_selectdomain(vi->domain);
372 case VM_POLICY_ROUND_ROBIN:
374 *domain = vm_domain_rr_selectdomain(-1);
387 * Returns 1 if the iteration is done, or 0 if it has not.
389 * This can only be called after at least one loop through
390 * the iterator. Ie, it's designed to be used as a tail
391 * check of a loop, not the head check of a loop.
394 vm_domain_iterator_isdone(struct vm_domain_iterator *vi)
401 vm_domain_iterator_cleanup(struct vm_domain_iterator *vi)