1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)vm_swap.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "../machine/pte.h" 10: 11: #include "param.h" 12: #include "systm.h" 13: #include "dir.h" 14: #include "user.h" 15: #include "proc.h" 16: #include "text.h" 17: #include "map.h" 18: #include "buf.h" 19: #include "cmap.h" 20: #include "vm.h" 21: 22: /* 23: * Swap a process in. 24: */ 25: swapin(p) 26: register struct proc *p; 27: { 28: register struct text *xp; 29: register int i, s; 30: 31: if (xp = p->p_textp) 32: xlock(xp); 33: p->p_szpt = clrnd(ctopt(p->p_ssize+p->p_dsize+p->p_tsize+UPAGES)); 34: if (vgetpt(p, memall) == 0) 35: goto nomem; 36: if (vgetu(p, memall, Swapmap, &swaputl, (struct user *)0) == 0) { 37: vrelpt(p); 38: goto nomem; 39: } 40: 41: swdspt(p, &swaputl, B_READ); 42: /* 43: * Make sure swdspt didn't smash u. pte's 44: */ 45: for (i = 0; i < UPAGES; i++) { 46: if (Swapmap[i].pg_pfnum != p->p_addr[i].pg_pfnum) 47: panic("swapin"); 48: } 49: vrelswu(p, &swaputl); 50: if (xp) { 51: xlink(p); 52: xunlock(xp); 53: } 54: 55: p->p_rssize = 0; 56: s = splclock(); 57: if (p->p_stat == SRUN) 58: setrq(p); 59: p->p_flag |= SLOAD; 60: if (p->p_flag & SSWAP) { 61: swaputl.u_pcb.pcb_sswap = (int *)&u.u_ssave; 62: p->p_flag &= ~SSWAP; 63: } 64: splx(s); 65: p->p_time = 0; 66: multprog++; 67: cnt.v_swpin++; 68: return (1); 69: 70: nomem: 71: if (xp) 72: xunlock(xp); 73: return (0); 74: } 75: 76: int xswapwant, xswaplock; 77: /* 78: * Swap out process p. 79: * ds and ss are the old data size and the stack size 80: * of the process, and are supplied during page table 81: * expansion swaps. 82: */ 83: swapout(p, ds, ss) 84: register struct proc *p; 85: size_t ds, ss; 86: { 87: register struct pte *map; 88: register struct user *utl; 89: int s; 90: int rc = 1; 91: 92: s = 1; 93: map = Xswapmap; 94: utl = &xswaputl; 95: if (xswaplock & s) 96: if ((xswaplock & 2) == 0) { 97: s = 2; 98: map = Xswap2map; 99: utl = &xswap2utl; 100: } 101: while (xswaplock & s) { 102: xswapwant |= s; 103: sleep((caddr_t)map, PSWP); 104: } 105: xswaplock |= s; 106: uaccess(p, map, utl); 107: if (vgetswu(p, utl) == 0) { 108: p->p_flag |= SLOAD; 109: rc = 0; 110: goto out; 111: } 112: utl->u_ru.ru_nswap++; 113: utl->u_odsize = ds; 114: utl->u_ossize = ss; 115: p->p_flag |= SLOCK; 116: if (p->p_textp) { 117: if (p->p_textp->x_ccount == 1) 118: p->p_textp->x_swrss = p->p_textp->x_rssize; 119: xdetach(p->p_textp, p); 120: } 121: p->p_swrss = p->p_rssize; 122: vsswap(p, dptopte(p, 0), CDATA, 0, (int)ds, &utl->u_dmap); 123: vsswap(p, sptopte(p, CLSIZE-1), CSTACK, 0, (int)ss, &utl->u_smap); 124: if (p->p_rssize != 0) 125: panic("swapout rssize"); 126: 127: swdspt(p, utl, B_WRITE); 128: /* 129: * If freeing the user structure and kernel stack 130: * for the current process, have to run a bit longer 131: * using the pages which are about to be freed... 132: * vrelu will then block memory allocation by raising ipl. 133: */ 134: vrelu(p, 1); 135: if ((p->p_flag & SLOAD) && (p->p_stat != SRUN || p != u.u_procp)) 136: panic("swapout"); 137: p->p_flag &= ~SLOAD; 138: vrelpt(p); 139: p->p_flag &= ~SLOCK; 140: p->p_time = 0; 141: 142: multprog--; 143: cnt.v_swpout++; 144: 145: if (runout) { 146: runout = 0; 147: wakeup((caddr_t)&runout); 148: } 149: out: 150: xswaplock &= ~s; 151: if (xswapwant & s) { 152: xswapwant &= ~s; 153: wakeup((caddr_t)map); 154: } 155: return (rc); 156: } 157: 158: /* 159: * Swap the data and stack page tables in or out. 160: * Only hard thing is swapping out when new pt size is different than old. 161: * If we are growing new pt pages, then we must spread pages with 2 swaps. 162: * If we are shrinking pt pages, then we must merge stack pte's into last 163: * data page so as not to lose them (and also do two swaps). 164: */ 165: swdspt(p, utl, rdwri) 166: register struct proc *p; 167: register struct user *utl; 168: { 169: register int szpt, tsz, ssz; 170: int tdlast, slast, tdsz; 171: register struct pte *pte; 172: register int i; 173: 174: szpt = clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)); 175: tsz = p->p_tsize / NPTEPG; 176: if (szpt == p->p_szpt) { 177: swptstat.pteasy++; 178: swpt(rdwri, p, 0, tsz, 179: (p->p_szpt - tsz) * NBPG - UPAGES * sizeof (struct pte)); 180: goto check; 181: } 182: if (szpt < p->p_szpt) 183: swptstat.ptshrink++; 184: else 185: swptstat.ptexpand++; 186: ssz = clrnd(ctopt(utl->u_ossize+UPAGES)); 187: if (szpt < p->p_szpt && utl->u_odsize && (utl->u_ossize+UPAGES)) { 188: /* 189: * Page tables shrinking... see if last text+data and 190: * last stack page must be merged... if so, copy 191: * stack pte's from last stack page to end of last 192: * data page, and decrease size of stack pt to be swapped. 193: */ 194: tdlast = (p->p_tsize + utl->u_odsize) % (NPTEPG * CLSIZE); 195: slast = (utl->u_ossize + UPAGES) % (NPTEPG * CLSIZE); 196: if (tdlast && slast && tdlast + slast <= (NPTEPG * CLSIZE)) { 197: swptstat.ptpack++; 198: tdsz = clrnd(ctopt(p->p_tsize + utl->u_odsize)); 199: bcopy((caddr_t)sptopte(p, utl->u_ossize - 1), 200: (caddr_t)&p->p_p0br[tdsz * NPTEPG - slast], 201: (unsigned)(slast * sizeof (struct pte))); 202: ssz -= CLSIZE; 203: } 204: } 205: if (ssz) 206: swpt(rdwri, p, szpt - ssz - tsz, p->p_szpt - ssz, ssz * NBPG); 207: if (utl->u_odsize) 208: swpt(rdwri, p, 0, tsz, 209: (int)(clrnd(ctopt(p->p_tsize + utl->u_odsize)) - tsz) * NBPG); 210: check: 211: for (i = 0; i < utl->u_odsize; i++) { 212: pte = dptopte(p, i); 213: if (pte->pg_v || pte->pg_fod == 0 && (pte->pg_pfnum||pte->pg_m)) 214: panic("swdspt"); 215: } 216: for (i = 0; i < utl->u_ossize; i++) { 217: pte = sptopte(p, i); 218: if (pte->pg_v || pte->pg_fod == 0 && (pte->pg_pfnum||pte->pg_m)) 219: panic("swdspt"); 220: } 221: } 222: 223: /* 224: * Swap a section of the page tables. 225: * Errors are handled at a lower level (by doing a panic). 226: */ 227: swpt(rdwri, p, doff, a, n) 228: int rdwri; 229: struct proc *p; 230: int doff, a, n; 231: { 232: 233: if (n <= 0) 234: return; 235: (void)swap(p, p->p_swaddr + ctod(UPAGES) + ctod(doff), 236: (caddr_t)&p->p_p0br[a * NPTEPG], n, rdwri, B_PAGET, swapdev, 0); 237: }