swap.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. static int canflush(Proc*, Segment*);
  8. static void executeio(void);
  9. static int needpages(void*);
  10. static void pageout(Proc*, Segment*);
  11. static void pagepte(int, Page**);
  12. static void pager(void*);
  13. Image swapimage;
  14. static int swopen;
  15. static Page **iolist;
  16. static int ioptr;
  17. void
  18. swapinit(void)
  19. {
  20. swapalloc.swmap = xalloc(conf.nswap);
  21. swapalloc.top = &swapalloc.swmap[conf.nswap];
  22. swapalloc.alloc = swapalloc.swmap;
  23. swapalloc.last = swapalloc.swmap;
  24. swapalloc.free = conf.nswap;
  25. iolist = xalloc(conf.nswppo*sizeof(Page*));
  26. if(swapalloc.swmap == 0 || iolist == 0)
  27. panic("swapinit: not enough memory");
  28. swapimage.notext = 1;
  29. }
  30. ulong
  31. newswap(void)
  32. {
  33. uchar *look;
  34. lock(&swapalloc);
  35. if(swapalloc.free == 0){
  36. unlock(&swapalloc);
  37. return ~0;
  38. }
  39. look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
  40. if(look == 0)
  41. panic("inconsistent swap");
  42. *look = 1;
  43. swapalloc.last = look;
  44. swapalloc.free--;
  45. unlock(&swapalloc);
  46. return (look-swapalloc.swmap) * BY2PG;
  47. }
  48. void
  49. putswap(Page *p)
  50. {
  51. uchar *idx;
  52. lock(&swapalloc);
  53. idx = &swapalloc.swmap[((ulong)p)/BY2PG];
  54. if(--(*idx) == 0) {
  55. swapalloc.free++;
  56. if(idx < swapalloc.last)
  57. swapalloc.last = idx;
  58. }
  59. if(*idx >= 254)
  60. panic("putswap %lux == %ud", p, *idx);
  61. unlock(&swapalloc);
  62. }
  63. void
  64. dupswap(Page *p)
  65. {
  66. lock(&swapalloc);
  67. if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
  68. panic("dupswap");
  69. unlock(&swapalloc);
  70. }
  71. int
  72. swapcount(ulong daddr)
  73. {
  74. return swapalloc.swmap[daddr/BY2PG];
  75. }
  76. void
  77. kickpager(void)
  78. {
  79. static int started;
  80. if(started)
  81. wakeup(&swapalloc.r);
  82. else {
  83. kproc("pager", pager, 0);
  84. started = 1;
  85. }
  86. }
  87. static void
  88. pager(void *junk)
  89. {
  90. int i;
  91. Segment *s;
  92. Proc *p, *ep;
  93. if(waserror())
  94. panic("pager: os error\n");
  95. p = proctab(0);
  96. ep = &p[conf.nproc];
  97. loop:
  98. up->psstate = "Idle";
  99. sleep(&swapalloc.r, needpages, 0);
  100. while(needpages(junk)) {
  101. if(swapimage.c) {
  102. p++;
  103. if(p >= ep)
  104. p = proctab(0);
  105. if(p->state == Dead || p->noswap)
  106. continue;
  107. if(!canqlock(&p->seglock))
  108. continue; /* process changing its segments */
  109. for(i = 0; i < NSEG; i++) {
  110. if(!needpages(junk)){
  111. qunlock(&p->seglock);
  112. goto loop;
  113. }
  114. if(s = p->seg[i]) {
  115. switch(s->type&SG_TYPE) {
  116. default:
  117. break;
  118. case SG_TEXT:
  119. pageout(p, s);
  120. break;
  121. case SG_DATA:
  122. case SG_BSS:
  123. case SG_STACK:
  124. case SG_SHARED:
  125. up->psstate = "Pageout";
  126. pageout(p, s);
  127. if(ioptr != 0) {
  128. up->psstate = "I/O";
  129. executeio();
  130. }
  131. break;
  132. }
  133. }
  134. }
  135. qunlock(&p->seglock);
  136. }
  137. else {
  138. print("out of physical memory; no swap configured\n");
  139. if(!cpuserver)
  140. freebroken(); /* can use the memory */
  141. else
  142. killbig("out of memory");
  143. /* Emulate the old system if no swap channel */
  144. tsleep(&up->sleep, return0, 0, 5000);
  145. wakeup(&palloc.r);
  146. }
  147. }
  148. goto loop;
  149. }
  150. static void
  151. pageout(Proc *p, Segment *s)
  152. {
  153. int type, i, size;
  154. Pte *l;
  155. Page **pg, *entry;
  156. if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
  157. return;
  158. if(s->steal) { /* Protected by /dev/proc */
  159. qunlock(&s->lk);
  160. return;
  161. }
  162. if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
  163. qunlock(&s->lk);
  164. putseg(s);
  165. return;
  166. }
  167. if(waserror()) {
  168. qunlock(&s->lk);
  169. putseg(s);
  170. return;
  171. }
  172. /* Pass through the pte tables looking for memory pages to swap out */
  173. type = s->type&SG_TYPE;
  174. size = s->mapsize;
  175. for(i = 0; i < size; i++) {
  176. l = s->map[i];
  177. if(l == 0)
  178. continue;
  179. for(pg = l->first; pg < l->last; pg++) {
  180. entry = *pg;
  181. if(pagedout(entry))
  182. continue;
  183. if(entry->modref & PG_REF) {
  184. entry->modref &= ~PG_REF;
  185. continue;
  186. }
  187. pagepte(type, pg);
  188. if(ioptr >= conf.nswppo)
  189. goto out;
  190. }
  191. }
  192. out:
  193. poperror();
  194. qunlock(&s->lk);
  195. putseg(s);
  196. }
  197. static int
  198. canflush(Proc *p, Segment *s)
  199. {
  200. int i;
  201. Proc *ep;
  202. lock(s);
  203. if(s->ref == 1) { /* Easy if we are the only user */
  204. s->ref++;
  205. unlock(s);
  206. return canpage(p);
  207. }
  208. s->ref++;
  209. unlock(s);
  210. /* Now we must do hardwork to ensure all processes which have tlb
  211. * entries for this segment will be flushed if we succeed in paging it out
  212. */
  213. p = proctab(0);
  214. ep = &p[conf.nproc];
  215. while(p < ep) {
  216. if(p->state != Dead) {
  217. for(i = 0; i < NSEG; i++)
  218. if(p->seg[i] == s)
  219. if(!canpage(p))
  220. return 0;
  221. }
  222. p++;
  223. }
  224. return 1;
  225. }
  226. static void
  227. pagepte(int type, Page **pg)
  228. {
  229. ulong daddr;
  230. Page *outp;
  231. outp = *pg;
  232. switch(type) {
  233. case SG_TEXT: /* Revert to demand load */
  234. putpage(outp);
  235. *pg = 0;
  236. break;
  237. case SG_DATA:
  238. case SG_BSS:
  239. case SG_STACK:
  240. case SG_SHARED:
  241. /*
  242. * get a new swap address and clear any pages
  243. * referring to it from the cache
  244. */
  245. daddr = newswap();
  246. if(daddr == ~0)
  247. break;
  248. cachedel(&swapimage, daddr);
  249. lock(outp);
  250. /* forget anything that it used to cache */
  251. uncachepage(outp);
  252. /*
  253. * incr the reference count to make sure it sticks around while
  254. * being written
  255. */
  256. outp->ref++;
  257. /*
  258. * enter it into the cache so that a fault happening
  259. * during the write will grab the page from the cache
  260. * rather than one partially written to the disk
  261. */
  262. outp->daddr = daddr;
  263. cachepage(outp, &swapimage);
  264. *pg = (Page*)(daddr|PG_ONSWAP);
  265. unlock(outp);
  266. /* Add page to IO transaction list */
  267. iolist[ioptr++] = outp;
  268. break;
  269. }
  270. }
  271. void
  272. pagersummary(void)
  273. {
  274. print("%lud/%lud memory %lud/%lud swap %d iolist\n",
  275. palloc.user-palloc.freecount,
  276. palloc.user, conf.nswap-swapalloc.free, conf.nswap,
  277. ioptr);
  278. }
  279. static void
  280. executeio(void)
  281. {
  282. Page *out;
  283. int i, n;
  284. Chan *c;
  285. char *kaddr;
  286. KMap *k;
  287. c = swapimage.c;
  288. for(i = 0; i < ioptr; i++) {
  289. if(ioptr > conf.nswppo)
  290. panic("executeio: ioptr %d > %d\n", ioptr, conf.nswppo);
  291. out = iolist[i];
  292. k = kmap(out);
  293. kaddr = (char*)VA(k);
  294. if(waserror())
  295. panic("executeio: page out I/O error");
  296. n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
  297. if(n != BY2PG)
  298. nexterror();
  299. kunmap(k);
  300. poperror();
  301. /* Free up the page after I/O */
  302. lock(out);
  303. out->ref--;
  304. unlock(out);
  305. putpage(out);
  306. }
  307. ioptr = 0;
  308. }
  309. static int
  310. needpages(void*)
  311. {
  312. return palloc.freecount < swapalloc.headroom;
  313. }
  314. void
  315. setswapchan(Chan *c)
  316. {
  317. uchar dirbuf[sizeof(Dir)+100];
  318. Dir d;
  319. int n;
  320. if(swapimage.c) {
  321. if(swapalloc.free != conf.nswap){
  322. cclose(c);
  323. error(Einuse);
  324. }
  325. cclose(swapimage.c);
  326. }
  327. /*
  328. * if this isn't a file, set the swap space
  329. * to be at most the size of the partition
  330. */
  331. if(devtab[c->type]->dc != L'M'){
  332. n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
  333. if(n <= 0){
  334. cclose(c);
  335. error("stat failed in setswapchan");
  336. }
  337. convM2D(dirbuf, n, &d, nil);
  338. if(d.length < conf.nswap*BY2PG){
  339. conf.nswap = d.length/BY2PG;
  340. swapalloc.top = &swapalloc.swmap[conf.nswap];
  341. swapalloc.free = conf.nswap;
  342. }
  343. }
  344. swapimage.c = c;
  345. }
  346. int
  347. swapfull(void)
  348. {
  349. return swapalloc.free < conf.nswap/10;
  350. }