]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/vm/vm_domain.c
Upgrade to Unbound 1.5.7.
[FreeBSD/FreeBSD.git] / sys / vm / vm_domain.c
1 /*-
2  * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
15  *
16  * NO WARRANTY
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.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_vm.h"
34 #include "opt_ddb.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/lock.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mutex.h>
42 #if MAXMEMDOM > 1
43 #include <sys/proc.h>
44 #endif
45 #include <sys/queue.h>
46 #include <sys/rwlock.h>
47 #include <sys/sbuf.h>
48 #include <sys/sysctl.h>
49 #include <sys/tree.h>
50 #include <sys/vmmeter.h>
51 #include <sys/seq.h>
52
53 #include <ddb/ddb.h>
54
55 #include <vm/vm.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>
61
62 #include <vm/vm_domain.h>
63
64 static __inline int
65 vm_domain_rr_selectdomain(void)
66 {
67 #if MAXMEMDOM > 1
68         struct thread *td;
69
70         td = curthread;
71
72         td->td_dom_rr_idx++;
73         td->td_dom_rr_idx %= vm_ndomains;
74         return (td->td_dom_rr_idx);
75 #else
76         return (0);
77 #endif
78 }
79
80 /*
81  * This implements a very simple set of VM domain memory allocation
82  * policies and iterators.
83  */
84
85 /*
86  * A VM domain policy represents a desired VM domain policy.
87  * Iterators implement searching through VM domains in a specific
88  * order.
89  */
90
91 /*
92  * When setting a policy, the caller must establish their own
93  * exclusive write protection for the contents of the domain
94  * policy.
95  */
96 int
97 vm_domain_policy_init(struct vm_domain_policy *vp)
98 {
99
100         bzero(vp, sizeof(*vp));
101         vp->p.policy = VM_POLICY_NONE;
102         vp->p.domain = -1;
103         return (0);
104 }
105
106 int
107 vm_domain_policy_set(struct vm_domain_policy *vp,
108     vm_domain_policy_type_t vt, int domain)
109 {
110
111         seq_write_begin(&vp->seq);
112         vp->p.policy = vt;
113         vp->p.domain = domain;
114         seq_write_end(&vp->seq);
115         return (0);
116 }
117
118 /*
119  * Take a local copy of a policy.
120  *
121  * The destination policy isn't write-barriered; this is used
122  * for doing local copies into something that isn't shared.
123  */
124 void
125 vm_domain_policy_localcopy(struct vm_domain_policy *dst,
126     const struct vm_domain_policy *src)
127 {
128         seq_t seq;
129
130         for (;;) {
131                 seq = seq_read(&src->seq);
132                 *dst = *src;
133                 if (seq_consistent(&src->seq, seq))
134                         return;
135                 cpu_spinwait();
136         }
137 }
138
139 /*
140  * Take a write-barrier copy of a policy.
141  *
142  * The destination policy is write -barriered; this is used
143  * for doing copies into policies that may be read by other
144  * threads.
145  */
146 void
147 vm_domain_policy_copy(struct vm_domain_policy *dst,
148     const struct vm_domain_policy *src)
149 {
150         seq_t seq;
151         struct vm_domain_policy d;
152
153         for (;;) {
154                 seq = seq_read(&src->seq);
155                 d = *src;
156                 if (seq_consistent(&src->seq, seq)) {
157                         seq_write_begin(&dst->seq);
158                         dst->p.domain = d.p.domain;
159                         dst->p.policy = d.p.policy;
160                         seq_write_end(&dst->seq);
161                         return;
162                 }
163                 cpu_spinwait();
164         }
165 }
166
167 int
168 vm_domain_policy_validate(const struct vm_domain_policy *vp)
169 {
170
171         switch (vp->p.policy) {
172         case VM_POLICY_NONE:
173         case VM_POLICY_ROUND_ROBIN:
174         case VM_POLICY_FIRST_TOUCH:
175         case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
176                 if (vp->p.domain == -1)
177                         return (0);
178                 return (-1);
179         case VM_POLICY_FIXED_DOMAIN:
180         case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
181                 if (vp->p.domain >= 0 && vp->p.domain < vm_ndomains)
182                         return (0);
183                 return (-1);
184         default:
185                 return (-1);
186         }
187         return (-1);
188 }
189
190 int
191 vm_domain_policy_cleanup(struct vm_domain_policy *vp)
192 {
193
194         /* For now, empty */
195         return (0);
196 }
197
198 int
199 vm_domain_iterator_init(struct vm_domain_iterator *vi)
200 {
201
202         /* Nothing to do for now */
203         return (0);
204 }
205
206 /*
207  * Manually setup an iterator with the given details.
208  */
209 int
210 vm_domain_iterator_set(struct vm_domain_iterator *vi,
211     vm_domain_policy_type_t vt, int domain)
212 {
213
214         switch (vt) {
215         case VM_POLICY_FIXED_DOMAIN:
216                 vi->policy = VM_POLICY_FIXED_DOMAIN;
217                 vi->domain = domain;
218                 vi->n = 1;
219                 break;
220         case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
221                 vi->policy = VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN;
222                 vi->domain = domain;
223                 vi->n = vm_ndomains;
224                 break;
225         case VM_POLICY_FIRST_TOUCH:
226                 vi->policy = VM_POLICY_FIRST_TOUCH;
227                 vi->domain = PCPU_GET(domain);
228                 vi->n = 1;
229                 break;
230         case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
231                 vi->policy = VM_POLICY_FIRST_TOUCH_ROUND_ROBIN;
232                 vi->domain = PCPU_GET(domain);
233                 vi->n = vm_ndomains;
234                 break;
235         case VM_POLICY_ROUND_ROBIN:
236         default:
237                 vi->policy = VM_POLICY_ROUND_ROBIN;
238                 vi->domain = -1;
239                 vi->n = vm_ndomains;
240                 break;
241         }
242         return (0);
243 }
244
245 /*
246  * Setup an iterator based on the given policy.
247  */
248 static inline void
249 _vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
250     const struct vm_domain_policy *vt)
251 {
252         /*
253          * Initialise the iterator.
254          *
255          * For first-touch, the initial domain is set
256          * via the current thread CPU domain.
257          *
258          * For fixed-domain, it's assumed that the
259          * caller has initialised the specific domain
260          * it is after.
261          */
262         switch (vt->p.policy) {
263         case VM_POLICY_FIXED_DOMAIN:
264                 vi->policy = vt->p.policy;
265                 vi->domain = vt->p.domain;
266                 vi->n = 1;
267                 break;
268         case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
269                 vi->policy = vt->p.policy;
270                 vi->domain = vt->p.domain;
271                 vi->n = vm_ndomains;
272                 break;
273         case VM_POLICY_FIRST_TOUCH:
274                 vi->policy = vt->p.policy;
275                 vi->domain = PCPU_GET(domain);
276                 vi->n = 1;
277                 break;
278         case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
279                 vi->policy = vt->p.policy;
280                 vi->domain = PCPU_GET(domain);
281                 vi->n = vm_ndomains;
282                 break;
283         case VM_POLICY_ROUND_ROBIN:
284         default:
285                 /*
286                  * Default to round-robin policy.
287                  */
288                 vi->policy = VM_POLICY_ROUND_ROBIN;
289                 vi->domain = -1;
290                 vi->n = vm_ndomains;
291                 break;
292         }
293 }
294
295 void
296 vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
297     const struct vm_domain_policy *vt)
298 {
299         seq_t seq;
300         struct vm_domain_policy vt_lcl;
301
302         for (;;) {
303                 seq = seq_read(&vt->seq);
304                 vt_lcl = *vt;
305                 if (seq_consistent(&vt->seq, seq)) {
306                         _vm_domain_iterator_set_policy(vi, &vt_lcl);
307                         return;
308                 }
309                 cpu_spinwait();
310         }
311 }
312
313 /*
314  * Return the next VM domain to use.
315  *
316  * Returns 0 w/ domain set to the next domain to use, or
317  * -1 to indicate no more domains are available.
318  */
319 int
320 vm_domain_iterator_run(struct vm_domain_iterator *vi, int *domain)
321 {
322
323         /* General catch-all */
324         if (vi->n <= 0)
325                 return (-1);
326
327         switch (vi->policy) {
328         case VM_POLICY_FIXED_DOMAIN:
329         case VM_POLICY_FIRST_TOUCH:
330                 *domain = vi->domain;
331                 vi->n--;
332                 break;
333         case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
334         case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
335                 /*
336                  * XXX TODO: skip over the rr'ed domain
337                  * if it equals the one we started with.
338                  */
339                 if (vi->n == vm_ndomains)
340                         *domain = vi->domain;
341                 else
342                         *domain = vm_domain_rr_selectdomain();
343                 vi->n--;
344                 break;
345         case VM_POLICY_ROUND_ROBIN:
346         default:
347                 *domain = vm_domain_rr_selectdomain();
348                 vi->n--;
349                 break;
350         }
351
352         return (0);
353 }
354
355 /*
356  * Returns 1 if the iteration is done, or 0 if it has not.
357
358  * This can only be called after at least one loop through
359  * the iterator.  Ie, it's designed to be used as a tail
360  * check of a loop, not the head check of a loop.
361  */
362 int
363 vm_domain_iterator_isdone(struct vm_domain_iterator *vi)
364 {
365
366         return (vi->n <= 0);
367 }
368
369 int
370 vm_domain_iterator_cleanup(struct vm_domain_iterator *vi)
371 {
372
373         return (0);
374 }