123460Smckusick /* 237729Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337729Smckusick * All rights reserved. 423460Smckusick * 5*44462Sbostic * %sccs.include.redist.c% 637729Smckusick * 7*44462Sbostic * @(#)vm_swap.c 7.14 (Berkeley) 06/28/90 823460Smckusick */ 91404Sbill 1017107Sbloom #include "param.h" 1117107Sbloom #include "systm.h" 1217107Sbloom #include "buf.h" 1317107Sbloom #include "conf.h" 1444409Skarels #include "user.h" 1537729Smckusick #include "vnode.h" 1640652Smckusick #include "specdev.h" 1717107Sbloom #include "map.h" 1817107Sbloom #include "file.h" 191404Sbill 201404Sbill /* 211404Sbill * Indirect driver for multi-controller paging. 221404Sbill */ 231404Sbill swstrategy(bp) 241404Sbill register struct buf *bp; 251404Sbill { 2630750Skarels int sz, off, seg, index; 2730750Skarels register struct swdevt *sp; 2839894Smckusick struct vnode *vp; 291404Sbill 307435Sroot #ifdef GENERIC 317435Sroot /* 327435Sroot * A mini-root gets copied into the front of the swap 337435Sroot * and we run over top of the swap area just long 347435Sroot * enough for us to do a mkfs and restor of the real 357435Sroot * root (sure beats rewriting standalone restor). 367435Sroot */ 3711051Ssam #define MINIROOTSIZE 4096 387435Sroot if (rootdev == dumpdev) 397435Sroot bp->b_blkno += MINIROOTSIZE; 407435Sroot #endif 419010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 4212490Ssam if (bp->b_blkno+sz > nswap) { 431404Sbill bp->b_flags |= B_ERROR; 4430750Skarels biodone(bp); 451404Sbill return; 461404Sbill } 4712490Ssam if (nswdev > 1) { 4812490Ssam off = bp->b_blkno % dmmax; 4912490Ssam if (off+sz > dmmax) { 5012490Ssam bp->b_flags |= B_ERROR; 5130750Skarels biodone(bp); 5212490Ssam return; 5312490Ssam } 5412490Ssam seg = bp->b_blkno / dmmax; 5530750Skarels index = seg % nswdev; 5612490Ssam seg /= nswdev; 5712490Ssam bp->b_blkno = seg*dmmax + off; 5812490Ssam } else 5930750Skarels index = 0; 6030750Skarels sp = &swdevt[index]; 6139894Smckusick if ((bp->b_dev = sp->sw_dev) == 0) 621404Sbill panic("swstrategy"); 6339304Smckusick if (sp->sw_vp == NULL) { 6439304Smckusick bp->b_error |= B_ERROR; 6539304Smckusick biodone(bp); 6639304Smckusick return; 6739304Smckusick } 6839806Smckusick VHOLD(sp->sw_vp); 6939880Smckusick if ((bp->b_flags & B_READ) == 0) { 7039894Smckusick if (vp = bp->b_vp) { 7139894Smckusick vp->v_numoutput--; 7239894Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 7339894Smckusick vp->v_flag &= ~VBWAIT; 7439894Smckusick wakeup((caddr_t)&vp->v_numoutput); 7539894Smckusick } 7639880Smckusick } 7739880Smckusick sp->sw_vp->v_numoutput++; 7839880Smckusick } 7939894Smckusick if (bp->b_vp != NULL) 8039894Smckusick brelvp(bp); 8137729Smckusick bp->b_vp = sp->sw_vp; 8237729Smckusick VOP_STRATEGY(bp); 831404Sbill } 841404Sbill 851404Sbill /* 861404Sbill * System call swapon(name) enables swapping on device name, 871404Sbill * which must be in the swdevsw. Return EBUSY 881404Sbill * if already swapping on this device. 891404Sbill */ 9043376Smckusick /* ARGSUSED */ 9143376Smckusick swapon(p, uap, retval) 9243376Smckusick struct proc *p; 9343376Smckusick struct args { 9443376Smckusick char *name; 9543376Smckusick } *uap; 9643376Smckusick int *retval; 971404Sbill { 9837729Smckusick register struct vnode *vp; 991404Sbill register struct swdevt *sp; 10016695Smckusick register struct nameidata *ndp = &u.u_nd; 10143376Smckusick dev_t dev; 10243376Smckusick int error; 1031404Sbill 10443376Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 10544409Skarels return (error); 10616695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 10716695Smckusick ndp->ni_segflg = UIO_USERSPACE; 10816695Smckusick ndp->ni_dirp = uap->name; 10943376Smckusick if (error = namei(ndp)) 11044409Skarels return (error); 11137729Smckusick vp = ndp->ni_vp; 11237729Smckusick if (vp->v_type != VBLK) { 11337729Smckusick vrele(vp); 11444409Skarels return (ENOTBLK); 1151404Sbill } 11637729Smckusick dev = (dev_t)vp->v_rdev; 1171404Sbill if (major(dev) >= nblkdev) { 11837729Smckusick vrele(vp); 11944409Skarels return (ENXIO); 1201404Sbill } 12117879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1221404Sbill if (sp->sw_dev == dev) { 1231404Sbill if (sp->sw_freed) { 12437729Smckusick vrele(vp); 12544409Skarels return (EBUSY); 1261404Sbill } 12737729Smckusick sp->sw_vp = vp; 12843376Smckusick if (error = swfree(sp - swdevt)) { 12937729Smckusick vrele(vp); 13044409Skarels return (error); 13137729Smckusick } 13244409Skarels return (0); 1331404Sbill } 13437729Smckusick vrele(vp); 13544409Skarels return (EINVAL); 1361404Sbill } 1371404Sbill 1381404Sbill /* 1391404Sbill * Swfree(index) frees the index'th portion of the swap map. 1401404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 14112490Ssam * space, which is laid out with blocks of dmmax pages circularly 1421404Sbill * among the devices. 1431404Sbill */ 1441404Sbill swfree(index) 1451404Sbill int index; 1461404Sbill { 14730750Skarels register struct swdevt *sp; 1481404Sbill register swblk_t vsbase; 1498772Sroot register long blk; 15037729Smckusick struct vnode *vp; 15112490Ssam register swblk_t dvbase; 15212490Ssam register int nblks; 15330750Skarels int error; 1541404Sbill 15530750Skarels sp = &swdevt[index]; 15637729Smckusick vp = sp->sw_vp; 15737729Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 15830750Skarels return (error); 15930750Skarels sp->sw_freed = 1; 16030750Skarels nblks = sp->sw_nblks; 16112490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 16212490Ssam blk = nblks - dvbase; 16312490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 16412490Ssam panic("swfree"); 16512490Ssam if (blk > dmmax) 16612490Ssam blk = dmmax; 1671404Sbill if (vsbase == 0) { 1681404Sbill /* 1691404Sbill * Can't free a block starting at 0 in the swapmap 1702788Swnj * but need some space for argmap so use 1/2 this 1711404Sbill * hunk which needs special treatment anyways. 1721404Sbill */ 17330750Skarels argdev = sp->sw_dev; 17437729Smckusick if (argdev_vp) 17537729Smckusick vrele(argdev_vp); 17638349Smckusick VREF(vp); 17737729Smckusick argdev_vp = vp; 1788961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1798961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1802788Swnj /* 1812788Swnj * First of all chunks... initialize the swapmap 1822788Swnj * the second half of the hunk. 1832788Swnj */ 18437729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 1858794Sroot "swap", nswapmap); 18630750Skarels } else if (dvbase == 0) { 18730750Skarels /* 18830750Skarels * Don't use the first cluster of the device 18930750Skarels * in case it starts with a label or boot block. 19030750Skarels */ 19130750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 19230750Skarels vsbase + ctod(CLSIZE)); 1931404Sbill } else 1942788Swnj rmfree(swapmap, blk, vsbase); 1951404Sbill } 19630750Skarels return (0); 1971404Sbill } 198