Annotation of sys/uvm/uvm_pglist.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uvm_pglist.c,v 1.20 2007/04/13 18:57:49 art Exp $ */
2: /* $NetBSD: uvm_pglist.c,v 1.13 2001/02/18 21:19:08 chs Exp $ */
3:
4: /*-
5: * Copyright (c) 1997 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * uvm_pglist.c: pglist functions
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/malloc.h>
48: #include <sys/proc.h>
49:
50: #include <uvm/uvm.h>
51:
52: #ifdef VM_PAGE_ALLOC_MEMORY_STATS
53: #define STAT_INCR(v) (v)++
54: #define STAT_DECR(v) do { \
55: if ((v) == 0) \
56: printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
57: else \
58: (v)--; \
59: } while (0)
60: u_long uvm_pglistalloc_npages;
61: #else
62: #define STAT_INCR(v)
63: #define STAT_DECR(v)
64: #endif
65:
66: int uvm_pglistalloc_simple(psize_t, paddr_t, paddr_t, struct pglist *);
67:
68: int
69: uvm_pglistalloc_simple(psize_t size, paddr_t low, paddr_t high,
70: struct pglist *rlist)
71: {
72: psize_t try;
73: int psi;
74: struct vm_page *pg;
75: int s, todo, idx, pgflidx, error, free_list;
76: UVMHIST_FUNC("uvm_pglistalloc_simple"); UVMHIST_CALLED(pghist);
77: #ifdef DEBUG
78: vm_page_t tp;
79: #endif
80:
81: /* Default to "lose". */
82: error = ENOMEM;
83:
84: todo = size / PAGE_SIZE;
85:
86: /*
87: * Block all memory allocation and lock the free list.
88: */
89: s = uvm_lock_fpageq();
90:
91: /* Are there even any free pages? */
92: if (uvmexp.free <= (uvmexp.reserve_pagedaemon + uvmexp.reserve_kernel))
93: goto out;
94:
95: for (try = low; try < high; try += PAGE_SIZE) {
96:
97: /*
98: * Make sure this is a managed physical page.
99: */
100:
101: if ((psi = vm_physseg_find(atop(try), &idx)) == -1)
102: continue; /* managed? */
103: pg = &vm_physmem[psi].pgs[idx];
104: if (VM_PAGE_IS_FREE(pg) == 0)
105: continue;
106:
107: free_list = uvm_page_lookup_freelist(pg);
108: pgflidx = (pg->pg_flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN;
109: #ifdef DEBUG
110: for (tp = TAILQ_FIRST(&uvm.page_free[free_list].pgfl_queues[pgflidx]);
111: tp != NULL;
112: tp = TAILQ_NEXT(tp, pageq)) {
113: if (tp == pg)
114: break;
115: }
116: if (tp == NULL)
117: panic("uvm_pglistalloc_simple: page not on freelist");
118: #endif
119: TAILQ_REMOVE(&uvm.page_free[free_list].pgfl_queues[pgflidx], pg, pageq);
120: uvmexp.free--;
121: if (pg->pg_flags & PG_ZERO)
122: uvmexp.zeropages--;
123: pg->pg_flags = PG_CLEAN;
124: pg->uobject = NULL;
125: pg->uanon = NULL;
126: pg->pg_version++;
127: TAILQ_INSERT_TAIL(rlist, pg, pageq);
128: STAT_INCR(uvm_pglistalloc_npages);
129: if (--todo == 0) {
130: error = 0;
131: goto out;
132: }
133: }
134:
135: out:
136: /*
137: * check to see if we need to generate some free pages waking
138: * the pagedaemon.
139: */
140:
141: if (!error && (uvmexp.free + uvmexp.paging < uvmexp.freemin ||
142: (uvmexp.free + uvmexp.paging < uvmexp.freetarg &&
143: uvmexp.inactive < uvmexp.inactarg))) {
144: wakeup(&uvm.pagedaemon);
145: }
146:
147: uvm_unlock_fpageq(s);
148:
149: if (error)
150: uvm_pglistfree(rlist);
151:
152: return (error);
153: }
154:
155: /*
156: * uvm_pglistalloc: allocate a list of pages
157: *
158: * => allocated pages are placed at the tail of rlist. rlist is
159: * assumed to be properly initialized by caller.
160: * => returns 0 on success or errno on failure
161: * => XXX: implementation allocates only a single segment, also
162: * might be able to better advantage of vm_physeg[].
163: * => doesn't take into account clean non-busy pages on inactive list
164: * that could be used(?)
165: * => params:
166: * size the size of the allocation, rounded to page size.
167: * low the low address of the allowed allocation range.
168: * high the high address of the allowed allocation range.
169: * alignment memory must be aligned to this power-of-two boundary.
170: * boundary no segment in the allocation may cross this
171: * power-of-two boundary (relative to zero).
172: */
173:
174: int
175: uvm_pglistalloc(size, low, high, alignment, boundary, rlist, nsegs, waitok)
176: psize_t size;
177: paddr_t low, high, alignment, boundary;
178: struct pglist *rlist;
179: int nsegs, waitok;
180: {
181: paddr_t try, idxpa, lastidxpa;
182: int psi;
183: struct vm_page *pgs;
184: int s, tryidx, idx, pgflidx, end, error, free_list;
185: vm_page_t m;
186: u_long pagemask;
187: #ifdef DEBUG
188: vm_page_t tp;
189: #endif
190: UVMHIST_FUNC("uvm_pglistalloc"); UVMHIST_CALLED(pghist);
191:
192: KASSERT((alignment & (alignment - 1)) == 0);
193: KASSERT((boundary & (boundary - 1)) == 0);
194:
195: /*
196: * Our allocations are always page granularity, so our alignment
197: * must be, too.
198: */
199: if (alignment < PAGE_SIZE)
200: alignment = PAGE_SIZE;
201:
202: if (size == 0)
203: return (EINVAL);
204:
205: size = round_page(size);
206: try = roundup(low, alignment);
207:
208: if ((nsegs >= size / PAGE_SIZE) && (alignment == PAGE_SIZE) &&
209: (boundary == 0))
210: return (uvm_pglistalloc_simple(size, try, high, rlist));
211:
212: if (boundary != 0 && boundary < size)
213: return (EINVAL);
214:
215: pagemask = ~(boundary - 1);
216:
217: /* Default to "lose". */
218: error = ENOMEM;
219:
220: /*
221: * Block all memory allocation and lock the free list.
222: */
223: s = uvm_lock_fpageq();
224:
225: /* Are there even any free pages? */
226: if (uvmexp.free <= (uvmexp.reserve_pagedaemon + uvmexp.reserve_kernel))
227: goto out;
228:
229: for (;; try += alignment) {
230: if (try + size > high) {
231:
232: /*
233: * We've run past the allowable range.
234: */
235:
236: goto out;
237: }
238:
239: /*
240: * Make sure this is a managed physical page.
241: */
242:
243: if ((psi = vm_physseg_find(atop(try), &idx)) == -1)
244: continue; /* managed? */
245: if (vm_physseg_find(atop(try + size), NULL) != psi)
246: continue; /* end must be in this segment */
247:
248: tryidx = idx;
249: end = idx + (size / PAGE_SIZE);
250: pgs = vm_physmem[psi].pgs;
251:
252: /*
253: * Found a suitable starting page. See of the range is free.
254: */
255:
256: for (; idx < end; idx++) {
257: if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) {
258: break;
259: }
260: idxpa = VM_PAGE_TO_PHYS(&pgs[idx]);
261: if (idx > tryidx) {
262: lastidxpa = VM_PAGE_TO_PHYS(&pgs[idx - 1]);
263: if ((lastidxpa + PAGE_SIZE) != idxpa) {
264:
265: /*
266: * Region not contiguous.
267: */
268:
269: break;
270: }
271: if (boundary != 0 &&
272: ((lastidxpa ^ idxpa) & pagemask) != 0) {
273:
274: /*
275: * Region crosses boundary.
276: */
277:
278: break;
279: }
280: }
281: }
282: if (idx == end) {
283: break;
284: }
285: }
286:
287: #if PGFL_NQUEUES != 2
288: #error uvm_pglistalloc needs to be updated
289: #endif
290:
291: /*
292: * we have a chunk of memory that conforms to the requested constraints.
293: */
294: idx = tryidx;
295: while (idx < end) {
296: m = &pgs[idx];
297: free_list = uvm_page_lookup_freelist(m);
298: pgflidx = (m->pg_flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN;
299: #ifdef DEBUG
300: for (tp = TAILQ_FIRST(&uvm.page_free[
301: free_list].pgfl_queues[pgflidx]);
302: tp != NULL;
303: tp = TAILQ_NEXT(tp, pageq)) {
304: if (tp == m)
305: break;
306: }
307: if (tp == NULL)
308: panic("uvm_pglistalloc: page not on freelist");
309: #endif
310: TAILQ_REMOVE(&uvm.page_free[free_list].pgfl_queues[pgflidx],
311: m, pageq);
312: uvmexp.free--;
313: if (m->pg_flags & PG_ZERO)
314: uvmexp.zeropages--;
315: m->pg_flags = PG_CLEAN;
316: m->uobject = NULL;
317: m->uanon = NULL;
318: m->pg_version++;
319: TAILQ_INSERT_TAIL(rlist, m, pageq);
320: idx++;
321: STAT_INCR(uvm_pglistalloc_npages);
322: }
323: error = 0;
324:
325: out:
326: /*
327: * check to see if we need to generate some free pages waking
328: * the pagedaemon.
329: */
330:
331: if (uvmexp.free + uvmexp.paging < uvmexp.freemin ||
332: (uvmexp.free + uvmexp.paging < uvmexp.freetarg &&
333: uvmexp.inactive < uvmexp.inactarg)) {
334: wakeup(&uvm.pagedaemon);
335: }
336:
337: uvm_unlock_fpageq(s);
338:
339: return (error);
340: }
341:
342: /*
343: * uvm_pglistfree: free a list of pages
344: *
345: * => pages should already be unmapped
346: */
347:
348: void
349: uvm_pglistfree(struct pglist *list)
350: {
351: struct vm_page *m;
352: int s;
353: UVMHIST_FUNC("uvm_pglistfree"); UVMHIST_CALLED(pghist);
354:
355: /*
356: * Block all memory allocation and lock the free list.
357: */
358: s = uvm_lock_fpageq();
359:
360: while ((m = TAILQ_FIRST(list)) != NULL) {
361: KASSERT((m->pg_flags & (PQ_ACTIVE|PQ_INACTIVE)) == 0);
362: TAILQ_REMOVE(list, m, pageq);
363: #ifdef DEBUG
364: if (m->uobject == (void *)0xdeadbeef &&
365: m->uanon == (void *)0xdeadbeef) {
366: panic("uvm_pagefree: freeing free page %p", m);
367: }
368:
369: m->uobject = (void *)0xdeadbeef;
370: m->offset = 0xdeadbeef;
371: m->uanon = (void *)0xdeadbeef;
372: #endif
373: atomic_clearbits_int(&m->pg_flags, PQ_MASK);
374: atomic_setbits_int(&m->pg_flags, PQ_FREE);
375: TAILQ_INSERT_TAIL(&uvm.page_free[
376: uvm_page_lookup_freelist(m)].pgfl_queues[PGFL_UNKNOWN],
377: m, pageq);
378: uvmexp.free++;
379: if (uvmexp.zeropages < UVM_PAGEZERO_TARGET)
380: uvm.page_idle_zero = vm_page_zero_enable;
381: STAT_DECR(uvm_pglistalloc_npages);
382: }
383:
384: uvm_unlock_fpageq(s);
385: }
CVSweb