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*43376Smckusick * @(#)vm_swap.c 7.12 (Berkeley) 06/21/90 1823460Smckusick */ 191404Sbill 2017107Sbloom #include "param.h" 2117107Sbloom #include "systm.h" 2217107Sbloom #include "buf.h" 2317107Sbloom #include "conf.h" 24*43376Smckusick #include "syscontext.h" 2537729Smckusick #include "vnode.h" 2640652Smckusick #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 */ 100*43376Smckusick /* ARGSUSED */ 101*43376Smckusick swapon(p, uap, retval) 102*43376Smckusick struct proc *p; 103*43376Smckusick struct args { 104*43376Smckusick char *name; 105*43376Smckusick } *uap; 106*43376Smckusick int *retval; 1071404Sbill { 10837729Smckusick register struct vnode *vp; 1091404Sbill register struct swdevt *sp; 11016695Smckusick register struct nameidata *ndp = &u.u_nd; 111*43376Smckusick dev_t dev; 112*43376Smckusick int error; 1131404Sbill 114*43376Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 115*43376Smckusick RETURN (error); 11616695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 11716695Smckusick ndp->ni_segflg = UIO_USERSPACE; 11816695Smckusick ndp->ni_dirp = uap->name; 119*43376Smckusick if (error = namei(ndp)) 120*43376Smckusick RETURN (error); 12137729Smckusick vp = ndp->ni_vp; 12237729Smckusick if (vp->v_type != VBLK) { 12337729Smckusick vrele(vp); 124*43376Smckusick RETURN (ENOTBLK); 1251404Sbill } 12637729Smckusick dev = (dev_t)vp->v_rdev; 1271404Sbill if (major(dev) >= nblkdev) { 12837729Smckusick vrele(vp); 129*43376Smckusick RETURN (ENXIO); 1301404Sbill } 13117879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1321404Sbill if (sp->sw_dev == dev) { 1331404Sbill if (sp->sw_freed) { 13437729Smckusick vrele(vp); 135*43376Smckusick RETURN (EBUSY); 1361404Sbill } 13737729Smckusick sp->sw_vp = vp; 138*43376Smckusick if (error = swfree(sp - swdevt)) { 13937729Smckusick vrele(vp); 140*43376Smckusick RETURN (error); 14137729Smckusick } 142*43376Smckusick RETURN (0); 1431404Sbill } 14437729Smckusick vrele(vp); 145*43376Smckusick RETURN (EINVAL); 1461404Sbill } 1471404Sbill 1481404Sbill /* 1491404Sbill * Swfree(index) frees the index'th portion of the swap map. 1501404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 15112490Ssam * space, which is laid out with blocks of dmmax pages circularly 1521404Sbill * among the devices. 1531404Sbill */ 1541404Sbill swfree(index) 1551404Sbill int index; 1561404Sbill { 15730750Skarels register struct swdevt *sp; 1581404Sbill register swblk_t vsbase; 1598772Sroot register long blk; 16037729Smckusick struct vnode *vp; 16112490Ssam register swblk_t dvbase; 16212490Ssam register int nblks; 16330750Skarels int error; 1641404Sbill 16530750Skarels sp = &swdevt[index]; 16637729Smckusick vp = sp->sw_vp; 16737729Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 16830750Skarels return (error); 16930750Skarels sp->sw_freed = 1; 17030750Skarels nblks = sp->sw_nblks; 17112490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 17212490Ssam blk = nblks - dvbase; 17312490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 17412490Ssam panic("swfree"); 17512490Ssam if (blk > dmmax) 17612490Ssam blk = dmmax; 1771404Sbill if (vsbase == 0) { 1781404Sbill /* 1791404Sbill * Can't free a block starting at 0 in the swapmap 1802788Swnj * but need some space for argmap so use 1/2 this 1811404Sbill * hunk which needs special treatment anyways. 1821404Sbill */ 18330750Skarels argdev = sp->sw_dev; 18437729Smckusick if (argdev_vp) 18537729Smckusick vrele(argdev_vp); 18638349Smckusick VREF(vp); 18737729Smckusick argdev_vp = vp; 1888961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1898961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1902788Swnj /* 1912788Swnj * First of all chunks... initialize the swapmap 1922788Swnj * the second half of the hunk. 1932788Swnj */ 19437729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 1958794Sroot "swap", nswapmap); 19630750Skarels } else if (dvbase == 0) { 19730750Skarels /* 19830750Skarels * Don't use the first cluster of the device 19930750Skarels * in case it starts with a label or boot block. 20030750Skarels */ 20130750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 20230750Skarels vsbase + ctod(CLSIZE)); 2031404Sbill } else 2042788Swnj rmfree(swapmap, blk, vsbase); 2051404Sbill } 20630750Skarels return (0); 2071404Sbill } 208