uvm_amap.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. /* $OpenBSD: uvm_amap.c,v 1.58 2014/12/23 04:56:47 tedu Exp $ */
  2. /* $NetBSD: uvm_amap.c,v 1.27 2000/11/25 06:27:59 chs Exp $ */
  3. /*
  4. * Copyright (c) 1997 Charles D. Cranor and Washington University.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /*
  28. * uvm_amap.c: amap operations
  29. *
  30. * this file contains functions that perform operations on amaps. see
  31. * uvm_amap.h for a brief explanation of the role of amaps in uvm.
  32. */
  33. #include <sys/param.h>
  34. #include <sys/systm.h>
  35. #include <sys/malloc.h>
  36. #include <sys/kernel.h>
  37. #include <sys/pool.h>
  38. #include <sys/atomic.h>
  39. #include <uvm/uvm.h>
  40. #include <uvm/uvm_swap.h>
  41. /*
  42. * pool for allocation of vm_map structures. note that in order to
  43. * avoid an endless loop, the amap pool's allocator cannot allocate
  44. * memory from an amap (it currently goes through the kernel uobj, so
  45. * we are ok).
  46. */
  47. struct pool uvm_amap_pool;
  48. LIST_HEAD(, vm_amap) amap_list;
  49. #define MALLOC_SLOT_UNIT (2 * sizeof(int) + sizeof(struct vm_anon *))
  50. /*
  51. * local functions
  52. */
  53. static struct vm_amap *amap_alloc1(int, int, int);
  54. static __inline void amap_list_insert(struct vm_amap *);
  55. static __inline void amap_list_remove(struct vm_amap *);
  56. static __inline void
  57. amap_list_insert(struct vm_amap *amap)
  58. {
  59. LIST_INSERT_HEAD(&amap_list, amap, am_list);
  60. }
  61. static __inline void
  62. amap_list_remove(struct vm_amap *amap)
  63. {
  64. LIST_REMOVE(amap, am_list);
  65. }
  66. #ifdef UVM_AMAP_PPREF
  67. /*
  68. * what is ppref? ppref is an _optional_ amap feature which is used
  69. * to keep track of reference counts on a per-page basis. it is enabled
  70. * when UVM_AMAP_PPREF is defined.
  71. *
  72. * when enabled, an array of ints is allocated for the pprefs. this
  73. * array is allocated only when a partial reference is added to the
  74. * map (either by unmapping part of the amap, or gaining a reference
  75. * to only a part of an amap). if the malloc of the array fails
  76. * (M_NOWAIT), then we set the array pointer to PPREF_NONE to indicate
  77. * that we tried to do ppref's but couldn't alloc the array so just
  78. * give up (after all, this is an optional feature!).
  79. *
  80. * the array is divided into page sized "chunks." for chunks of length 1,
  81. * the chunk reference count plus one is stored in that chunk's slot.
  82. * for chunks of length > 1 the first slot contains (the reference count
  83. * plus one) * -1. [the negative value indicates that the length is
  84. * greater than one.] the second slot of the chunk contains the length
  85. * of the chunk. here is an example:
  86. *
  87. * actual REFS: 2 2 2 2 3 1 1 0 0 0 4 4 0 1 1 1
  88. * ppref: -3 4 x x 4 -2 2 -1 3 x -5 2 1 -2 3 x
  89. * <----------><-><----><-------><----><-><------->
  90. * (x = don't care)
  91. *
  92. * this allows us to allow one int to contain the ref count for the whole
  93. * chunk. note that the "plus one" part is needed because a reference
  94. * count of zero is neither positive or negative (need a way to tell
  95. * if we've got one zero or a bunch of them).
  96. *
  97. * here are some in-line functions to help us.
  98. */
  99. static __inline void pp_getreflen(int *, int, int *, int *);
  100. static __inline void pp_setreflen(int *, int, int, int);
  101. /*
  102. * pp_getreflen: get the reference and length for a specific offset
  103. */
  104. static __inline void
  105. pp_getreflen(int *ppref, int offset, int *refp, int *lenp)
  106. {
  107. if (ppref[offset] > 0) { /* chunk size must be 1 */
  108. *refp = ppref[offset] - 1; /* don't forget to adjust */
  109. *lenp = 1;
  110. } else {
  111. *refp = (ppref[offset] * -1) - 1;
  112. *lenp = ppref[offset+1];
  113. }
  114. }
  115. /*
  116. * pp_setreflen: set the reference and length for a specific offset
  117. */
  118. static __inline void
  119. pp_setreflen(int *ppref, int offset, int ref, int len)
  120. {
  121. if (len == 1) {
  122. ppref[offset] = ref + 1;
  123. } else {
  124. ppref[offset] = (ref + 1) * -1;
  125. ppref[offset+1] = len;
  126. }
  127. }
  128. #endif
  129. /*
  130. * amap_init: called at boot time to init global amap data structures
  131. */
  132. void
  133. amap_init(void)
  134. {
  135. /* Initialize the vm_amap pool. */
  136. pool_init(&uvm_amap_pool, sizeof(struct vm_amap), 0, 0, PR_WAITOK,
  137. "amappl", NULL);
  138. pool_sethiwat(&uvm_amap_pool, 4096);
  139. }
  140. /*
  141. * amap_alloc1: internal function that allocates an amap, but does not
  142. * init the overlay.
  143. */
  144. static inline struct vm_amap *
  145. amap_alloc1(int slots, int padslots, int waitf)
  146. {
  147. struct vm_amap *amap;
  148. int totalslots;
  149. amap = pool_get(&uvm_amap_pool, (waitf == M_WAITOK) ? PR_WAITOK
  150. : PR_NOWAIT);
  151. if (amap == NULL)
  152. return(NULL);
  153. totalslots = malloc_roundup((slots + padslots) * MALLOC_SLOT_UNIT) /
  154. MALLOC_SLOT_UNIT;
  155. amap->am_ref = 1;
  156. amap->am_flags = 0;
  157. #ifdef UVM_AMAP_PPREF
  158. amap->am_ppref = NULL;
  159. #endif
  160. amap->am_maxslot = totalslots;
  161. amap->am_nslot = slots;
  162. amap->am_nused = 0;
  163. amap->am_slots = malloc(totalslots * MALLOC_SLOT_UNIT, M_UVMAMAP,
  164. waitf);
  165. if (amap->am_slots == NULL)
  166. goto fail1;
  167. amap->am_bckptr = (int *)(((char *)amap->am_slots) + totalslots *
  168. sizeof(int));
  169. amap->am_anon = (struct vm_anon **)(((char *)amap->am_bckptr) +
  170. totalslots * sizeof(int));
  171. return(amap);
  172. fail1:
  173. pool_put(&uvm_amap_pool, amap);
  174. return (NULL);
  175. }
  176. /*
  177. * amap_alloc: allocate an amap to manage "sz" bytes of anonymous VM
  178. *
  179. * => caller should ensure sz is a multiple of PAGE_SIZE
  180. * => reference count to new amap is set to one
  181. */
  182. struct vm_amap *
  183. amap_alloc(vaddr_t sz, vaddr_t padsz, int waitf)
  184. {
  185. struct vm_amap *amap;
  186. int slots, padslots;
  187. AMAP_B2SLOT(slots, sz); /* load slots */
  188. AMAP_B2SLOT(padslots, padsz);
  189. amap = amap_alloc1(slots, padslots, waitf);
  190. if (amap) {
  191. memset(amap->am_anon, 0,
  192. amap->am_maxslot * sizeof(struct vm_anon *));
  193. amap_list_insert(amap);
  194. }
  195. return(amap);
  196. }
  197. /*
  198. * amap_free: free an amap
  199. *
  200. * => the amap should have a zero reference count and be empty
  201. */
  202. void
  203. amap_free(struct vm_amap *amap)
  204. {
  205. KASSERT(amap->am_ref == 0 && amap->am_nused == 0);
  206. KASSERT((amap->am_flags & AMAP_SWAPOFF) == 0);
  207. free(amap->am_slots, M_UVMAMAP, 0);
  208. #ifdef UVM_AMAP_PPREF
  209. if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
  210. free(amap->am_ppref, M_UVMAMAP, 0);
  211. #endif
  212. pool_put(&uvm_amap_pool, amap);
  213. }
  214. /*
  215. * amap_extend: extend the size of an amap (if needed)
  216. *
  217. * => called from uvm_map when we want to extend an amap to cover
  218. * a new mapping (rather than allocate a new one)
  219. * => to safely extend an amap it should have a reference count of
  220. * one (thus it can't be shared)
  221. * => XXXCDC: support padding at this level?
  222. */
  223. int
  224. amap_extend(struct vm_map_entry *entry, vsize_t addsize)
  225. {
  226. struct vm_amap *amap = entry->aref.ar_amap;
  227. int slotoff = entry->aref.ar_pageoff;
  228. int slotmapped, slotadd, slotneed, slotalloc;
  229. #ifdef UVM_AMAP_PPREF
  230. int *newppref, *oldppref;
  231. #endif
  232. u_int *newsl, *newbck, *oldsl, *oldbck;
  233. struct vm_anon **newover, **oldover;
  234. int slotadded;
  235. /*
  236. * first, determine how many slots we need in the amap. don't
  237. * forget that ar_pageoff could be non-zero: this means that
  238. * there are some unused slots before us in the amap.
  239. */
  240. AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */
  241. AMAP_B2SLOT(slotadd, addsize); /* slots to add */
  242. slotneed = slotoff + slotmapped + slotadd;
  243. /*
  244. * case 1: we already have enough slots in the map and thus
  245. * only need to bump the reference counts on the slots we are
  246. * adding.
  247. */
  248. if (amap->am_nslot >= slotneed) {
  249. #ifdef UVM_AMAP_PPREF
  250. if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  251. amap_pp_adjref(amap, slotoff + slotmapped, slotadd, 1);
  252. }
  253. #endif
  254. return (0);
  255. }
  256. /*
  257. * case 2: we pre-allocated slots for use and we just need to
  258. * bump nslot up to take account for these slots.
  259. */
  260. if (amap->am_maxslot >= slotneed) {
  261. #ifdef UVM_AMAP_PPREF
  262. if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  263. if ((slotoff + slotmapped) < amap->am_nslot)
  264. amap_pp_adjref(amap, slotoff + slotmapped,
  265. (amap->am_nslot - (slotoff + slotmapped)),
  266. 1);
  267. pp_setreflen(amap->am_ppref, amap->am_nslot, 1,
  268. slotneed - amap->am_nslot);
  269. }
  270. #endif
  271. amap->am_nslot = slotneed;
  272. /*
  273. * no need to zero am_anon since that was done at
  274. * alloc time and we never shrink an allocation.
  275. */
  276. return (0);
  277. }
  278. /*
  279. * case 3: we need to malloc a new amap and copy all the amap
  280. * data over from old amap to the new one.
  281. *
  282. * XXXCDC: could we take advantage of a kernel realloc()?
  283. */
  284. if (slotneed >= UVM_AMAP_LARGE)
  285. return E2BIG;
  286. slotalloc = malloc_roundup(slotneed * MALLOC_SLOT_UNIT) /
  287. MALLOC_SLOT_UNIT;
  288. #ifdef UVM_AMAP_PPREF
  289. newppref = NULL;
  290. if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  291. newppref = mallocarray(slotalloc, sizeof(int), M_UVMAMAP,
  292. M_WAITOK | M_CANFAIL);
  293. if (newppref == NULL) {
  294. /* give up if malloc fails */
  295. free(amap->am_ppref, M_UVMAMAP, 0);
  296. amap->am_ppref = PPREF_NONE;
  297. }
  298. }
  299. #endif
  300. newsl = malloc(slotalloc * MALLOC_SLOT_UNIT, M_UVMAMAP,
  301. M_WAITOK | M_CANFAIL);
  302. if (newsl == NULL) {
  303. #ifdef UVM_AMAP_PPREF
  304. if (newppref != NULL) {
  305. free(newppref, M_UVMAMAP, 0);
  306. }
  307. #endif
  308. return (ENOMEM);
  309. }
  310. newbck = (int *)(((char *)newsl) + slotalloc * sizeof(int));
  311. newover = (struct vm_anon **)(((char *)newbck) + slotalloc *
  312. sizeof(int));
  313. KASSERT(amap->am_maxslot < slotneed);
  314. /* now copy everything over to new malloc'd areas... */
  315. slotadded = slotalloc - amap->am_nslot;
  316. /* do am_slots */
  317. oldsl = amap->am_slots;
  318. memcpy(newsl, oldsl, sizeof(int) * amap->am_nused);
  319. amap->am_slots = newsl;
  320. /* do am_anon */
  321. oldover = amap->am_anon;
  322. memcpy(newover, oldover, sizeof(struct vm_anon *) * amap->am_nslot);
  323. memset(newover + amap->am_nslot, 0, sizeof(struct vm_anon *) *
  324. slotadded);
  325. amap->am_anon = newover;
  326. /* do am_bckptr */
  327. oldbck = amap->am_bckptr;
  328. memcpy(newbck, oldbck, sizeof(int) * amap->am_nslot);
  329. memset(newbck + amap->am_nslot, 0, sizeof(int) * slotadded); /* XXX: needed? */
  330. amap->am_bckptr = newbck;
  331. #ifdef UVM_AMAP_PPREF
  332. /* do ppref */
  333. oldppref = amap->am_ppref;
  334. if (newppref) {
  335. memcpy(newppref, oldppref, sizeof(int) * amap->am_nslot);
  336. memset(newppref + amap->am_nslot, 0, sizeof(int) * slotadded);
  337. amap->am_ppref = newppref;
  338. if ((slotoff + slotmapped) < amap->am_nslot)
  339. amap_pp_adjref(amap, slotoff + slotmapped,
  340. (amap->am_nslot - (slotoff + slotmapped)), 1);
  341. pp_setreflen(newppref, amap->am_nslot, 1,
  342. slotneed - amap->am_nslot);
  343. }
  344. #endif
  345. /* update master values */
  346. amap->am_nslot = slotneed;
  347. amap->am_maxslot = slotalloc;
  348. /* and free */
  349. free(oldsl, M_UVMAMAP, 0);
  350. #ifdef UVM_AMAP_PPREF
  351. if (oldppref && oldppref != PPREF_NONE)
  352. free(oldppref, M_UVMAMAP, 0);
  353. #endif
  354. return (0);
  355. }
  356. /*
  357. * amap_share_protect: change protection of anons in a shared amap
  358. *
  359. * for shared amaps, given the current data structure layout, it is
  360. * not possible for us to directly locate all maps referencing the
  361. * shared anon (to change the protection). in order to protect data
  362. * in shared maps we use pmap_page_protect(). [this is useful for IPC
  363. * mechanisms like map entry passing that may want to write-protect
  364. * all mappings of a shared amap.] we traverse am_anon or am_slots
  365. * depending on the current state of the amap.
  366. */
  367. void
  368. amap_share_protect(struct vm_map_entry *entry, vm_prot_t prot)
  369. {
  370. struct vm_amap *amap = entry->aref.ar_amap;
  371. int slots, lcv, slot, stop;
  372. AMAP_B2SLOT(slots, (entry->end - entry->start));
  373. stop = entry->aref.ar_pageoff + slots;
  374. if (slots < amap->am_nused) {
  375. /* cheaper to traverse am_anon */
  376. for (lcv = entry->aref.ar_pageoff ; lcv < stop ; lcv++) {
  377. if (amap->am_anon[lcv] == NULL)
  378. continue;
  379. if (amap->am_anon[lcv]->an_page != NULL)
  380. pmap_page_protect(amap->am_anon[lcv]->an_page,
  381. prot);
  382. }
  383. return;
  384. }
  385. /* cheaper to traverse am_slots */
  386. for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  387. slot = amap->am_slots[lcv];
  388. if (slot < entry->aref.ar_pageoff || slot >= stop)
  389. continue;
  390. if (amap->am_anon[slot]->an_page != NULL)
  391. pmap_page_protect(amap->am_anon[slot]->an_page, prot);
  392. }
  393. return;
  394. }
  395. /*
  396. * amap_wipeout: wipeout all anon's in an amap; then free the amap!
  397. *
  398. * => called from amap_unref when the final reference to an amap is
  399. * discarded (i.e. when reference count == 1)
  400. */
  401. void
  402. amap_wipeout(struct vm_amap *amap)
  403. {
  404. int lcv, slot;
  405. struct vm_anon *anon;
  406. KASSERT(amap->am_ref == 0);
  407. if (__predict_false((amap->am_flags & AMAP_SWAPOFF) != 0)) {
  408. /* amap_swap_off will call us again. */
  409. return;
  410. }
  411. amap_list_remove(amap);
  412. for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  413. int refs;
  414. slot = amap->am_slots[lcv];
  415. anon = amap->am_anon[slot];
  416. if (anon == NULL || anon->an_ref == 0)
  417. panic("amap_wipeout: corrupt amap");
  418. refs = --anon->an_ref;
  419. if (refs == 0) {
  420. /* we had the last reference to a vm_anon. free it. */
  421. uvm_anfree(anon);
  422. }
  423. }
  424. /* now we free the map */
  425. amap->am_ref = 0; /* ... was one */
  426. amap->am_nused = 0;
  427. amap_free(amap); /* will free amap */
  428. }
  429. /*
  430. * amap_copy: ensure that a map entry's "needs_copy" flag is false
  431. * by copying the amap if necessary.
  432. *
  433. * => an entry with a null amap pointer will get a new (blank) one.
  434. * => if canchunk is true, then we may clip the entry into a chunk
  435. * => "startva" and "endva" are used only if canchunk is true. they are
  436. * used to limit chunking (e.g. if you have a large space that you
  437. * know you are going to need to allocate amaps for, there is no point
  438. * in allowing that to be chunked)
  439. */
  440. void
  441. amap_copy(struct vm_map *map, struct vm_map_entry *entry, int waitf,
  442. boolean_t canchunk, vaddr_t startva, vaddr_t endva)
  443. {
  444. struct vm_amap *amap, *srcamap;
  445. int slots, lcv;
  446. vaddr_t chunksize;
  447. /* is there a map to copy? if not, create one from scratch. */
  448. if (entry->aref.ar_amap == NULL) {
  449. /*
  450. * check to see if we have a large amap that we can
  451. * chunk. we align startva/endva to chunk-sized
  452. * boundaries and then clip to them.
  453. */
  454. if (canchunk && atop(entry->end - entry->start) >=
  455. UVM_AMAP_LARGE) {
  456. /* convert slots to bytes */
  457. chunksize = UVM_AMAP_CHUNK << PAGE_SHIFT;
  458. startva = (startva / chunksize) * chunksize;
  459. endva = roundup(endva, chunksize);
  460. UVM_MAP_CLIP_START(map, entry, startva);
  461. /* watch out for endva wrap-around! */
  462. if (endva >= startva)
  463. UVM_MAP_CLIP_END(map, entry, endva);
  464. }
  465. entry->aref.ar_pageoff = 0;
  466. entry->aref.ar_amap = amap_alloc(entry->end - entry->start, 0,
  467. waitf);
  468. if (entry->aref.ar_amap != NULL)
  469. entry->etype &= ~UVM_ET_NEEDSCOPY;
  470. return;
  471. }
  472. /*
  473. * first check and see if we are the only map entry
  474. * referencing the amap we currently have. if so, then we can
  475. * just take it over rather than copying it. the value can only
  476. * be one if we have the only reference to the amap
  477. */
  478. if (entry->aref.ar_amap->am_ref == 1) {
  479. entry->etype &= ~UVM_ET_NEEDSCOPY;
  480. return;
  481. }
  482. /* looks like we need to copy the map. */
  483. AMAP_B2SLOT(slots, entry->end - entry->start);
  484. amap = amap_alloc1(slots, 0, waitf);
  485. if (amap == NULL)
  486. return;
  487. srcamap = entry->aref.ar_amap;
  488. /*
  489. * need to double check reference count now. the reference count
  490. * could have changed while we were in malloc. if the reference count
  491. * dropped down to one we take over the old map rather than
  492. * copying the amap.
  493. */
  494. if (srcamap->am_ref == 1) { /* take it over? */
  495. entry->etype &= ~UVM_ET_NEEDSCOPY;
  496. amap->am_ref--; /* drop final reference to map */
  497. amap_free(amap); /* dispose of new (unused) amap */
  498. return;
  499. }
  500. /* we must copy it now. */
  501. for (lcv = 0 ; lcv < slots; lcv++) {
  502. amap->am_anon[lcv] =
  503. srcamap->am_anon[entry->aref.ar_pageoff + lcv];
  504. if (amap->am_anon[lcv] == NULL)
  505. continue;
  506. amap->am_anon[lcv]->an_ref++;
  507. amap->am_bckptr[lcv] = amap->am_nused;
  508. amap->am_slots[amap->am_nused] = lcv;
  509. amap->am_nused++;
  510. }
  511. memset(&amap->am_anon[lcv], 0,
  512. (amap->am_maxslot - lcv) * sizeof(struct vm_anon *));
  513. /*
  514. * drop our reference to the old amap (srcamap).
  515. * we know that the reference count on srcamap is greater than
  516. * one (we checked above), so there is no way we could drop
  517. * the count to zero. [and no need to worry about freeing it]
  518. */
  519. srcamap->am_ref--;
  520. if (srcamap->am_ref == 1 && (srcamap->am_flags & AMAP_SHARED) != 0)
  521. srcamap->am_flags &= ~AMAP_SHARED; /* clear shared flag */
  522. #ifdef UVM_AMAP_PPREF
  523. if (srcamap->am_ppref && srcamap->am_ppref != PPREF_NONE) {
  524. amap_pp_adjref(srcamap, entry->aref.ar_pageoff,
  525. (entry->end - entry->start) >> PAGE_SHIFT, -1);
  526. }
  527. #endif
  528. /* install new amap. */
  529. entry->aref.ar_pageoff = 0;
  530. entry->aref.ar_amap = amap;
  531. entry->etype &= ~UVM_ET_NEEDSCOPY;
  532. amap_list_insert(amap);
  533. }
  534. /*
  535. * amap_cow_now: resolve all copy-on-write faults in an amap now for fork(2)
  536. *
  537. * called during fork(2) when the parent process has a wired map
  538. * entry. in that case we want to avoid write-protecting pages
  539. * in the parent's map (e.g. like what you'd do for a COW page)
  540. * so we resolve the COW here.
  541. *
  542. * => assume parent's entry was wired, thus all pages are resident.
  543. * => assume pages that are loaned out (loan_count) are already mapped
  544. * read-only in all maps, and thus no need for us to worry about them
  545. * => caller passes child's map/entry in to us
  546. * => XXXCDC: out of memory should cause fork to fail, but there is
  547. * currently no easy way to do this (needs fix)
  548. */
  549. void
  550. amap_cow_now(struct vm_map *map, struct vm_map_entry *entry)
  551. {
  552. struct vm_amap *amap = entry->aref.ar_amap;
  553. int lcv, slot;
  554. struct vm_anon *anon, *nanon;
  555. struct vm_page *pg, *npg;
  556. /*
  557. * note that if we wait, we must ReStart the "lcv" for loop because
  558. * some other process could reorder the anon's in the
  559. * am_anon[] array on us.
  560. */
  561. ReStart:
  562. for (lcv = 0 ; lcv < amap->am_nused ; lcv++) {
  563. /* get the page */
  564. slot = amap->am_slots[lcv];
  565. anon = amap->am_anon[slot];
  566. pg = anon->an_page;
  567. /* page must be resident since parent is wired */
  568. if (pg == NULL)
  569. panic("amap_cow_now: non-resident wired page"
  570. " in anon %p", anon);
  571. /*
  572. * if the anon ref count is one and the page is not loaned,
  573. * then we are safe (the child has exclusive access to the
  574. * page). if the page is loaned, then it must already be
  575. * mapped read-only.
  576. *
  577. * we only need to get involved when these are not true.
  578. * [note: if loan_count == 0, then the anon must own the page]
  579. */
  580. if (anon->an_ref > 1 && pg->loan_count == 0) {
  581. /*
  582. * if the page is busy then we have to wait for
  583. * it and then restart.
  584. */
  585. if (pg->pg_flags & PG_BUSY) {
  586. atomic_setbits_int(&pg->pg_flags, PG_WANTED);
  587. UVM_WAIT(pg, FALSE, "cownow", 0);
  588. goto ReStart;
  589. }
  590. /* ok, time to do a copy-on-write to a new anon */
  591. nanon = uvm_analloc();
  592. if (nanon) {
  593. npg = uvm_pagealloc(NULL, 0, nanon, 0);
  594. } else
  595. npg = NULL; /* XXX: quiet gcc warning */
  596. if (nanon == NULL || npg == NULL) {
  597. /* out of memory */
  598. /*
  599. * XXXCDC: we should cause fork to fail, but
  600. * we can't ...
  601. */
  602. if (nanon) {
  603. uvm_anfree(nanon);
  604. }
  605. uvm_wait("cownowpage");
  606. goto ReStart;
  607. }
  608. /*
  609. * got it... now we can copy the data and replace anon
  610. * with our new one...
  611. */
  612. uvm_pagecopy(pg, npg); /* old -> new */
  613. anon->an_ref--; /* can't drop to zero */
  614. amap->am_anon[slot] = nanon; /* replace */
  615. /*
  616. * drop PG_BUSY on new page ... since we have had its
  617. * owner locked the whole time it can't be
  618. * PG_RELEASED | PG_WANTED.
  619. */
  620. atomic_clearbits_int(&npg->pg_flags, PG_BUSY|PG_FAKE);
  621. UVM_PAGE_OWN(npg, NULL);
  622. uvm_lock_pageq();
  623. uvm_pageactivate(npg);
  624. uvm_unlock_pageq();
  625. }
  626. }
  627. }
  628. /*
  629. * amap_splitref: split a single reference into two separate references
  630. *
  631. * => called from uvm_map's clip routines
  632. */
  633. void
  634. amap_splitref(struct vm_aref *origref, struct vm_aref *splitref, vaddr_t offset)
  635. {
  636. int leftslots;
  637. AMAP_B2SLOT(leftslots, offset);
  638. if (leftslots == 0)
  639. panic("amap_splitref: split at zero offset");
  640. /* now: we have a valid am_mapped array. */
  641. if (origref->ar_amap->am_nslot - origref->ar_pageoff - leftslots <= 0)
  642. panic("amap_splitref: map size check failed");
  643. #ifdef UVM_AMAP_PPREF
  644. /* establish ppref before we add a duplicate reference to the amap */
  645. if (origref->ar_amap->am_ppref == NULL)
  646. amap_pp_establish(origref->ar_amap);
  647. #endif
  648. splitref->ar_amap = origref->ar_amap;
  649. splitref->ar_amap->am_ref++; /* not a share reference */
  650. splitref->ar_pageoff = origref->ar_pageoff + leftslots;
  651. }
  652. #ifdef UVM_AMAP_PPREF
  653. /*
  654. * amap_pp_establish: add a ppref array to an amap, if possible
  655. */
  656. void
  657. amap_pp_establish(struct vm_amap *amap)
  658. {
  659. amap->am_ppref = mallocarray(amap->am_maxslot, sizeof(int),
  660. M_UVMAMAP, M_NOWAIT|M_ZERO);
  661. /* if we fail then we just won't use ppref for this amap */
  662. if (amap->am_ppref == NULL) {
  663. amap->am_ppref = PPREF_NONE; /* not using it */
  664. return;
  665. }
  666. /* init ppref */
  667. pp_setreflen(amap->am_ppref, 0, amap->am_ref, amap->am_nslot);
  668. }
  669. /*
  670. * amap_pp_adjref: adjust reference count to a part of an amap using the
  671. * per-page reference count array.
  672. *
  673. * => caller must check that ppref != PPREF_NONE before calling
  674. */
  675. void
  676. amap_pp_adjref(struct vm_amap *amap, int curslot, vsize_t slotlen, int adjval)
  677. {
  678. int stopslot, *ppref, lcv, prevlcv;
  679. int ref, len, prevref, prevlen;
  680. stopslot = curslot + slotlen;
  681. ppref = amap->am_ppref;
  682. prevlcv = 0;
  683. /*
  684. * first advance to the correct place in the ppref array,
  685. * fragment if needed.
  686. */
  687. for (lcv = 0 ; lcv < curslot ; lcv += len) {
  688. pp_getreflen(ppref, lcv, &ref, &len);
  689. if (lcv + len > curslot) { /* goes past start? */
  690. pp_setreflen(ppref, lcv, ref, curslot - lcv);
  691. pp_setreflen(ppref, curslot, ref, len - (curslot -lcv));
  692. len = curslot - lcv; /* new length of entry @ lcv */
  693. }
  694. prevlcv = lcv;
  695. }
  696. if (lcv != 0)
  697. pp_getreflen(ppref, prevlcv, &prevref, &prevlen);
  698. else {
  699. /* Ensure that the "prevref == ref" test below always
  700. * fails, since we're starting from the beginning of
  701. * the ppref array; that is, there is no previous
  702. * chunk.
  703. */
  704. prevref = -1;
  705. prevlen = 0;
  706. }
  707. /*
  708. * now adjust reference counts in range. merge the first
  709. * changed entry with the last unchanged entry if possible.
  710. */
  711. if (lcv != curslot)
  712. panic("amap_pp_adjref: overshot target");
  713. for (/* lcv already set */; lcv < stopslot ; lcv += len) {
  714. pp_getreflen(ppref, lcv, &ref, &len);
  715. if (lcv + len > stopslot) { /* goes past end? */
  716. pp_setreflen(ppref, lcv, ref, stopslot - lcv);
  717. pp_setreflen(ppref, stopslot, ref,
  718. len - (stopslot - lcv));
  719. len = stopslot - lcv;
  720. }
  721. ref += adjval;
  722. if (ref < 0)
  723. panic("amap_pp_adjref: negative reference count");
  724. if (lcv == prevlcv + prevlen && ref == prevref) {
  725. pp_setreflen(ppref, prevlcv, ref, prevlen + len);
  726. } else {
  727. pp_setreflen(ppref, lcv, ref, len);
  728. }
  729. if (ref == 0)
  730. amap_wiperange(amap, lcv, len);
  731. }
  732. }
  733. /*
  734. * amap_wiperange: wipe out a range of an amap
  735. * [different from amap_wipeout because the amap is kept intact]
  736. */
  737. void
  738. amap_wiperange(struct vm_amap *amap, int slotoff, int slots)
  739. {
  740. int byanon, lcv, stop, curslot, ptr, slotend;
  741. struct vm_anon *anon;
  742. /*
  743. * we can either traverse the amap by am_anon or by am_slots depending
  744. * on which is cheaper. decide now.
  745. */
  746. if (slots < amap->am_nused) {
  747. byanon = TRUE;
  748. lcv = slotoff;
  749. stop = slotoff + slots;
  750. } else {
  751. byanon = FALSE;
  752. lcv = 0;
  753. stop = amap->am_nused;
  754. slotend = slotoff + slots;
  755. }
  756. while (lcv < stop) {
  757. int refs;
  758. if (byanon) {
  759. curslot = lcv++; /* lcv advances here */
  760. if (amap->am_anon[curslot] == NULL)
  761. continue;
  762. } else {
  763. curslot = amap->am_slots[lcv];
  764. if (curslot < slotoff || curslot >= slotend) {
  765. lcv++; /* lcv advances here */
  766. continue;
  767. }
  768. stop--; /* drop stop, since anon will be removed */
  769. }
  770. anon = amap->am_anon[curslot];
  771. /* remove it from the amap */
  772. amap->am_anon[curslot] = NULL;
  773. ptr = amap->am_bckptr[curslot];
  774. if (ptr != (amap->am_nused - 1)) {
  775. amap->am_slots[ptr] =
  776. amap->am_slots[amap->am_nused - 1];
  777. amap->am_bckptr[amap->am_slots[ptr]] =
  778. ptr; /* back ptr. */
  779. }
  780. amap->am_nused--;
  781. /* drop anon reference count */
  782. refs = --anon->an_ref;
  783. if (refs == 0) {
  784. /*
  785. * we just eliminated the last reference to an anon.
  786. * free it.
  787. */
  788. uvm_anfree(anon);
  789. }
  790. }
  791. }
  792. #endif
  793. /*
  794. * amap_swap_off: pagein anonymous pages in amaps and drop swap slots.
  795. *
  796. * => note that we don't always traverse all anons.
  797. * eg. amaps being wiped out, released anons.
  798. * => return TRUE if failed.
  799. */
  800. boolean_t
  801. amap_swap_off(int startslot, int endslot)
  802. {
  803. struct vm_amap *am;
  804. struct vm_amap *am_next;
  805. struct vm_amap marker_prev;
  806. struct vm_amap marker_next;
  807. boolean_t rv = FALSE;
  808. #if defined(DIAGNOSTIC)
  809. memset(&marker_prev, 0, sizeof(marker_prev));
  810. memset(&marker_next, 0, sizeof(marker_next));
  811. #endif /* defined(DIAGNOSTIC) */
  812. for (am = LIST_FIRST(&amap_list); am != NULL && !rv; am = am_next) {
  813. int i;
  814. LIST_INSERT_BEFORE(am, &marker_prev, am_list);
  815. LIST_INSERT_AFTER(am, &marker_next, am_list);
  816. if (am->am_nused <= 0) {
  817. goto next;
  818. }
  819. for (i = 0; i < am->am_nused; i++) {
  820. int slot;
  821. int swslot;
  822. struct vm_anon *anon;
  823. slot = am->am_slots[i];
  824. anon = am->am_anon[slot];
  825. swslot = anon->an_swslot;
  826. if (swslot < startslot || endslot <= swslot) {
  827. continue;
  828. }
  829. am->am_flags |= AMAP_SWAPOFF;
  830. rv = uvm_anon_pagein(anon);
  831. am->am_flags &= ~AMAP_SWAPOFF;
  832. if (amap_refs(am) == 0) {
  833. amap_wipeout(am);
  834. am = NULL;
  835. break;
  836. }
  837. if (rv) {
  838. break;
  839. }
  840. i = 0;
  841. }
  842. next:
  843. KASSERT(LIST_NEXT(&marker_prev, am_list) == &marker_next ||
  844. LIST_NEXT(LIST_NEXT(&marker_prev, am_list), am_list) ==
  845. &marker_next);
  846. am_next = LIST_NEXT(&marker_next, am_list);
  847. LIST_REMOVE(&marker_prev, am_list);
  848. LIST_REMOVE(&marker_next, am_list);
  849. }
  850. return rv;
  851. }
  852. /*
  853. * amap_lookup: look up a page in an amap
  854. */
  855. struct vm_anon *
  856. amap_lookup(struct vm_aref *aref, vaddr_t offset)
  857. {
  858. int slot;
  859. struct vm_amap *amap = aref->ar_amap;
  860. AMAP_B2SLOT(slot, offset);
  861. slot += aref->ar_pageoff;
  862. if (slot >= amap->am_nslot)
  863. panic("amap_lookup: offset out of range");
  864. return(amap->am_anon[slot]);
  865. }
  866. /*
  867. * amap_lookups: look up a range of pages in an amap
  868. *
  869. * => XXXCDC: this interface is biased toward array-based amaps. fix.
  870. */
  871. void
  872. amap_lookups(struct vm_aref *aref, vaddr_t offset,
  873. struct vm_anon **anons, int npages)
  874. {
  875. int slot;
  876. struct vm_amap *amap = aref->ar_amap;
  877. AMAP_B2SLOT(slot, offset);
  878. slot += aref->ar_pageoff;
  879. if ((slot + (npages - 1)) >= amap->am_nslot)
  880. panic("amap_lookups: offset out of range");
  881. memcpy(anons, &amap->am_anon[slot], npages * sizeof(struct vm_anon *));
  882. return;
  883. }
  884. /*
  885. * amap_add: add (or replace) a page to an amap
  886. *
  887. * => returns an "offset" which is meaningful to amap_unadd().
  888. */
  889. void
  890. amap_add(struct vm_aref *aref, vaddr_t offset, struct vm_anon *anon,
  891. boolean_t replace)
  892. {
  893. int slot;
  894. struct vm_amap *amap = aref->ar_amap;
  895. AMAP_B2SLOT(slot, offset);
  896. slot += aref->ar_pageoff;
  897. if (slot >= amap->am_nslot)
  898. panic("amap_add: offset out of range");
  899. if (replace) {
  900. if (amap->am_anon[slot] == NULL)
  901. panic("amap_add: replacing null anon");
  902. if (amap->am_anon[slot]->an_page != NULL &&
  903. (amap->am_flags & AMAP_SHARED) != 0) {
  904. pmap_page_protect(amap->am_anon[slot]->an_page,
  905. PROT_NONE);
  906. /*
  907. * XXX: suppose page is supposed to be wired somewhere?
  908. */
  909. }
  910. } else { /* !replace */
  911. if (amap->am_anon[slot] != NULL)
  912. panic("amap_add: slot in use");
  913. amap->am_bckptr[slot] = amap->am_nused;
  914. amap->am_slots[amap->am_nused] = slot;
  915. amap->am_nused++;
  916. }
  917. amap->am_anon[slot] = anon;
  918. }
  919. /*
  920. * amap_unadd: remove a page from an amap
  921. */
  922. void
  923. amap_unadd(struct vm_aref *aref, vaddr_t offset)
  924. {
  925. int ptr, slot;
  926. struct vm_amap *amap = aref->ar_amap;
  927. AMAP_B2SLOT(slot, offset);
  928. slot += aref->ar_pageoff;
  929. if (slot >= amap->am_nslot)
  930. panic("amap_unadd: offset out of range");
  931. if (amap->am_anon[slot] == NULL)
  932. panic("amap_unadd: nothing there");
  933. amap->am_anon[slot] = NULL;
  934. ptr = amap->am_bckptr[slot];
  935. if (ptr != (amap->am_nused - 1)) { /* swap to keep slots contig? */
  936. amap->am_slots[ptr] = amap->am_slots[amap->am_nused - 1];
  937. amap->am_bckptr[amap->am_slots[ptr]] = ptr; /* back link */
  938. }
  939. amap->am_nused--;
  940. }
  941. /*
  942. * amap_ref: gain a reference to an amap
  943. *
  944. * => "offset" and "len" are in units of pages
  945. * => called at fork time to gain the child's reference
  946. */
  947. void
  948. amap_ref(struct vm_amap *amap, vaddr_t offset, vsize_t len, int flags)
  949. {
  950. amap->am_ref++;
  951. if (flags & AMAP_SHARED)
  952. amap->am_flags |= AMAP_SHARED;
  953. #ifdef UVM_AMAP_PPREF
  954. if (amap->am_ppref == NULL && (flags & AMAP_REFALL) == 0 &&
  955. len != amap->am_nslot)
  956. amap_pp_establish(amap);
  957. if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  958. if (flags & AMAP_REFALL)
  959. amap_pp_adjref(amap, 0, amap->am_nslot, 1);
  960. else
  961. amap_pp_adjref(amap, offset, len, 1);
  962. }
  963. #endif
  964. }
  965. /*
  966. * amap_unref: remove a reference to an amap
  967. *
  968. * => caller must remove all pmap-level references to this amap before
  969. * dropping the reference
  970. * => called from uvm_unmap_detach [only] ... note that entry is no
  971. * longer part of a map
  972. */
  973. void
  974. amap_unref(struct vm_amap *amap, vaddr_t offset, vsize_t len, boolean_t all)
  975. {
  976. /* if we are the last reference, free the amap and return. */
  977. if (amap->am_ref-- == 1) {
  978. amap_wipeout(amap); /* drops final ref and frees */
  979. return;
  980. }
  981. /* otherwise just drop the reference count(s) */
  982. if (amap->am_ref == 1 && (amap->am_flags & AMAP_SHARED) != 0)
  983. amap->am_flags &= ~AMAP_SHARED; /* clear shared flag */
  984. #ifdef UVM_AMAP_PPREF
  985. if (amap->am_ppref == NULL && all == 0 && len != amap->am_nslot)
  986. amap_pp_establish(amap);
  987. if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
  988. if (all)
  989. amap_pp_adjref(amap, 0, amap->am_nslot, -1);
  990. else
  991. amap_pp_adjref(amap, offset, len, -1);
  992. }
  993. #endif
  994. }