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