1*16695Smckusick /* vm_swap.c 6.2 84/07/08 */ 21404Sbill 31404Sbill #include "../h/param.h" 41404Sbill #include "../h/systm.h" 51404Sbill #include "../h/buf.h" 61404Sbill #include "../h/conf.h" 71404Sbill #include "../h/dir.h" 81404Sbill #include "../h/user.h" 91404Sbill #include "../h/inode.h" 101404Sbill #include "../h/map.h" 117828Sroot #include "../h/uio.h" 129010Sroot #include "../h/file.h" 131404Sbill 141404Sbill struct buf rswbuf; 151404Sbill /* 161404Sbill * Indirect driver for multi-controller paging. 171404Sbill */ 181404Sbill swstrategy(bp) 191404Sbill register struct buf *bp; 201404Sbill { 211404Sbill int sz, off, seg; 221404Sbill dev_t dev; 231404Sbill 247435Sroot #ifdef GENERIC 257435Sroot /* 267435Sroot * A mini-root gets copied into the front of the swap 277435Sroot * and we run over top of the swap area just long 287435Sroot * enough for us to do a mkfs and restor of the real 297435Sroot * root (sure beats rewriting standalone restor). 307435Sroot */ 3111051Ssam #define MINIROOTSIZE 4096 327435Sroot if (rootdev == dumpdev) 337435Sroot bp->b_blkno += MINIROOTSIZE; 347435Sroot #endif 359010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 3612490Ssam if (bp->b_blkno+sz > nswap) { 371404Sbill bp->b_flags |= B_ERROR; 381404Sbill iodone(bp); 391404Sbill return; 401404Sbill } 4112490Ssam if (nswdev > 1) { 4212490Ssam off = bp->b_blkno % dmmax; 4312490Ssam if (off+sz > dmmax) { 4412490Ssam bp->b_flags |= B_ERROR; 4512490Ssam iodone(bp); 4612490Ssam return; 4712490Ssam } 4812490Ssam seg = bp->b_blkno / dmmax; 4912490Ssam dev = swdevt[seg % nswdev].sw_dev; 5012490Ssam seg /= nswdev; 5112490Ssam bp->b_blkno = seg*dmmax + off; 5212490Ssam } else 5312490Ssam dev = swdevt[0].sw_dev; 541404Sbill bp->b_dev = dev; 551404Sbill if (dev == 0) 561404Sbill panic("swstrategy"); 571404Sbill (*bdevsw[major(dev)].d_strategy)(bp); 581404Sbill } 591404Sbill 607828Sroot swread(dev, uio) 617828Sroot dev_t dev; 627828Sroot struct uio *uio; 631404Sbill { 641404Sbill 658819Sroot return (physio(swstrategy, &rswbuf, dev, B_READ, minphys, uio)); 661404Sbill } 671404Sbill 687828Sroot swwrite(dev, uio) 697828Sroot dev_t dev; 707828Sroot struct uio *uio; 711404Sbill { 721404Sbill 738819Sroot return (physio(swstrategy, &rswbuf, dev, B_WRITE, minphys, uio)); 741404Sbill } 751404Sbill 761404Sbill /* 771404Sbill * System call swapon(name) enables swapping on device name, 781404Sbill * which must be in the swdevsw. Return EBUSY 791404Sbill * if already swapping on this device. 801404Sbill */ 8112359Ssam swapon() 821404Sbill { 8312359Ssam struct a { 8412359Ssam char *name; 85*16695Smckusick } *uap = (struct a *)u.u_ap; 861404Sbill register struct inode *ip; 871404Sbill dev_t dev; 881404Sbill register struct swdevt *sp; 89*16695Smckusick register struct nameidata *ndp = &u.u_nd; 901404Sbill 91*16695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 92*16695Smckusick ndp->ni_segflg = UIO_USERSPACE; 93*16695Smckusick ndp->ni_dirp = uap->name; 94*16695Smckusick ip = namei(ndp); 951404Sbill if (ip == NULL) 961404Sbill return; 971404Sbill if ((ip->i_mode&IFMT) != IFBLK) { 981404Sbill u.u_error = ENOTBLK; 991404Sbill iput(ip); 1001404Sbill return; 1011404Sbill } 1027278Swnj dev = (dev_t)ip->i_rdev; 1031404Sbill iput(ip); 1041404Sbill if (major(dev) >= nblkdev) { 1051404Sbill u.u_error = ENXIO; 1061404Sbill return; 1071404Sbill } 1081404Sbill /* 1091404Sbill * Search starting at second table entry, 1101404Sbill * since first (primary swap area) is freed at boot. 1111404Sbill */ 1121404Sbill for (sp = &swdevt[1]; sp->sw_dev; sp++) 1131404Sbill if (sp->sw_dev == dev) { 1141404Sbill if (sp->sw_freed) { 1151404Sbill u.u_error = EBUSY; 1161404Sbill return; 1171404Sbill } 1181404Sbill swfree(sp - swdevt); 1191404Sbill return; 1201404Sbill } 1211404Sbill u.u_error = ENODEV; 1221404Sbill } 1231404Sbill 1241404Sbill /* 1251404Sbill * Swfree(index) frees the index'th portion of the swap map. 1261404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 12712490Ssam * space, which is laid out with blocks of dmmax pages circularly 1281404Sbill * among the devices. 1291404Sbill */ 1301404Sbill swfree(index) 1311404Sbill int index; 1321404Sbill { 1331404Sbill register swblk_t vsbase; 1348772Sroot register long blk; 1358961Sroot dev_t dev; 13612490Ssam register swblk_t dvbase; 13712490Ssam register int nblks; 1381404Sbill 1398961Sroot dev = swdevt[index].sw_dev; 1408961Sroot (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE); 1411404Sbill swdevt[index].sw_freed = 1; 14212490Ssam nblks = swdevt[index].sw_nblks; 14312490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 14412490Ssam blk = nblks - dvbase; 14512490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 14612490Ssam panic("swfree"); 14712490Ssam if (blk > dmmax) 14812490Ssam blk = dmmax; 1491404Sbill if (vsbase == 0) { 1501404Sbill /* 1511404Sbill * Can't free a block starting at 0 in the swapmap 1522788Swnj * but need some space for argmap so use 1/2 this 1531404Sbill * hunk which needs special treatment anyways. 1541404Sbill */ 1551404Sbill argdev = swdevt[0].sw_dev; 1568961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1578961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1582788Swnj /* 1592788Swnj * First of all chunks... initialize the swapmap 1602788Swnj * the second half of the hunk. 1612788Swnj */ 1628794Sroot rminit(swapmap, (long)blk/2, (long)blk/2, 1638794Sroot "swap", nswapmap); 1641404Sbill } else 1652788Swnj rmfree(swapmap, blk, vsbase); 1661404Sbill } 1671404Sbill } 168