123460Smckusick /* 237729Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337729Smckusick * All rights reserved. 423460Smckusick * 537729Smckusick * Redistribution and use in source and binary forms are permitted 637729Smckusick * provided that the above copyright notice and this paragraph are 737729Smckusick * duplicated in all such forms and that any documentation, 837729Smckusick * advertising materials, and other materials related to such 937729Smckusick * distribution and use acknowledge that the software was developed 1037729Smckusick * by the University of California, Berkeley. The name of the 1137729Smckusick * University may not be used to endorse or promote products derived 1237729Smckusick * from this software without specific prior written permission. 1337729Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437729Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537729Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637729Smckusick * 17*39304Smckusick * @(#)vm_swap.c 7.7 (Berkeley) 10/15/89 1823460Smckusick */ 191404Sbill 2017107Sbloom #include "param.h" 2117107Sbloom #include "systm.h" 2217107Sbloom #include "buf.h" 2317107Sbloom #include "conf.h" 2417107Sbloom #include "user.h" 2537729Smckusick #include "vnode.h" 2617107Sbloom #include "map.h" 2717107Sbloom #include "file.h" 281404Sbill 291404Sbill /* 301404Sbill * Indirect driver for multi-controller paging. 311404Sbill */ 321404Sbill swstrategy(bp) 331404Sbill register struct buf *bp; 341404Sbill { 3530750Skarels int sz, off, seg, index; 3630750Skarels register struct swdevt *sp; 371404Sbill 387435Sroot #ifdef GENERIC 397435Sroot /* 407435Sroot * A mini-root gets copied into the front of the swap 417435Sroot * and we run over top of the swap area just long 427435Sroot * enough for us to do a mkfs and restor of the real 437435Sroot * root (sure beats rewriting standalone restor). 447435Sroot */ 4511051Ssam #define MINIROOTSIZE 4096 467435Sroot if (rootdev == dumpdev) 477435Sroot bp->b_blkno += MINIROOTSIZE; 487435Sroot #endif 499010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 5012490Ssam if (bp->b_blkno+sz > nswap) { 511404Sbill bp->b_flags |= B_ERROR; 5230750Skarels biodone(bp); 531404Sbill return; 541404Sbill } 5512490Ssam if (nswdev > 1) { 5612490Ssam off = bp->b_blkno % dmmax; 5712490Ssam if (off+sz > dmmax) { 5812490Ssam bp->b_flags |= B_ERROR; 5930750Skarels biodone(bp); 6012490Ssam return; 6112490Ssam } 6212490Ssam seg = bp->b_blkno / dmmax; 6330750Skarels index = seg % nswdev; 6412490Ssam seg /= nswdev; 6512490Ssam bp->b_blkno = seg*dmmax + off; 6612490Ssam } else 6730750Skarels index = 0; 6830750Skarels sp = &swdevt[index]; 6930750Skarels bp->b_dev = sp->sw_dev; 7030750Skarels if (bp->b_dev == 0) 711404Sbill panic("swstrategy"); 7237729Smckusick if (bp->b_vp) 7337729Smckusick brelvp(bp); 74*39304Smckusick if (sp->sw_vp == NULL) { 75*39304Smckusick bp->b_error |= B_ERROR; 76*39304Smckusick biodone(bp); 77*39304Smckusick return; 78*39304Smckusick } 7938349Smckusick VREF(sp->sw_vp); 8037729Smckusick bp->b_vp = sp->sw_vp; 8137729Smckusick VOP_STRATEGY(bp); 821404Sbill } 831404Sbill 841404Sbill /* 851404Sbill * System call swapon(name) enables swapping on device name, 861404Sbill * which must be in the swdevsw. Return EBUSY 871404Sbill * if already swapping on this device. 881404Sbill */ 8912359Ssam swapon() 901404Sbill { 9112359Ssam struct a { 9212359Ssam char *name; 9316695Smckusick } *uap = (struct a *)u.u_ap; 9437729Smckusick register struct vnode *vp; 951404Sbill dev_t dev; 961404Sbill register struct swdevt *sp; 9716695Smckusick register struct nameidata *ndp = &u.u_nd; 981404Sbill 9937552Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 10021017Smckusick return; 10116695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 10216695Smckusick ndp->ni_segflg = UIO_USERSPACE; 10316695Smckusick ndp->ni_dirp = uap->name; 10437729Smckusick if (u.u_error = namei(ndp)) 1051404Sbill return; 10637729Smckusick vp = ndp->ni_vp; 10737729Smckusick if (vp->v_type != VBLK) { 10837729Smckusick vrele(vp); 1091404Sbill u.u_error = ENOTBLK; 1101404Sbill return; 1111404Sbill } 11237729Smckusick dev = (dev_t)vp->v_rdev; 1131404Sbill if (major(dev) >= nblkdev) { 11437729Smckusick vrele(vp); 1151404Sbill u.u_error = ENXIO; 1161404Sbill return; 1171404Sbill } 11817879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1191404Sbill if (sp->sw_dev == dev) { 1201404Sbill if (sp->sw_freed) { 12137729Smckusick vrele(vp); 1221404Sbill u.u_error = EBUSY; 1231404Sbill return; 1241404Sbill } 12537729Smckusick sp->sw_vp = vp; 12637729Smckusick if (u.u_error = swfree(sp - swdevt)) { 12737729Smckusick vrele(vp); 12837729Smckusick return; 12937729Smckusick } 1301404Sbill return; 1311404Sbill } 13237729Smckusick vrele(vp); 13317879Sbloom u.u_error = EINVAL; 1341404Sbill } 1351404Sbill 1361404Sbill /* 1371404Sbill * Swfree(index) frees the index'th portion of the swap map. 1381404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 13912490Ssam * space, which is laid out with blocks of dmmax pages circularly 1401404Sbill * among the devices. 1411404Sbill */ 1421404Sbill swfree(index) 1431404Sbill int index; 1441404Sbill { 14530750Skarels register struct swdevt *sp; 1461404Sbill register swblk_t vsbase; 1478772Sroot register long blk; 14837729Smckusick struct vnode *vp; 14912490Ssam register swblk_t dvbase; 15012490Ssam register int nblks; 15130750Skarels int error; 1521404Sbill 15330750Skarels sp = &swdevt[index]; 15437729Smckusick vp = sp->sw_vp; 15537729Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 15630750Skarels return (error); 15730750Skarels sp->sw_freed = 1; 15830750Skarels nblks = sp->sw_nblks; 15912490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 16012490Ssam blk = nblks - dvbase; 16112490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 16212490Ssam panic("swfree"); 16312490Ssam if (blk > dmmax) 16412490Ssam blk = dmmax; 1651404Sbill if (vsbase == 0) { 1661404Sbill /* 1671404Sbill * Can't free a block starting at 0 in the swapmap 1682788Swnj * but need some space for argmap so use 1/2 this 1691404Sbill * hunk which needs special treatment anyways. 1701404Sbill */ 17130750Skarels argdev = sp->sw_dev; 17237729Smckusick if (argdev_vp) 17337729Smckusick vrele(argdev_vp); 17438349Smckusick VREF(vp); 17537729Smckusick argdev_vp = vp; 1768961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1778961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1782788Swnj /* 1792788Swnj * First of all chunks... initialize the swapmap 1802788Swnj * the second half of the hunk. 1812788Swnj */ 18237729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 1838794Sroot "swap", nswapmap); 18430750Skarels } else if (dvbase == 0) { 18530750Skarels /* 18630750Skarels * Don't use the first cluster of the device 18730750Skarels * in case it starts with a label or boot block. 18830750Skarels */ 18930750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 19030750Skarels vsbase + ctod(CLSIZE)); 1911404Sbill } else 1922788Swnj rmfree(swapmap, blk, vsbase); 1931404Sbill } 19430750Skarels return (0); 1951404Sbill } 196