pager.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. /*
  16. * There's no pager process here.
  17. * One process waiting for memory becomes the pager,
  18. * during the call to kickpager()
  19. */
  20. enum
  21. {
  22. Minpages = 2
  23. };
  24. static QLock pagerlck;
  25. static struct
  26. {
  27. uint32_t ntext;
  28. uint32_t nbig;
  29. uint32_t nall;
  30. } pstats;
  31. void
  32. swapinit(void)
  33. {
  34. }
  35. void
  36. putswap(Page* p)
  37. {
  38. panic("putswap");
  39. }
  40. void
  41. dupswap(Page* p)
  42. {
  43. panic("dupswap");
  44. }
  45. int
  46. swapcount(uint32_t daddr)
  47. {
  48. USED(daddr);
  49. return 0;
  50. }
  51. static int
  52. canflush(Proc *p, Segment *s)
  53. {
  54. int i, x;
  55. lock(&s->r.l);
  56. if(s->r.ref == 1) { /* Easy if we are the only user */
  57. s->r.ref++;
  58. unlock(&s->r.l);
  59. return canpage(p);
  60. }
  61. s->r.ref++;
  62. unlock(&s->r.l);
  63. /* Now we must do hardwork to ensure all processes which have tlb
  64. * entries for this segment will be flushed if we succeed in paging it out
  65. */
  66. for(x = 0; (p = psincref(x)) != nil; x++){
  67. if(p->state != Dead) {
  68. for(i = 0; i < NSEG; i++){
  69. if(p->seg[i] == s && !canpage(p)){
  70. psdecref(p);
  71. return 0;
  72. }
  73. }
  74. }
  75. psdecref(p);
  76. }
  77. return 1;
  78. }
  79. static int
  80. pageout(Proc *p, Segment *s)
  81. {
  82. Proc *up = externup();
  83. int i, size, n;
  84. Pte *l;
  85. Page **pg, *entry;
  86. if((s->type&SG_TYPE) != SG_LOAD && (s->type&SG_TYPE) != SG_TEXT)
  87. panic("pageout");
  88. if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
  89. return 0;
  90. if(s->steal){ /* Protected by /dev/proc */
  91. qunlock(&s->lk);
  92. return 0;
  93. }
  94. if(!canflush(p, s)){ /* Able to invalidate all tlbs with references */
  95. qunlock(&s->lk);
  96. putseg(s);
  97. return 0;
  98. }
  99. if(waserror()){
  100. qunlock(&s->lk);
  101. putseg(s);
  102. return 0;
  103. }
  104. /* Pass through the pte tables looking for text memory pages to put */
  105. n = 0;
  106. size = s->mapsize;
  107. for(i = 0; i < size; i++){
  108. l = s->map[i];
  109. if(l == 0)
  110. continue;
  111. for(pg = l->first; pg < l->last; pg++){
  112. entry = *pg;
  113. if(pagedout(entry))
  114. continue;
  115. n++;
  116. if(entry->modref & PG_REF){
  117. entry->modref &= ~PG_REF;
  118. continue;
  119. }
  120. putpage(*pg);
  121. *pg = nil;
  122. }
  123. }
  124. poperror();
  125. qunlock(&s->lk);
  126. putseg(s);
  127. return n;
  128. }
  129. static void
  130. pageouttext(int pgszi, int color)
  131. {
  132. Proc *p;
  133. Pgsza *pa;
  134. int i, n, np, x;
  135. Segment *s;
  136. int prepaged;
  137. USED(color);
  138. pa = &pga.pgsza[pgszi];
  139. n = x = 0;
  140. prepaged = 0;
  141. /*
  142. * Try first to steal text pages from non-prepaged processes,
  143. * then from anyone.
  144. */
  145. Again:
  146. do{
  147. if((p = psincref(x)) == nil)
  148. break;
  149. np = 0;
  150. if(p->prepagemem == 0 || prepaged != 0)
  151. if(p->state != Dead && p->noswap == 0 && canqlock(&p->seglock)){
  152. for(i = 0; i < NSEG; i++){
  153. if((s = p->seg[i]) == nil)
  154. continue;
  155. if((s->type&SG_TYPE) == SG_TEXT)
  156. np = pageout(p, s);
  157. }
  158. qunlock(&p->seglock);
  159. }
  160. /*
  161. * else process dead or locked or changing its segments
  162. */
  163. psdecref(p);
  164. n += np;
  165. if(np > 0)
  166. DBG("pager: %d from proc #%d %#p\n", np, x, p);
  167. x++;
  168. }while(pa->freecount < Minpages);
  169. if(pa->freecount < Minpages && prepaged++ == 0)
  170. goto Again;
  171. }
  172. static void
  173. freepages(int si, int once)
  174. {
  175. Proc *up = externup();
  176. Pgsza *pa;
  177. Page *p;
  178. for(; si < sys->npgsz; si++){
  179. pa = &pga.pgsza[si];
  180. if(pa->freecount > 0){
  181. DBG("kickpager() up %#p: releasing %uK pages\n",
  182. up, sys->pgsz[si]/KiB);
  183. lock(&pga.l);
  184. if(pa->freecount == 0){
  185. unlock(&pga.l);
  186. continue;
  187. }
  188. p = pa->head;
  189. pageunchain(p);
  190. unlock(&pga.l);
  191. if(p->ref != 0)
  192. panic("freepages pa %#llx", p->pa);
  193. pgfree(p);
  194. if(once)
  195. break;
  196. }
  197. }
  198. }
  199. static int
  200. tryalloc(int pgszi, int color)
  201. {
  202. Page *p;
  203. p = pgalloc(sys->pgsz[pgszi], color);
  204. if(p != nil){
  205. lock(&pga.l);
  206. pagechainhead(p);
  207. unlock(&pga.l);
  208. return 0;
  209. }
  210. return -1;
  211. }
  212. static int
  213. hascolor(Page *pl, int color)
  214. {
  215. Page *p;
  216. lock(&pga.l);
  217. for(p = pl; p != nil; p = p->next)
  218. if(color == NOCOLOR || p->color == color){
  219. unlock(&pga.l);
  220. return 1;
  221. }
  222. unlock(&pga.l);
  223. return 0;
  224. }
  225. /*
  226. * Someone couldn't find pages of the given size index and color.
  227. * (color may be NOCOLOR if the caller is trying to get any page
  228. * and is desperate).
  229. * Many processes may be calling this at the same time,
  230. * The first one operates as a pager and does what it can.
  231. */
  232. void
  233. kickpager(int pgszi, int color)
  234. {
  235. Proc *up = externup();
  236. Pgsza *pa;
  237. if(DBGFLG>1)
  238. DBG("kickpager() %#p\n", up);
  239. if(waserror())
  240. panic("error in kickpager");
  241. qlock(&pagerlck);
  242. pa = &pga.pgsza[pgszi];
  243. /*
  244. * 1. did anyone else release one for us in the mean time?
  245. */
  246. if(hascolor(pa->head, color))
  247. goto Done;
  248. /*
  249. * 2. try allocating from physical memory
  250. */
  251. tryalloc(pgszi, color);
  252. if(hascolor(pa->head, color))
  253. goto Done;
  254. /*
  255. * If pgszi is <= text page size, try releasing text pages.
  256. */
  257. if(sys->pgsz[pgszi] <= 2*MiB){
  258. pstats.ntext++;
  259. DBG("kickpager() up %#p: reclaiming text pages\n", up);
  260. pageouttext(pgszi, color);
  261. tryalloc(pgszi, color);
  262. if(hascolor(pa->head, color)){
  263. DBG("kickpager() found %lu free\n", pa->freecount);
  264. goto Done;
  265. }
  266. }
  267. /*
  268. * Try releasing memory from bigger pages.
  269. */
  270. pstats.nbig++;
  271. freepages(pgszi+1, 1);
  272. tryalloc(pgszi, color);
  273. if(hascolor(pa->head, color)){
  274. DBG("kickpager() found %lu free\n", pa->freecount);
  275. goto Done;
  276. }
  277. /*
  278. * Really the last resort. Try releasing memory from all pages.
  279. */
  280. pstats.nall++;
  281. DBG("kickpager() up %#p: releasing all pages\n", up);
  282. freepages(0, 0);
  283. tryalloc(pgszi, color);
  284. if(pa->freecount > 0){
  285. DBG("kickpager() found %lu free\n", pa->freecount);
  286. goto Done;
  287. }
  288. /*
  289. * What else can we do?
  290. * But don't panic if we are still trying to get memory of
  291. * a particular color and there's none. We'll retry asking
  292. * for any color.
  293. */
  294. if(color == NOCOLOR)
  295. panic("kickpager(): no physical memory");
  296. Done:
  297. poperror();
  298. qunlock(&pagerlck);
  299. if(DBGFLG>1)
  300. DBG("kickpager() done %#p\n", up);
  301. }
  302. void
  303. pagersummary(void)
  304. {
  305. print("ntext %lu nbig %lu nall %lu\n",
  306. pstats.ntext, pstats.nbig, pstats.nall);
  307. print("no swap\n");
  308. }