pager.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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*)
  37. {
  38. panic("putswap");
  39. }
  40. void
  41. dupswap(Page*)
  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);
  56. if(s->ref == 1) { /* Easy if we are the only user */
  57. s->ref++;
  58. unlock(s);
  59. return canpage(p);
  60. }
  61. s->ref++;
  62. unlock(s);
  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. int i, size, n;
  83. Pte *l;
  84. Page **pg, *entry;
  85. if((s->type&SG_TYPE) != SG_TEXT)
  86. panic("pageout");
  87. if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
  88. return 0;
  89. if(s->steal){ /* Protected by /dev/proc */
  90. qunlock(&s->lk);
  91. return 0;
  92. }
  93. if(!canflush(p, s)){ /* Able to invalidate all tlbs with references */
  94. qunlock(&s->lk);
  95. putseg(s);
  96. return 0;
  97. }
  98. if(waserror()){
  99. qunlock(&s->lk);
  100. putseg(s);
  101. return 0;
  102. }
  103. /* Pass through the pte tables looking for text memory pages to put */
  104. n = 0;
  105. size = s->mapsize;
  106. for(i = 0; i < size; i++){
  107. l = s->map[i];
  108. if(l == 0)
  109. continue;
  110. for(pg = l->first; pg < l->last; pg++){
  111. entry = *pg;
  112. if(pagedout(entry))
  113. continue;
  114. n++;
  115. if(entry->modref & PG_REF){
  116. entry->modref &= ~PG_REF;
  117. continue;
  118. }
  119. putpage(*pg);
  120. *pg = nil;
  121. }
  122. }
  123. poperror();
  124. qunlock(&s->lk);
  125. putseg(s);
  126. return n;
  127. }
  128. static void
  129. pageouttext(int pgszi, int color)
  130. {
  131. Proc *p;
  132. Pgsza *pa;
  133. int i, n, np, x;
  134. Segment *s;
  135. int prepaged;
  136. USED(color);
  137. pa = &pga.pgsza[pgszi];
  138. n = x = 0;
  139. prepaged = 0;
  140. /*
  141. * Try first to steal text pages from non-prepaged processes,
  142. * then from anyone.
  143. */
  144. Again:
  145. do{
  146. if((p = psincref(x)) == nil)
  147. break;
  148. np = 0;
  149. if(p->prepagemem == 0 || prepaged != 0)
  150. if(p->state != Dead && p->noswap == 0 && canqlock(&p->seglock)){
  151. for(i = 0; i < NSEG; i++){
  152. if((s = p->seg[i]) == nil)
  153. continue;
  154. if((s->type&SG_TYPE) == SG_TEXT)
  155. np = pageout(p, s);
  156. }
  157. qunlock(&p->seglock);
  158. }
  159. /*
  160. * else process dead or locked or changing its segments
  161. */
  162. psdecref(p);
  163. n += np;
  164. if(np > 0)
  165. DBG("pager: %d from proc #%d %#p\n", np, x, p);
  166. x++;
  167. }while(pa->freecount < Minpages);
  168. if(pa->freecount < Minpages && prepaged++ == 0)
  169. goto Again;
  170. }
  171. static void
  172. freepages(int si, int once)
  173. {
  174. Pgsza *pa;
  175. Page *p;
  176. for(; si < m->npgsz; si++){
  177. pa = &pga.pgsza[si];
  178. if(pa->freecount > 0){
  179. DBG("kickpager() up %#p: releasing %udK pages\n",
  180. up, m->pgsz[si]/KiB);
  181. lock(&pga);
  182. if(pa->freecount == 0){
  183. unlock(&pga);
  184. continue;
  185. }
  186. p = pa->head;
  187. pageunchain(p);
  188. unlock(&pga);
  189. if(p->ref != 0)
  190. panic("freepages pa %#ullx", p->pa);
  191. pgfree(p);
  192. if(once)
  193. break;
  194. }
  195. }
  196. }
  197. static int
  198. tryalloc(int pgszi, int color)
  199. {
  200. Page *p;
  201. p = pgalloc(m->pgsz[pgszi], color);
  202. if(p != nil){
  203. lock(&pga);
  204. pagechainhead(p);
  205. unlock(&pga);
  206. return 0;
  207. }
  208. return -1;
  209. }
  210. static int
  211. hascolor(Page *pl, int color)
  212. {
  213. Page *p;
  214. lock(&pga);
  215. for(p = pl; p != nil; p = p->next)
  216. if(color == NOCOLOR || p->color == color){
  217. unlock(&pga);
  218. return 1;
  219. }
  220. unlock(&pga);
  221. return 0;
  222. }
  223. /*
  224. * Someone couldn't find pages of the given size index and color.
  225. * (color may be NOCOLOR if the caller is trying to get any page
  226. * and is desperate).
  227. * Many processes may be calling this at the same time,
  228. * The first one operates as a pager and does what it can.
  229. */
  230. void
  231. kickpager(int pgszi, int color)
  232. {
  233. Pgsza *pa;
  234. if(DBGFLG>1)
  235. DBG("kickpager() %#p\n", up);
  236. if(waserror())
  237. panic("error in kickpager");
  238. qlock(&pagerlck);
  239. pa = &pga.pgsza[pgszi];
  240. /*
  241. * 1. did anyone else release one for us in the mean time?
  242. */
  243. if(hascolor(pa->head, color))
  244. goto Done;
  245. /*
  246. * 2. try allocating from physical memory
  247. */
  248. tryalloc(pgszi, color);
  249. if(hascolor(pa->head, color))
  250. goto Done;
  251. /*
  252. * If pgszi is <= text page size, try releasing text pages.
  253. */
  254. if(m->pgsz[pgszi] <= 2*MiB){
  255. pstats.ntext++;
  256. DBG("kickpager() up %#p: reclaiming text pages\n", up);
  257. pageouttext(pgszi, color);
  258. tryalloc(pgszi, color);
  259. if(hascolor(pa->head, color)){
  260. DBG("kickpager() found %uld free\n", pa->freecount);
  261. goto Done;
  262. }
  263. }
  264. /*
  265. * Try releasing memory from bigger pages.
  266. */
  267. pstats.nbig++;
  268. freepages(pgszi+1, 1);
  269. tryalloc(pgszi, color);
  270. if(hascolor(pa->head, color)){
  271. DBG("kickpager() found %uld free\n", pa->freecount);
  272. goto Done;
  273. }
  274. /*
  275. * Really the last resort. Try releasing memory from all pages.
  276. */
  277. pstats.nall++;
  278. DBG("kickpager() up %#p: releasing all pages\n", up);
  279. freepages(0, 0);
  280. tryalloc(pgszi, color);
  281. if(pa->freecount > 0){
  282. DBG("kickpager() found %uld free\n", pa->freecount);
  283. goto Done;
  284. }
  285. /*
  286. * What else can we do?
  287. * But don't panic if we are still trying to get memory of
  288. * a particular color and there's none. We'll retry asking
  289. * for any color.
  290. */
  291. if(color == NOCOLOR)
  292. panic("kickpager(): no physical memory");
  293. Done:
  294. poperror();
  295. qunlock(&pagerlck);
  296. if(DBGFLG>1)
  297. DBG("kickpager() done %#p\n", up);
  298. }
  299. void
  300. pagersummary(void)
  301. {
  302. print("ntext %uld nbig %uld nall %uld\n",
  303. pstats.ntext, pstats.nbig, pstats.nall);
  304. print("no swap\n");
  305. }