|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)vm_drum.c 7.8 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "proc.h" ! 27: #include "buf.h" ! 28: #include "text.h" ! 29: #include "map.h" ! 30: #include "vm.h" ! 31: #include "cmap.h" ! 32: #include "kernel.h" ! 33: ! 34: #include "machine/pte.h" ! 35: ! 36: /* ! 37: * Expand the swap area for both the data and stack segments. ! 38: * If space is not available for both, retract and return ENOMEM. ! 39: */ ! 40: swpexpand(ds, ss, dmp, smp) ! 41: segsz_t ds, ss; ! 42: register struct dmap *dmp, *smp; ! 43: { ! 44: register struct dmap *tmp; ! 45: register int ts; ! 46: segsz_t ods; ! 47: ! 48: /* ! 49: * If dmap isn't growing, do smap first. ! 50: * This avoids anomalies if smap will try to grow and ! 51: * fail, which otherwise would shrink ds without expanding ! 52: * ss, a rather curious side effect! ! 53: */ ! 54: if (dmp->dm_alloc > ctod(ds)) { ! 55: tmp = dmp; ts = ds; ! 56: dmp = smp; ds = ss; ! 57: smp = tmp; ss = ts; ! 58: } ! 59: ods = dtoc(dmp->dm_size); ! 60: if (vsexpand(ds, dmp, 0) == 0) ! 61: return (ENOMEM); ! 62: if (vsexpand(ss, smp, 0) == 0) { ! 63: /* flush text cache and try again */ ! 64: if (xpurge() && vsexpand(ss, smp, 0)) ! 65: return (0); ! 66: (void) vsexpand(ods, dmp, 1); ! 67: return (ENOMEM); ! 68: } ! 69: return (0); ! 70: } ! 71: ! 72: /* ! 73: * Expand or contract the virtual swap segment mapped ! 74: * by the argument diskmap so as to just allow the given size. ! 75: * ! 76: * FOR NOW CANT RELEASE UNLESS SHRINKING TO ZERO, SINCE PAGEOUTS MAY ! 77: * BE IN PROGRESS... TYPICALLY NEVER SHRINK ANYWAYS, SO DOESNT MATTER MUCH ! 78: */ ! 79: vsexpand(vssize, dmp, canshrink) ! 80: register segsz_t vssize; ! 81: register struct dmap *dmp; ! 82: { ! 83: register long blk = dmmin; ! 84: register int vsbase = 0; ! 85: register swblk_t *ip = dmp->dm_map; ! 86: segsz_t oldsize = dmp->dm_size; ! 87: segsz_t oldalloc = dmp->dm_alloc; ! 88: ! 89: vssize = ctod(vssize); ! 90: while (vsbase < oldalloc || vsbase < vssize) { ! 91: if (ip - dmp->dm_map >= NDMAP) ! 92: panic("vmdrum NDMAP"); ! 93: if (vsbase >= oldalloc) { ! 94: *ip = rmalloc(swapmap, blk); ! 95: if (*ip == 0) { ! 96: dmp->dm_size = vsbase; ! 97: if (vsexpand(dtoc(oldsize), dmp, 1) == 0) ! 98: panic("vsexpand"); ! 99: return (0); ! 100: } ! 101: dmp->dm_alloc += blk; ! 102: } else if (vssize == 0 || ! 103: vsbase >= vssize && canshrink) { ! 104: rmfree(swapmap, blk, *ip); ! 105: *ip = 0; ! 106: dmp->dm_alloc -= blk; ! 107: } ! 108: vsbase += blk; ! 109: if (blk < dmmax) ! 110: blk *= 2; ! 111: ip++; ! 112: } ! 113: dmp->dm_size = vssize; ! 114: return (1); ! 115: } ! 116: ! 117: /* ! 118: * Allocate swap space for a text segment, ! 119: * in chunks of at most dmtext pages. ! 120: */ ! 121: vsxalloc(xp) ! 122: struct text *xp; ! 123: { ! 124: register long blk; ! 125: register swblk_t *dp; ! 126: swblk_t vsbase; ! 127: ! 128: if (ctod(xp->x_size) > NXDAD * dmtext) ! 129: return (0); ! 130: dp = xp->x_daddr; ! 131: for (vsbase = 0; vsbase < ctod(xp->x_size); vsbase += dmtext) { ! 132: blk = ctod(xp->x_size) - vsbase; ! 133: if (blk > dmtext) ! 134: blk = dmtext; ! 135: if ((*dp++ = rmalloc(swapmap, blk)) == 0) { ! 136: vsxfree(xp, dtoc(vsbase)); ! 137: return (0); ! 138: } ! 139: } ! 140: if (xp->x_flag & XPAGV) { ! 141: xp->x_ptdaddr = ! 142: rmalloc(swapmap, (long)ctod(clrnd(ctopt(xp->x_size)))); ! 143: if (xp->x_ptdaddr == 0) { ! 144: vsxfree(xp, (long)xp->x_size); ! 145: return (0); ! 146: } ! 147: } ! 148: return (1); ! 149: } ! 150: ! 151: /* ! 152: * Free the swap space of a text segment which ! 153: * has been allocated ts pages. ! 154: */ ! 155: vsxfree(xp, ts) ! 156: struct text *xp; ! 157: long ts; ! 158: { ! 159: register long blk; ! 160: register swblk_t *dp; ! 161: swblk_t vsbase; ! 162: ! 163: ts = ctod(ts); ! 164: dp = xp->x_daddr; ! 165: for (vsbase = 0; vsbase < ts; vsbase += dmtext) { ! 166: blk = ts - vsbase; ! 167: if (blk > dmtext) ! 168: blk = dmtext; ! 169: rmfree(swapmap, blk, *dp); ! 170: *dp++ = 0; ! 171: } ! 172: if ((xp->x_flag&XPAGV) && xp->x_ptdaddr) { ! 173: rmfree(swapmap, (long)ctod(clrnd(ctopt(xp->x_size))), ! 174: xp->x_ptdaddr); ! 175: xp->x_ptdaddr = 0; ! 176: } ! 177: } ! 178: ! 179: /* ! 180: * Swap a segment of virtual memory to disk, ! 181: * by locating the contiguous dirty pte's ! 182: * and calling vschunk with each chunk. ! 183: * We ignore swap errors here because swap() ! 184: * will panic on an error when writing to disk. ! 185: */ ! 186: vsswap(p, pte, type, vsbase, vscount, dmp) ! 187: struct proc *p; ! 188: register struct pte *pte; ! 189: int type; ! 190: register int vsbase, vscount; ! 191: struct dmap *dmp; ! 192: { ! 193: register int size = 0; ! 194: register struct cmap *c; ! 195: ! 196: if (vscount % CLSIZE) ! 197: panic("vsswap"); ! 198: for (;;) { ! 199: if (vscount == 0 || pte->pg_fod || pte->pg_pfnum == 0 || ! 200: !dirtycl(pte)) { ! 201: if (size) { ! 202: vschunk(p, vsbase, size, type, dmp); ! 203: vsbase += size; ! 204: size = 0; ! 205: } ! 206: if (vscount == 0) ! 207: return; ! 208: vsbase += CLSIZE; ! 209: if (pte->pg_fod == 0 && pte->pg_pfnum) ! 210: if (type == CTEXT) ! 211: p->p_textp->x_rssize -= vmemfree(pte, CLSIZE); ! 212: else ! 213: p->p_rssize -= vmemfree(pte, CLSIZE); ! 214: } else { ! 215: size += CLSIZE; ! 216: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 217: MLOCK(c); ! 218: MUNLOCK(c); ! 219: } ! 220: vscount -= CLSIZE; ! 221: if (type == CSTACK) ! 222: pte -= CLSIZE; ! 223: else ! 224: pte += CLSIZE; ! 225: } ! 226: } ! 227: ! 228: vschunk(p, base, size, type, dmp) ! 229: register struct proc *p; ! 230: register int base, size; ! 231: int type; ! 232: struct dmap *dmp; ! 233: { ! 234: register struct pte *pte; ! 235: struct dblock db; ! 236: unsigned v; ! 237: ! 238: base = ctod(base); ! 239: size = ctod(size); ! 240: if (type == CTEXT) { ! 241: while (size > 0) { ! 242: db.db_size = dmtext - base % dmtext; ! 243: if (db.db_size > size) ! 244: db.db_size = size; ! 245: (void)swap(p, ! 246: p->p_textp->x_daddr[base/dmtext] + base%dmtext, ! 247: ptob(tptov(p, dtoc(base))), (int)dtob(db.db_size), ! 248: B_WRITE, 0, swapdev_vp, 0); ! 249: pte = tptopte(p, dtoc(base)); ! 250: p->p_textp->x_rssize -= ! 251: vmemfree(pte, (int)dtoc(db.db_size)); ! 252: base += db.db_size; ! 253: size -= db.db_size; ! 254: } ! 255: return; ! 256: } ! 257: do { ! 258: vstodb(base, size, dmp, &db, type == CSTACK); ! 259: v = type==CSTACK ? ! 260: sptov(p, dtoc(base+db.db_size)-1) : ! 261: dptov(p, dtoc(base)); ! 262: (void)swap(p, db.db_base, ptob(v), (int)dtob(db.db_size), ! 263: B_WRITE, 0, swapdev_vp, 0); ! 264: pte = type==CSTACK ? ! 265: sptopte(p, dtoc(base+db.db_size)-1) : ! 266: dptopte(p, dtoc(base)); ! 267: p->p_rssize -= vmemfree(pte, (int)dtoc(db.db_size)); ! 268: base += db.db_size; ! 269: size -= db.db_size; ! 270: } while (size != 0); ! 271: } ! 272: ! 273: /* ! 274: * Given a base/size pair in virtual swap area, ! 275: * return a physical base/size pair which is the ! 276: * (largest) initial, physically contiguous block. ! 277: */ ! 278: vstodb(vsbase, vssize, dmp, dbp, rev) ! 279: register int vsbase, vssize; ! 280: struct dmap *dmp; ! 281: register struct dblock *dbp; ! 282: { ! 283: register int blk = dmmin; ! 284: register swblk_t *ip = dmp->dm_map; ! 285: ! 286: if (vsbase < 0 || vssize < 0 || vsbase + vssize > dmp->dm_size) ! 287: panic("vstodb"); ! 288: while (vsbase >= blk) { ! 289: vsbase -= blk; ! 290: if (blk < dmmax) ! 291: blk *= 2; ! 292: ip++; ! 293: } ! 294: if (*ip + blk > nswap) ! 295: panic("vstodb *ip"); ! 296: dbp->db_size = imin(vssize, blk - vsbase); ! 297: dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); ! 298: } ! 299: ! 300: /* ! 301: * Convert a virtual page number ! 302: * to its corresponding disk block number. ! 303: * Used in pagein/pageout to initiate single page transfers. ! 304: * An assumption here is that dmmin >= CLBYTES/DEV_BSIZE ! 305: * i.e. a page cluster must be stored contiguously in the swap area. ! 306: */ ! 307: swblk_t ! 308: vtod(p, v, dmap, smap) ! 309: register struct proc *p; ! 310: unsigned v; ! 311: struct dmap *dmap, *smap; ! 312: { ! 313: struct dblock db; ! 314: int tp; ! 315: ! 316: if (isatsv(p, v)) { ! 317: tp = ctod(vtotp(p, v)); ! 318: return (p->p_textp->x_daddr[tp/dmtext] + tp%dmtext); ! 319: } ! 320: if (isassv(p, v)) ! 321: vstodb(ctod(vtosp(p, v)), ctod(1), smap, &db, 1); ! 322: else ! 323: vstodb(ctod(vtodp(p, v)), ctod(1), dmap, &db, 0); ! 324: return (db.db_base); ! 325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.