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*40652Smckusick * @(#)vm_swap.c 7.11 (Berkeley) 03/27/90 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" 26*40652Smckusick #include "specdev.h" 2717107Sbloom #include "map.h" 2817107Sbloom #include "file.h" 291404Sbill 301404Sbill /* 311404Sbill * Indirect driver for multi-controller paging. 321404Sbill */ 331404Sbill swstrategy(bp) 341404Sbill register struct buf *bp; 351404Sbill { 3630750Skarels int sz, off, seg, index; 3730750Skarels register struct swdevt *sp; 3839894Smckusick struct vnode *vp; 391404Sbill 407435Sroot #ifdef GENERIC 417435Sroot /* 427435Sroot * A mini-root gets copied into the front of the swap 437435Sroot * and we run over top of the swap area just long 447435Sroot * enough for us to do a mkfs and restor of the real 457435Sroot * root (sure beats rewriting standalone restor). 467435Sroot */ 4711051Ssam #define MINIROOTSIZE 4096 487435Sroot if (rootdev == dumpdev) 497435Sroot bp->b_blkno += MINIROOTSIZE; 507435Sroot #endif 519010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 5212490Ssam if (bp->b_blkno+sz > nswap) { 531404Sbill bp->b_flags |= B_ERROR; 5430750Skarels biodone(bp); 551404Sbill return; 561404Sbill } 5712490Ssam if (nswdev > 1) { 5812490Ssam off = bp->b_blkno % dmmax; 5912490Ssam if (off+sz > dmmax) { 6012490Ssam bp->b_flags |= B_ERROR; 6130750Skarels biodone(bp); 6212490Ssam return; 6312490Ssam } 6412490Ssam seg = bp->b_blkno / dmmax; 6530750Skarels index = seg % nswdev; 6612490Ssam seg /= nswdev; 6712490Ssam bp->b_blkno = seg*dmmax + off; 6812490Ssam } else 6930750Skarels index = 0; 7030750Skarels sp = &swdevt[index]; 7139894Smckusick if ((bp->b_dev = sp->sw_dev) == 0) 721404Sbill panic("swstrategy"); 7339304Smckusick if (sp->sw_vp == NULL) { 7439304Smckusick bp->b_error |= B_ERROR; 7539304Smckusick biodone(bp); 7639304Smckusick return; 7739304Smckusick } 7839806Smckusick VHOLD(sp->sw_vp); 7939880Smckusick if ((bp->b_flags & B_READ) == 0) { 8039894Smckusick if (vp = bp->b_vp) { 8139894Smckusick vp->v_numoutput--; 8239894Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 8339894Smckusick vp->v_flag &= ~VBWAIT; 8439894Smckusick wakeup((caddr_t)&vp->v_numoutput); 8539894Smckusick } 8639880Smckusick } 8739880Smckusick sp->sw_vp->v_numoutput++; 8839880Smckusick } 8939894Smckusick if (bp->b_vp != NULL) 9039894Smckusick brelvp(bp); 9137729Smckusick bp->b_vp = sp->sw_vp; 9237729Smckusick VOP_STRATEGY(bp); 931404Sbill } 941404Sbill 951404Sbill /* 961404Sbill * System call swapon(name) enables swapping on device name, 971404Sbill * which must be in the swdevsw. Return EBUSY 981404Sbill * if already swapping on this device. 991404Sbill */ 10012359Ssam swapon() 1011404Sbill { 10212359Ssam struct a { 10312359Ssam char *name; 10416695Smckusick } *uap = (struct a *)u.u_ap; 10537729Smckusick register struct vnode *vp; 1061404Sbill dev_t dev; 1071404Sbill register struct swdevt *sp; 10816695Smckusick register struct nameidata *ndp = &u.u_nd; 1091404Sbill 11037552Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 11121017Smckusick return; 11216695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 11316695Smckusick ndp->ni_segflg = UIO_USERSPACE; 11416695Smckusick ndp->ni_dirp = uap->name; 11537729Smckusick if (u.u_error = namei(ndp)) 1161404Sbill return; 11737729Smckusick vp = ndp->ni_vp; 11837729Smckusick if (vp->v_type != VBLK) { 11937729Smckusick vrele(vp); 1201404Sbill u.u_error = ENOTBLK; 1211404Sbill return; 1221404Sbill } 12337729Smckusick dev = (dev_t)vp->v_rdev; 1241404Sbill if (major(dev) >= nblkdev) { 12537729Smckusick vrele(vp); 1261404Sbill u.u_error = ENXIO; 1271404Sbill return; 1281404Sbill } 12917879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1301404Sbill if (sp->sw_dev == dev) { 1311404Sbill if (sp->sw_freed) { 13237729Smckusick vrele(vp); 1331404Sbill u.u_error = EBUSY; 1341404Sbill return; 1351404Sbill } 13637729Smckusick sp->sw_vp = vp; 13737729Smckusick if (u.u_error = swfree(sp - swdevt)) { 13837729Smckusick vrele(vp); 13937729Smckusick return; 14037729Smckusick } 1411404Sbill return; 1421404Sbill } 14337729Smckusick vrele(vp); 14417879Sbloom u.u_error = EINVAL; 1451404Sbill } 1461404Sbill 1471404Sbill /* 1481404Sbill * Swfree(index) frees the index'th portion of the swap map. 1491404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 15012490Ssam * space, which is laid out with blocks of dmmax pages circularly 1511404Sbill * among the devices. 1521404Sbill */ 1531404Sbill swfree(index) 1541404Sbill int index; 1551404Sbill { 15630750Skarels register struct swdevt *sp; 1571404Sbill register swblk_t vsbase; 1588772Sroot register long blk; 15937729Smckusick struct vnode *vp; 16012490Ssam register swblk_t dvbase; 16112490Ssam register int nblks; 16230750Skarels int error; 1631404Sbill 16430750Skarels sp = &swdevt[index]; 16537729Smckusick vp = sp->sw_vp; 16637729Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 16730750Skarels return (error); 16830750Skarels sp->sw_freed = 1; 16930750Skarels nblks = sp->sw_nblks; 17012490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 17112490Ssam blk = nblks - dvbase; 17212490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 17312490Ssam panic("swfree"); 17412490Ssam if (blk > dmmax) 17512490Ssam blk = dmmax; 1761404Sbill if (vsbase == 0) { 1771404Sbill /* 1781404Sbill * Can't free a block starting at 0 in the swapmap 1792788Swnj * but need some space for argmap so use 1/2 this 1801404Sbill * hunk which needs special treatment anyways. 1811404Sbill */ 18230750Skarels argdev = sp->sw_dev; 18337729Smckusick if (argdev_vp) 18437729Smckusick vrele(argdev_vp); 18538349Smckusick VREF(vp); 18637729Smckusick argdev_vp = vp; 1878961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1888961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1892788Swnj /* 1902788Swnj * First of all chunks... initialize the swapmap 1912788Swnj * the second half of the hunk. 1922788Swnj */ 19337729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 1948794Sroot "swap", nswapmap); 19530750Skarels } else if (dvbase == 0) { 19630750Skarels /* 19730750Skarels * Don't use the first cluster of the device 19830750Skarels * in case it starts with a label or boot block. 19930750Skarels */ 20030750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 20130750Skarels vsbase + ctod(CLSIZE)); 2021404Sbill } else 2032788Swnj rmfree(swapmap, blk, vsbase); 2041404Sbill } 20530750Skarels return (0); 2061404Sbill } 207