FreeBSD/Linux Kernel Cross Reference
sys/uvm/uvm_amap.c
1 /* $NetBSD: uvm_amap.c,v 1.53.2.2 2006/01/27 22:21:01 tron Exp $ */
2
3 /*
4 *
5 * Copyright (c) 1997 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * uvm_amap.c: amap operations
37 */
38
39 /*
40 * this file contains functions that perform operations on amaps. see
41 * uvm_amap.h for a brief explanation of the role of amaps in uvm.
42 */
43
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.53.2.2 2006/01/27 22:21:01 tron Exp $");
46
47 #undef UVM_AMAP_INLINE /* enable/disable amap inlines */
48
49 #include "opt_uvmhist.h"
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/proc.h>
54 #include <sys/malloc.h>
55 #include <sys/kernel.h>
56 #include <sys/pool.h>
57
58 #define UVM_AMAP_C /* ensure disabled inlines are in */
59 #include <uvm/uvm.h>
60 #include <uvm/uvm_swap.h>
61
62 /*
63 * pool for allocation of vm_map structures. note that the pool has
64 * its own simplelock for its protection. also note that in order to
65 * avoid an endless loop, the amap pool's allocator cannot allocate
66 * memory from an amap (it currently goes through the kernel uobj, so
67 * we are ok).
68 */
69
70 struct pool uvm_amap_pool;
71
72 MALLOC_DEFINE(M_UVMAMAP, "UVM amap", "UVM amap and related structures");
73
74 /*
75 * local functions
76 */
77
78 static struct vm_amap *amap_alloc1(int, int, int);
79
80 #ifdef UVM_AMAP_PPREF
81 /*
82 * what is ppref? ppref is an _optional_ amap feature which is used
83 * to keep track of reference counts on a per-page basis. it is enabled
84 * when UVM_AMAP_PPREF is defined.
85 *
86 * when enabled, an array of ints is allocated for the pprefs. this
87 * array is allocated only when a partial reference is added to the
88 * map (either by unmapping part of the amap, or gaining a reference
89 * to only a part of an amap). if the malloc of the array fails
90 * (M_NOWAIT), then we set the array pointer to PPREF_NONE to indicate
91 * that we tried to do ppref's but couldn't alloc the array so just
92 * give up (after all, this is an optional feature!).
93 *
94 * the array is divided into page sized "chunks." for chunks of length 1,
95 * the chunk reference count plus one is stored in that chunk's slot.
96 * for chunks of length > 1 the first slot contains (the reference count
97 * plus one) * -1. [the negative value indicates that the length is
98 * greater than one.] the second slot of the chunk contains the length
99 * of the chunk. here is an example:
100 *
101 * actual REFS: 2 2 2 2 3 1 1 0 0 0 4 4 0 1 1 1
102 * ppref: -3 4 x x 4 -2 2 -1 3 x -5 2 1 -2 3 x
103 * <----------><-><----><-------><----><-><------->
104 * (x = don't care)
105 *
106 * this allows us to allow one int to contain the ref count for the whole
107 * chunk. note that the "plus one" part is needed because a reference
108 * count of zero is neither positive or negative (need a way to tell
109 * if we've got one zero or a bunch of them).
110 *
111 * here are some in-line functions to help us.
112 */
113
114 static __inline void pp_getreflen(int *, int, int *, int *);
115 static __inline void pp_setreflen(int *, int, int, int);
116
117 /*
118 * pp_getreflen: get the reference and length for a specific offset
119 *
120 * => ppref's amap must be locked
121 */
122 static __inline void
123 pp_getreflen(ppref, offset, refp, lenp)
124 int *ppref, offset, *refp, *lenp;
125 {
126
127 if (ppref[offset] > 0) { /* chunk size must be 1 */
128 *refp = ppref[offset] - 1; /* don't forget to adjust */
129 *lenp = 1;
130 } else {
131 *refp = (ppref[offset] * -1) - 1;
132 *lenp = ppref[offset+1];
133 }
134 }
135
136 /*
137 * pp_setreflen: set the reference and length for a specific offset
138 *
139 * => ppref's amap must be locked
140 */
141 static __inline void
142 pp_setreflen(ppref, offset, ref, len)
143 int *ppref, offset, ref, len;
144 {
145 if (len == 0)
146 return;
147 if (len == 1) {
148 ppref[offset] = ref + 1;
149 } else {
150 ppref[offset] = (ref + 1) * -1;
151 ppref[offset+1] = len;
152 }
153 }
154 #endif
155
156 /*
157 * amap_init: called at boot time to init global amap data structures
158 */
159
160 void
161 amap_init(void)
162 {
163
164 /*
165 * Initialize the vm_amap pool.
166 */
167
168 pool_init(&uvm_amap_pool, sizeof(struct vm_amap), 0, 0, 0,
169 "amappl", &pool_allocator_nointr);
170 }
171
172 /*
173 * amap_alloc1: internal function that allocates an amap, but does not
174 * init the overlay.
175 *
176 * => lock on returned amap is init'd
177 */
178 static inline struct vm_amap *
179 amap_alloc1(slots, padslots, waitf)
180 int slots, padslots, waitf;
181 {
182 struct vm_amap *amap;
183 int totalslots;
184
185 amap = pool_get(&uvm_amap_pool, (waitf == M_WAITOK) ? PR_WAITOK : 0);
186 if (amap == NULL)
187 return(NULL);
188
189 totalslots = malloc_roundup((slots + padslots) * sizeof(int)) /
190 sizeof(int);
191 simple_lock_init(&amap->am_l);
192 amap->am_ref = 1;
193 amap->am_flags = 0;
194 #ifdef UVM_AMAP_PPREF
195 amap->am_ppref = NULL;
196 #endif
197 amap->am_maxslot = totalslots;
198 amap->am_nslot = slots;
199 amap->am_nused = 0;
200
201 amap->am_slots = malloc(totalslots * sizeof(int), M_UVMAMAP,
202 waitf);
203 if (amap->am_slots == NULL)
204 goto fail1;
205
206 amap->am_bckptr = malloc(totalslots * sizeof(int), M_UVMAMAP, waitf);
207 if (amap->am_bckptr == NULL)
208 goto fail2;
209
210 amap->am_anon = malloc(totalslots * sizeof(struct vm_anon *),
211 M_UVMAMAP, waitf);
212 if (amap->am_anon == NULL)
213 goto fail3;
214
215 return(amap);
216
217 fail3:
218 free(amap->am_bckptr, M_UVMAMAP);
219 fail2:
220 free(amap->am_slots, M_UVMAMAP);
221 fail1:
222 pool_put(&uvm_amap_pool, amap);
223
224 /*
225 * XXX hack to tell the pagedaemon how many pages we need,
226 * since we can need more than it would normally free.
227 */
228 if (waitf == M_NOWAIT) {
229 extern int uvm_extrapages;
230 uvm_extrapages += ((sizeof(int) * 2 +
231 sizeof(struct vm_anon *)) *
232 totalslots) >> PAGE_SHIFT;
233 }
234 return (NULL);
235 }
236
237 /*
238 * amap_alloc: allocate an amap to manage "sz" bytes of anonymous VM
239 *
240 * => caller should ensure sz is a multiple of PAGE_SIZE
241 * => reference count to new amap is set to one
242 * => new amap is returned unlocked
243 */
244
245 struct vm_amap *
246 amap_alloc(sz, padsz, waitf)
247 vaddr_t sz, padsz;
248 int waitf;
249 {
250 struct vm_amap *amap;
251 int slots, padslots;
252 UVMHIST_FUNC("amap_alloc"); UVMHIST_CALLED(maphist);
253
254 AMAP_B2SLOT(slots, sz);
255 AMAP_B2SLOT(padslots, padsz);
256
257 amap = amap_alloc1(slots, padslots, waitf);
258 if (amap)
259 memset(amap->am_anon, 0,
260 amap->am_maxslot * sizeof(struct vm_anon *));
261
262 UVMHIST_LOG(maphist,"<- done, amap = 0x%x, sz=%d", amap, sz, 0, 0);
263 return(amap);
264 }
265
266
267 /*
268 * amap_free: free an amap
269 *
270 * => the amap must be unlocked
271 * => the amap should have a zero reference count and be empty
272 */
273 void
274 amap_free(amap)
275 struct vm_amap *amap;
276 {
277 UVMHIST_FUNC("amap_free"); UVMHIST_CALLED(maphist);
278
279 KASSERT(amap->am_ref == 0 && amap->am_nused == 0);
280 LOCK_ASSERT(!simple_lock_held(&amap->am_l));
281 free(amap->am_slots, M_UVMAMAP);
282 free(amap->am_bckptr, M_UVMAMAP);
283 free(amap->am_anon, M_UVMAMAP);
284 #ifdef UVM_AMAP_PPREF
285 if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
286 free(amap->am_ppref, M_UVMAMAP);
287 #endif
288 pool_put(&uvm_amap_pool, amap);
289 UVMHIST_LOG(maphist,"<- done, freed amap = 0x%x", amap, 0, 0, 0);
290 }
291
292 /*
293 * amap_extend: extend the size of an amap (if needed)
294 *
295 * => called from uvm_map when we want to extend an amap to cover
296 * a new mapping (rather than allocate a new one)
297 * => amap should be unlocked (we will lock it)
298 * => to safely extend an amap it should have a reference count of
299 * one (thus it can't be shared)
300 */
301 int
302 amap_extend(entry, addsize, flags)
303 struct vm_map_entry *entry;
304 vsize_t addsize;
305 int flags;
306 {
307 struct vm_amap *amap = entry->aref.ar_amap;
308 int slotoff = entry->aref.ar_pageoff;
309 int slotmapped, slotadd, slotneed, slotadded, slotalloc;
310 int slotadj, slotspace;
311 #ifdef UVM_AMAP_PPREF
312 int *newppref, *oldppref;
313 #endif
314 int i, *newsl, *newbck, *oldsl, *oldbck;
315 struct vm_anon **newover, **oldover;
316 int mflag = (flags & AMAP_EXTEND_NOWAIT) ? M_NOWAIT :
317 (M_WAITOK | M_CANFAIL);
318
319 UVMHIST_FUNC("amap_extend"); UVMHIST_CALLED(maphist);
320
321 UVMHIST_LOG(maphist, " (entry=0x%x, addsize=0x%x, flags=0x%x)",
322 entry, addsize, flags, 0);
323
324 /*
325 * first, determine how many slots we need in the amap. don't
326 * forget that ar_pageoff could be non-zero: this means that
327 * there are some unused slots before us in the amap.
328 */
329
330 amap_lock(amap);
331 AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */
332 AMAP_B2SLOT(slotadd, addsize); /* slots to add */
333 if (flags & AMAP_EXTEND_FORWARDS) {
334 slotneed = slotoff + slotmapped + slotadd;
335 slotadj = 0;
336 slotspace = 0;
337 }
338 else {
339 slotneed = slotadd + slotmapped;
340 slotadj = slotadd - slotoff;
341 slotspace = amap->am_maxslot - slotmapped;
342 }
343
344 /*
345 * case 1: we already have enough slots in the map and thus
346 * only need to bump the reference counts on the slots we are
347 * adding.
348 */
349
350 if (flags & AMAP_EXTEND_FORWARDS) {
351 if (amap->am_nslot >= slotneed) {
352 #ifdef UVM_AMAP_PPREF
353 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
354 amap_pp_adjref(amap, slotoff + slotmapped,
355 slotadd, 1);
356 }
357 #endif
358 amap_unlock(amap);
359 UVMHIST_LOG(maphist,
360 "<- done (case 1f), amap = 0x%x, sltneed=%d",
361 amap, slotneed, 0, 0);
362 return 0;
363 }
364 } else {
365 if (slotadj <= 0) {
366 slotoff -= slotadd;
367 entry->aref.ar_pageoff = slotoff;
368 #ifdef UVM_AMAP_PPREF
369 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
370 amap_pp_adjref(amap, slotoff, slotadd, 1);
371 }
372 #endif
373 amap_unlock(amap);
374 UVMHIST_LOG(maphist,
375 "<- done (case 1b), amap = 0x%x, sltneed=%d",
376 amap, slotneed, 0, 0);
377 return 0;
378 }
379 }
380
381 /*
382 * case 2: we pre-allocated slots for use and we just need to
383 * bump nslot up to take account for these slots.
384 */
385
386 if (amap->am_maxslot >= slotneed) {
387 if (flags & AMAP_EXTEND_FORWARDS) {
388 #ifdef UVM_AMAP_PPREF
389 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
390 if ((slotoff + slotmapped) < amap->am_nslot)
391 amap_pp_adjref(amap,
392 slotoff + slotmapped,
393 (amap->am_nslot -
394 (slotoff + slotmapped)), 1);
395 pp_setreflen(amap->am_ppref, amap->am_nslot, 1,
396 slotneed - amap->am_nslot);
397 }
398 #endif
399 amap->am_nslot = slotneed;
400 amap_unlock(amap);
401
402 /*
403 * no need to zero am_anon since that was done at
404 * alloc time and we never shrink an allocation.
405 */
406
407 UVMHIST_LOG(maphist,"<- done (case 2f), amap = 0x%x, "
408 "slotneed=%d", amap, slotneed, 0, 0);
409 return 0;
410 } else {
411 #ifdef UVM_AMAP_PPREF
412 if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
413 /*
414 * Slide up the ref counts on the pages that
415 * are actually in use.
416 */
417 memmove(amap->am_ppref + slotspace,
418 amap->am_ppref + slotoff,
419 slotmapped * sizeof(int));
420 /*
421 * Mark the (adjusted) gap at the front as
422 * referenced/not referenced.
423 */
424 pp_setreflen(amap->am_ppref,
425 0, 0, slotspace - slotadd);
426 pp_setreflen(amap->am_ppref,
427 slotspace - slotadd, 1, slotadd);
428 }
429 #endif
430
431 /*
432 * Slide the anon pointers up and clear out
433 * the space we just made.
434 */
435 memmove(amap->am_anon + slotspace,
436 amap->am_anon + slotoff,
437 slotmapped * sizeof(struct vm_anon*));
438 memset(amap->am_anon + slotoff, 0,
439 (slotspace - slotoff) * sizeof(struct vm_anon *));
440
441 /*
442 * Slide the backpointers up, but don't bother
443 * wiping out the old slots.
444 */
445 memmove(amap->am_bckptr + slotspace,
446 amap->am_bckptr + slotoff,
447 slotmapped * sizeof(int));
448
449 /*
450 * Adjust all the useful active slot numbers.
451 */
452 for (i = 0; i < amap->am_nused; i++)
453 amap->am_slots[i] += (slotspace - slotoff);
454
455 /*
456 * We just filled all the empty space in the
457 * front of the amap by activating a few new
458 * slots.
459 */
460 amap->am_nslot = amap->am_maxslot;
461 entry->aref.ar_pageoff = slotspace - slotadd;
462 amap_unlock(amap);
463
464 UVMHIST_LOG(maphist,"<- done (case 2b), amap = 0x%x, "
465 "slotneed=%d", amap, slotneed, 0, 0);
466 return 0;
467 }
468 }
469
470 /*
471 * case 3: we need to malloc a new amap and copy all the amap
472 * data over from old amap to the new one.
473 *
474 * note that the use of a kernel realloc() probably would not
475 * help here, since we wish to abort cleanly if one of the
476 * three (or four) mallocs fails.
477 */
478
479 amap_unlock(amap); /* unlock in case we sleep in malloc */
480 slotalloc = malloc_roundup(slotneed * sizeof(int)) / sizeof(int);
481 #ifdef UVM_AMAP_PPREF
482 newppref = NULL;
483 if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
484 newppref = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
485 #endif
486 newsl = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
487 newbck = malloc(slotalloc * sizeof(int), M_UVMAMAP, mflag);
488 newover = malloc(slotalloc * sizeof(struct vm_anon *), M_UVMAMAP,
489 mflag);
490 if (newsl == NULL || newbck == NULL || newover == NULL) {
491 #ifdef UVM_AMAP_PPREF
492 if (newppref != NULL) {
493 free(newppref, M_UVMAMAP);
494 }
495 #endif
496 if (newsl != NULL) {
497 free(newsl, M_UVMAMAP);
498 }
499 if (newbck != NULL) {
500 free(newbck, M_UVMAMAP);
501 }
502 if (newover != NULL) {
503 free(newover, M_UVMAMAP);
504 }
505 return ENOMEM;
506 }
507 amap_lock(amap);
508 KASSERT(amap->am_maxslot < slotneed);
509
510 /*
511 * now copy everything over to new malloc'd areas...
512 */
513
514 slotadded = slotalloc - amap->am_nslot;
515 if (!(flags & AMAP_EXTEND_FORWARDS))
516 slotspace = slotalloc - slotmapped;
517
518 /* do am_slots */
519 oldsl = amap->am_slots;
520 if (flags & AMAP_EXTEND_FORWARDS)
521 memcpy(newsl, oldsl, sizeof(int) * amap->am_nused);
522 else
523 for (i = 0; i < amap->am_nused; i++)
524 newsl[i] = oldsl[i] + slotspace - slotoff;
525 amap->am_slots = newsl;
526
527 /* do am_anon */
528 oldover = amap->am_anon;
529 if (flags & AMAP_EXTEND_FORWARDS) {
530 memcpy(newover, oldover,
531 sizeof(struct vm_anon *) * amap->am_nslot);
532 memset(newover + amap->am_nslot, 0,
533 sizeof(struct vm_anon *) * slotadded);
534 } else {
535 memcpy(newover + slotspace, oldover + slotoff,
536 sizeof(struct vm_anon *) * slotmapped);
537 memset(newover, 0,
538 sizeof(struct vm_anon *) * slotspace);
539 }
540 amap->am_anon = newover;
541
542 /* do am_bckptr */
543 oldbck = amap->am_bckptr;
544 if (flags & AMAP_EXTEND_FORWARDS)
545 memcpy(newbck, oldbck, sizeof(int) * amap->am_nslot);
546 else
547 memcpy(newbck + slotspace, oldbck + slotoff,
548 sizeof(int) * slotmapped);
549 amap->am_bckptr = newbck;
550
551 #ifdef UVM_AMAP_PPREF
552 /* do ppref */
553 oldppref = amap->am_ppref;
554 if (newppref) {
555 if (flags & AMAP_EXTEND_FORWARDS) {
556 memcpy(newppref, oldppref,
557 sizeof(int) * amap->am_nslot);
558 memset(newppref + amap->am_nslot, 0,
559 sizeof(int) * slotadded);
560 } else {
561 memcpy(newppref + slotspace, oldppref + slotoff,
562 sizeof(int) * slotmapped);
563 }
564 amap->am_ppref = newppref;
565 if ((flags & AMAP_EXTEND_FORWARDS) &&
566 (slotoff + slotmapped) < amap->am_nslot)
567 amap_pp_adjref(amap, slotoff + slotmapped,
568 (amap->am_nslot - (slotoff + slotmapped)), 1);
569 if (flags & AMAP_EXTEND_FORWARDS)
570 pp_setreflen(newppref, amap->am_nslot, 1,
571 slotneed - amap->am_nslot);
572 else {
573 pp_setreflen(newppref, 0, 0,
574 slotalloc - slotneed);
575 pp_setreflen(newppref, slotalloc - slotneed, 1,
576 slotneed - slotmapped);
577 }
578 } else {
579 if (amap->am_ppref)
580 amap->am_ppref = PPREF_NONE;
581 }
582 #endif
583
584 /* update master values */
585 if (flags & AMAP_EXTEND_FORWARDS)
586 amap->am_nslot = slotneed;
587 else {
588 entry->aref.ar_pageoff = slotspace - slotadd;
589 amap->am_nslot = slotalloc;
590 }
591 amap->am_maxslot = slotalloc;
592
593 amap_unlock(amap);
594 free(oldsl, M_UVMAMAP);
595 free(oldbck, M_UVMAMAP);
596 free(oldover, M_UVMAMAP);
597 #ifdef UVM_AMAP_PPREF
598 if (oldppref && oldppref != PPREF_NONE)
599 free(oldppref, M_UVMAMAP);
600 #endif
601 UVMHIST_LOG(maphist,"<- done (case 3), amap = 0x%x, slotneed=%d",
602 amap, slotneed, 0, 0);
603 return 0;
604 }
605
606 /*
607 * amap_share_protect: change protection of anons in a shared amap
608 *
609 * for shared amaps, given the current data structure layout, it is
610 * not possible for us to directly locate all maps referencing the
611 * shared anon (to change the protection). in order to protect data
612 * in shared maps we use pmap_page_protect(). [this is useful for IPC
613 * mechanisms like map entry passing that may want to write-protect
614 * all mappings of a shared amap.] we traverse am_anon or am_slots
615 * depending on the current state of the amap.
616 *
617 * => entry's map and amap must be locked by the caller
618 */
619 void
620 amap_share_protect(entry, prot)
621 struct vm_map_entry *entry;
622 vm_prot_t prot;
623 {
624 struct vm_amap *amap = entry->aref.ar_amap;
625 int slots, lcv, slot, stop;
626
627 LOCK_ASSERT(simple_lock_held(&amap->am_l));
628
629 AMAP_B2SLOT(slots, (entry->end - entry->start));
630 stop = entry->aref.ar_pageoff + slots;
631
632 if (slots < amap->am_nused) {
633 /* cheaper to traverse am_anon */
634 for (lcv = entry->aref.ar_pageoff ; lcv < stop ; lcv++) {
635 if (amap->am_anon[lcv] == NULL)
636 continue;
637 if (amap->am_anon[lcv]->u.an_page != NULL)
638 pmap_page_protect(amap->am_anon[lcv]->u.an_page,
639 prot);
640 }
641 return;
642 }
643
644 /* cheaper to traverse am_slots */
645 for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
646 slot = amap->am_slots[lcv];
647 if (slot < entry->aref.ar_pageoff || slot >= stop)
648 continue;
649 if (amap->am_anon[slot]->u.an_page != NULL)
650 pmap_page_protect(amap->am_anon[slot]->u.an_page, prot);
651 }
652 }
653
654 /*
655 * amap_wipeout: wipeout all anon's in an amap; then free the amap!
656 *
657 * => called from amap_unref when the final reference to an amap is
658 * discarded (i.e. when reference count == 1)
659 * => the amap should be locked (by the caller)
660 */
661
662 void
663 amap_wipeout(amap)
664 struct vm_amap *amap;
665 {
666 int lcv, slot;
667 struct vm_anon *anon;
668 UVMHIST_FUNC("amap_wipeout"); UVMHIST_CALLED(maphist);
669 UVMHIST_LOG(maphist,"(amap=0x%x)", amap, 0,0,0);
670
671 amap_unlock(amap);
672 for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
673 int refs;
674
675 slot = amap->am_slots[lcv];
676 anon = amap->am_anon[slot];
677
678 if (anon == NULL || anon->an_ref == 0)
679 panic("amap_wipeout: corrupt amap");
680
681 simple_lock(&anon->an_lock);
682 UVMHIST_LOG(maphist," processing anon 0x%x, ref=%d", anon,
683 anon->an_ref, 0, 0);
684 refs = --anon->an_ref;
685 simple_unlock(&anon->an_lock);
686 if (refs == 0) {
687
688 /*
689 * we had the last reference to a vm_anon. free it.
690 */
691
692 uvm_anfree(anon);
693 }
694
695 /*
696 * XXX
697 * releasing the swap space held by an N anons is an O(N^2)
698 * operation because of the implementation of extents.
699 * if there are many anons, tearing down an exiting process'
700 * address space can take many seconds, which causes very
701 * annoying pauses. we yield here to give other processes
702 * a chance to run. this should be removed once the performance
703 * of swap space management is improved.
704 */
705
706 if (curlwp->l_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
707 preempt(1);
708 }
709
710 /*
711 * now we free the map
712 */
713
714 amap->am_ref = 0; /* ... was one */
715 amap->am_nused = 0;
716 amap_free(amap); /* will unlock and free amap */
717 UVMHIST_LOG(maphist,"<- done!", 0,0,0,0);
718 }
719
720 /*
721 * amap_copy: ensure that a map entry's "needs_copy" flag is false
722 * by copying the amap if necessary.
723 *
724 * => an entry with a null amap pointer will get a new (blank) one.
725 * => the map that the map entry belongs to must be locked by caller.
726 * => the amap currently attached to "entry" (if any) must be unlocked.
727 * => if canchunk is true, then we may clip the entry into a chunk
728 * => "startva" and "endva" are used only if canchunk is true. they are
729 * used to limit chunking (e.g. if you have a large space that you
730 * know you are going to need to allocate amaps for, there is no point
731 * in allowing that to be chunked)
732 */
733
734 void
735 amap_copy(map, entry, waitf, canchunk, startva, endva)
736 struct vm_map *map;
737 struct vm_map_entry *entry;
738 int waitf;
739 boolean_t canchunk;
740 vaddr_t startva, endva;
741 {
742 struct vm_amap *amap, *srcamap;
743 int slots, lcv;
744 vaddr_t chunksize;
745 UVMHIST_FUNC("amap_copy"); UVMHIST_CALLED(maphist);
746 UVMHIST_LOG(maphist, " (map=%p, entry=%p, waitf=%d)",
747 map, entry, waitf, 0);
748
749 /*
750 * is there a map to copy? if not, create one from scratch.
751 */
752
753 if (entry->aref.ar_amap == NULL) {
754
755 /*
756 * check to see if we have a large amap that we can
757 * chunk. we align startva/endva to chunk-sized
758 * boundaries and then clip to them.
759 */
760
761 if (canchunk && atop(entry->end - entry->start) >=
762 UVM_AMAP_LARGE) {
763 /* convert slots to bytes */
764 chunksize = UVM_AMAP_CHUNK << PAGE_SHIFT;
765 startva = (startva / chunksize) * chunksize;
766 endva = roundup(endva, chunksize);
767 UVMHIST_LOG(maphist, " chunk amap ==> clip 0x%x->0x%x"
768 "to 0x%x->0x%x", entry->start, entry->end, startva,
769 endva);
770 UVM_MAP_CLIP_START(map, entry, startva);
771 /* watch out for endva wrap-around! */
772 if (endva >= startva)
773 UVM_MAP_CLIP_END(map, entry, endva);
774 }
775
776 UVMHIST_LOG(maphist, "<- done [creating new amap 0x%x->0x%x]",
777 entry->start, entry->end, 0, 0);
778 entry->aref.ar_pageoff = 0;
779 entry->aref.ar_amap = amap_alloc(entry->end - entry->start, 0,
780 waitf);
781 if (entry->aref.ar_amap != NULL)
782 entry->etype &= ~UVM_ET_NEEDSCOPY;
783 return;
784 }
785
786 /*
787 * first check and see if we are the only map entry
788 * referencing the amap we currently have. if so, then we can
789 * just take it over rather than copying it. note that we are
790 * reading am_ref with the amap unlocked... the value can only
791 * be one if we have the only reference to the amap (via our
792 * locked map). if we are greater than one we fall through to
793 * the next case (where we double check the value).
794 */
795
796 if (entry->aref.ar_amap->am_ref == 1) {
797 entry->etype &= ~UVM_ET_NEEDSCOPY;
798 UVMHIST_LOG(maphist, "<- done [ref cnt = 1, took it over]",
799 0, 0, 0, 0);
800 return;
801 }
802
803 /*
804 * looks like we need to copy the map.
805 */
806
807 UVMHIST_LOG(maphist," amap=%p, ref=%d, must copy it",
808 entry->aref.ar_amap, entry->aref.ar_amap->am_ref, 0, 0);
809 AMAP_B2SLOT(slots, entry->end - entry->start);
810 amap = amap_alloc1(slots, 0, waitf);
811 if (amap == NULL) {
812 UVMHIST_LOG(maphist, " amap_alloc1 failed", 0,0,0,0);
813 return;
814 }
815 srcamap = entry->aref.ar_amap;
816 amap_lock(srcamap);
817
818 /*
819 * need to double check reference count now that we've got the
820 * src amap locked down. the reference count could have
821 * changed while we were in malloc. if the reference count
822 * dropped down to one we take over the old map rather than
823 * copying the amap.
824 */
825
826 if (srcamap->am_ref == 1) { /* take it over? */
827 entry->etype &= ~UVM_ET_NEEDSCOPY;
828 amap->am_ref--; /* drop final reference to map */
829 amap_free(amap); /* dispose of new (unused) amap */
830 amap_unlock(srcamap);
831 return;
832 }
833
834 /*
835 * we must copy it now.
836 */
837
838 UVMHIST_LOG(maphist, " copying amap now",0, 0, 0, 0);
839 for (lcv = 0 ; lcv < slots; lcv++) {
840 amap->am_anon[lcv] =
841 srcamap->am_anon[entry->aref.ar_pageoff + lcv];
842 if (amap->am_anon[lcv] == NULL)
843 continue;
844 simple_lock(&amap->am_anon[lcv]->an_lock);
845 amap->am_anon[lcv]->an_ref++;
846 simple_unlock(&amap->am_anon[lcv]->an_lock);
847 amap->am_bckptr[lcv] = amap->am_nused;
848 amap->am_slots[amap->am_nused] = lcv;
849 amap->am_nused++;
850 }
851 memset(&amap->am_anon[lcv], 0,
852 (amap->am_maxslot - lcv) * sizeof(struct vm_anon *));
853
854 /*
855 * drop our reference to the old amap (srcamap) and unlock.
856 * we know that the reference count on srcamap is greater than
857 * one (we checked above), so there is no way we could drop
858 * the count to zero. [and no need to worry about freeing it]
859 */
860
861 srcamap->am_ref--;
862 if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0)
863 srcamap->am_flags &= ~AMAP_SHARED; /* clear shared flag */
864 #ifdef UVM_AMAP_PPREF
865 if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) {
866 amap_pp_adjref(srcamap, entry->aref.ar_pageoff,
867 (entry->end - entry->start) >> PAGE_SHIFT, -1);
868 }
869 #endif
870
871 amap_unlock(srcamap);
872
873 /*
874 * install new amap.
875 */
876
877 entry->aref.ar_pageoff = 0;
878 entry->aref.ar_amap = amap;
879 entry->etype &= ~UVM_ET_NEEDSCOPY;
880 UVMHIST_LOG(maphist, "<- done",0, 0, 0, 0);
881 }
882
883 /*
884 * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2)
885 *
886 * called during fork(2) when the parent process has a wired map
887 * entry. in that case we want to avoid write-protecting pages
888 * in the parent's map (e.g. like what you'd do for a COW page)
889 * so we resolve the COW here.
890 *
891 * => assume parent's entry was wired, thus all pages are resident.
892 * => assume pages that are loaned out (loan_count) are already mapped
893 * read-only in all maps, and thus no need for us to worry about them
894 * => assume both parent and child vm_map's are locked
895 * => caller passes child's map/entry in to us
896 * => if we run out of memory we will unlock the amap and sleep _with_ the
897 * parent and child vm_map's locked(!). we have to do this since
898 * we are in the middle of a fork(2) and we can't let the parent
899 * map change until we are done copying all the map entrys.
900 * => XXXCDC: out of memory should cause fork to fail, but there is
901 * currently no easy way to do this (needs fix)
902 * => page queues must be unlocked (we may lock them)
903 */
904
905 void
906 amap_cow_now(map, entry)
907 struct vm_map *map;
908 struct vm_map_entry *entry;
909 {
910 struct vm_amap *amap = entry->aref.ar_amap;
911 int lcv, slot;
912 struct vm_anon *anon, *nanon;
913 struct vm_page *pg, *npg;
914
915 /*
916 * note that if we unlock the amap then we must ReStart the "lcv" for
917 * loop because some other process could reorder the anon's in the
918 * am_anon[] array on us while the lock is dropped.
919 */
920
921 ReStart:
922 amap_lock(amap);
923 for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
924
925 /*
926 * get the page
927 */
928
929 slot = amap->am_slots[lcv];
930 anon = amap->am_anon[slot];
931 simple_lock(&anon->an_lock);
932
933 /*
934 * If the anon has only one ref, we must have already copied it.
935 * This can happen if we needed to sleep waiting for memory
936 * in a previous run through this loop. The new page might
937 * even have been paged out, since the new page is not wired.
938 */
939
940 if (anon->an_ref == 1) {
941 KASSERT(anon->u.an_page != NULL ||
942 anon->an_swslot != 0);
943 simple_unlock(&anon->an_lock);
944 continue;
945 }
946
947 /*
948 * The old page must be resident since the parent is wired.
949 */
950
951 pg = anon->u.an_page;
952 KASSERT(pg != NULL);
953 KASSERT(pg->wire_count > 0);
954
955 /*
956 * If the page is loaned then it must already be mapped
957 * read-only and we don't need to copy it.
958 */
959
960 if (pg->loan_count != 0) {
961 simple_unlock(&anon->an_lock);
962 continue;
963 }
964 KASSERT(pg->uanon == anon && pg->uobject == NULL);
965
966 /*
967 * if the page is busy then we have to unlock, wait for
968 * it and then restart.
969 */
970
971 if (pg->flags & PG_BUSY) {
972 pg->flags |= PG_WANTED;
973 amap_unlock(amap);
974 UVM_UNLOCK_AND_WAIT(pg, &anon->an_lock, FALSE,
975 "cownow", 0);
976 goto ReStart;
977 }
978
979 /*
980 * ok, time to do a copy-on-write to a new anon
981 */
982
983 nanon = uvm_analloc();
984 if (nanon) {
985 npg = uvm_pagealloc(NULL, 0, nanon, 0);
986 } else
987 npg = NULL; /* XXX: quiet gcc warning */
988 if (nanon == NULL || npg == NULL) {
989
990 /*
991 * XXXCDC: we should cause fork to fail, but we can't.
992 */
993
994 if (nanon) {
995 nanon->an_ref--;
996 simple_unlock(&nanon->an_lock);
997 uvm_anfree(nanon);
998 }
999 simple_unlock(&anon->an_lock);
1000 amap_unlock(amap);
1001 uvm_wait("cownowpage");
1002 goto ReStart;
1003 }
1004
1005 /*
1006 * got it... now we can copy the data and replace anon
1007 * with our new one...
1008 */
1009
1010 uvm_pagecopy(pg, npg); /* old -> new */
1011 anon->an_ref--; /* can't drop to zero */
1012 amap->am_anon[slot] = nanon; /* replace */
1013
1014 /*
1015 * drop PG_BUSY on new page ... since we have had its owner
1016 * locked the whole time it can't be PG_RELEASED or PG_WANTED.
1017 */
1018
1019 uvm_lock_pageq();
1020 uvm_pageactivate(npg);
1021 uvm_unlock_pageq();
1022 npg->flags &= ~(PG_BUSY|PG_FAKE);
1023 UVM_PAGE_OWN(npg, NULL);
1024 simple_unlock(&nanon->an_lock);
1025 simple_unlock(&anon->an_lock);
1026 }
1027 amap_unlock(amap);
1028 }
1029
1030 /*
1031 * amap_splitref: split a single reference into two separate references
1032 *
1033 * => called from uvm_map's clip routines
1034 * => origref's map should be locked
1035 * => origref->ar_amap should be unlocked (we will lock)
1036 */
1037 void
1038 amap_splitref(origref, splitref, offset)
1039 struct vm_aref *origref, *splitref;
1040 vaddr_t offset;
1041 {
1042 int leftslots;
1043
1044 AMAP_B2SLOT(leftslots, offset);
1045 if (leftslots == 0)
1046 panic("amap_splitref: split at zero offset");
1047
1048 amap_lock(origref->ar_amap);
1049
1050 /*
1051 * now: amap is locked and we have a valid am_mapped array.
1052 */
1053
1054 if (origref->ar_amap->am_nslot - origref->ar_pageoff - leftslots <= 0)
1055 panic("amap_splitref: map size check failed");
1056
1057 #ifdef UVM_AMAP_PPREF
1058 /*
1059 * establish ppref before we add a duplicate reference to the amap
1060 */
1061 if (origref->ar_amap->am_ppref == NULL)
1062 amap_pp_establish(origref->ar_amap, origref->ar_pageoff);
1063 #endif
1064
1065 splitref->ar_amap = origref->ar_amap;
1066 splitref->ar_amap->am_ref++; /* not a share reference */
1067 splitref->ar_pageoff = origref->ar_pageoff + leftslots;
1068
1069 amap_unlock(origref->ar_amap);
1070 }
1071
1072 #ifdef UVM_AMAP_PPREF
1073
1074 /*
1075 * amap_pp_establish: add a ppref array to an amap, if possible
1076 *
1077 * => amap locked by caller
1078 */
1079 void
1080 amap_pp_establish(amap, offset)
1081 struct vm_amap *amap;
1082 vaddr_t offset;
1083 {
1084 amap->am_ppref = malloc(sizeof(int) * amap->am_maxslot,
1085 M_UVMAMAP, M_NOWAIT);
1086
1087 /*
1088 * if we fail then we just won't use ppref for this amap
1089 */
1090
1091 if (amap->am_ppref == NULL) {
1092 amap->am_ppref = PPREF_NONE; /* not using it */
1093 return;
1094 }
1095 memset(amap->am_ppref, 0, sizeof(int) * amap->am_maxslot);
1096 pp_setreflen(amap->am_ppref, 0, 0, offset);
1097 pp_setreflen(amap->am_ppref, offset, amap->am_ref,
1098 amap->am_nslot - offset);
1099 return;
1100 }
1101
1102 /*
1103 * amap_pp_adjref: adjust reference count to a part of an amap using the
1104 * per-page reference count array.
1105 *
1106 * => map and amap locked by caller
1107 * => caller must check that ppref != PPREF_NONE before calling
1108 */
1109 void
1110 amap_pp_adjref(amap, curslot, slotlen, adjval)
1111 struct vm_amap *amap;
1112 int curslot;
1113 vsize_t slotlen;
1114 int adjval;
1115 {
1116 int stopslot, *ppref, lcv, prevlcv;
1117 int ref, len, prevref, prevlen;
1118
1119 stopslot = curslot + slotlen;
1120 ppref = amap->am_ppref;
1121 prevlcv = 0;
1122
1123 /*
1124 * first advance to the correct place in the ppref array,
1125 * fragment if needed.
1126 */
1127
1128 for (lcv = 0 ; lcv < curslot ; lcv += len) {
1129 pp_getreflen(ppref, lcv, &ref, &len);
1130 if (lcv + len > curslot) { /* goes past start? */
1131 pp_setreflen(ppref, lcv, ref, curslot - lcv);
1132 pp_setreflen(ppref, curslot, ref, len - (curslot -lcv));
1133 len = curslot - lcv; /* new length of entry @ lcv */
1134 }
1135 prevlcv = lcv;
1136 }
1137 if (lcv != 0)
1138 pp_getreflen(ppref, prevlcv, &prevref, &prevlen);
1139 else {
1140 /* Ensure that the "prevref == ref" test below always
1141 * fails, since we're starting from the beginning of
1142 * the ppref array; that is, there is no previous
1143 * chunk.
1144 */
1145 prevref = -1;
1146 prevlen = 0;
1147 }
1148
1149 /*
1150 * now adjust reference counts in range. merge the first
1151 * changed entry with the last unchanged entry if possible.
1152 */
1153
1154 if (lcv != curslot)
1155 panic("amap_pp_adjref: overshot target");
1156
1157 for (/* lcv already set */; lcv < stopslot ; lcv += len) {
1158 pp_getreflen(ppref, lcv, &ref, &len);
1159 if (lcv + len > stopslot) { /* goes past end? */
1160 pp_setreflen(ppref, lcv, ref, stopslot - lcv);
1161 pp_setreflen(ppref, stopslot, ref,
1162 len - (stopslot - lcv));
1163 len = stopslot - lcv;
1164 }
1165 ref += adjval;
1166 if (ref < 0)
1167 panic("amap_pp_adjref: negative reference count");
1168 if (lcv == prevlcv + prevlen && ref == prevref) {
1169 pp_setreflen(ppref, prevlcv, ref, prevlen + len);
1170 } else {
1171 pp_setreflen(ppref, lcv, ref, len);
1172 }
1173 if (ref == 0)
1174 amap_wiperange(amap, lcv, len);
1175 }
1176
1177 }
1178
1179 /*
1180 * amap_wiperange: wipe out a range of an amap
1181 * [different from amap_wipeout because the amap is kept intact]
1182 *
1183 * => both map and amap must be locked by caller.
1184 */
1185 void
1186 amap_wiperange(amap, slotoff, slots)
1187 struct vm_amap *amap;
1188 int slotoff, slots;
1189 {
1190 int byanon, lcv, stop, curslot, ptr, slotend;
1191 struct vm_anon *anon;
1192
1193 /*
1194 * we can either traverse the amap by am_anon or by am_slots depending
1195 * on which is cheaper. decide now.
1196 */
1197
1198 if (slots < amap->am_nused) {
1199 byanon = TRUE;
1200 lcv = slotoff;
1201 stop = slotoff + slots;
1202 slotend = 0;
1203 } else {
1204 byanon = FALSE;
1205 lcv = 0;
1206 stop = amap->am_nused;
1207 slotend = slotoff + slots;
1208 }
1209
1210 while (lcv < stop) {
1211 int refs;
1212
1213 if (byanon) {
1214 curslot = lcv++; /* lcv advances here */
1215 if (amap->am_anon[curslot] == NULL)
1216 continue;
1217 } else {
1218 curslot = amap->am_slots[lcv];
1219 if (curslot < slotoff || curslot >= slotend) {
1220 lcv++; /* lcv advances here */
1221 continue;
1222 }
1223 stop--; /* drop stop, since anon will be removed */
1224 }
1225 anon = amap->am_anon[curslot];
1226
1227 /*
1228 * remove it from the amap
1229 */
1230
1231 amap->am_anon[curslot] = NULL;
1232 ptr = amap->am_bckptr[curslot];
1233 if (ptr != (amap->am_nused - 1)) {
1234 amap->am_slots[ptr] =
1235 amap->am_slots[amap->am_nused - 1];
1236 amap->am_bckptr[amap->am_slots[ptr]] =
1237 ptr; /* back ptr. */
1238 }
1239 amap->am_nused--;
1240
1241 /*
1242 * drop anon reference count
1243 */
1244
1245 simple_lock(&anon->an_lock);
1246 refs = --anon->an_ref;
1247 simple_unlock(&anon->an_lock);
1248 if (refs == 0) {
1249
1250 /*
1251 * we just eliminated the last reference to an anon.
1252 * free it.
1253 */
1254
1255 uvm_anfree(anon);
1256 }
1257 }
1258 }
1259
1260 #endif
Cache object: 0029347613e3d0761a71499b6cea7abf
|