123460Smckusick /* 2*37729Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*37729Smckusick * All rights reserved. 423460Smckusick * 5*37729Smckusick * Redistribution and use in source and binary forms are permitted 6*37729Smckusick * provided that the above copyright notice and this paragraph are 7*37729Smckusick * duplicated in all such forms and that any documentation, 8*37729Smckusick * advertising materials, and other materials related to such 9*37729Smckusick * distribution and use acknowledge that the software was developed 10*37729Smckusick * by the University of California, Berkeley. The name of the 11*37729Smckusick * University may not be used to endorse or promote products derived 12*37729Smckusick * from this software without specific prior written permission. 13*37729Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*37729Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*37729Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*37729Smckusick * 17*37729Smckusick * @(#)vm_swap.c 7.5 (Berkeley) 05/09/89 1823460Smckusick */ 191404Sbill 2017107Sbloom #include "param.h" 2117107Sbloom #include "systm.h" 2217107Sbloom #include "buf.h" 2317107Sbloom #include "conf.h" 2417107Sbloom #include "user.h" 25*37729Smckusick #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"); 72*37729Smckusick if (bp->b_vp) 73*37729Smckusick brelvp(bp); 74*37729Smckusick sp->sw_vp->v_count++; 75*37729Smckusick bp->b_vp = sp->sw_vp; 76*37729Smckusick VOP_STRATEGY(bp); 771404Sbill } 781404Sbill 791404Sbill /* 801404Sbill * System call swapon(name) enables swapping on device name, 811404Sbill * which must be in the swdevsw. Return EBUSY 821404Sbill * if already swapping on this device. 831404Sbill */ 8412359Ssam swapon() 851404Sbill { 8612359Ssam struct a { 8712359Ssam char *name; 8816695Smckusick } *uap = (struct a *)u.u_ap; 89*37729Smckusick register struct vnode *vp; 901404Sbill dev_t dev; 911404Sbill register struct swdevt *sp; 9216695Smckusick register struct nameidata *ndp = &u.u_nd; 931404Sbill 9437552Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 9521017Smckusick return; 9616695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 9716695Smckusick ndp->ni_segflg = UIO_USERSPACE; 9816695Smckusick ndp->ni_dirp = uap->name; 99*37729Smckusick if (u.u_error = namei(ndp)) 1001404Sbill return; 101*37729Smckusick vp = ndp->ni_vp; 102*37729Smckusick if (vp->v_type != VBLK) { 103*37729Smckusick vrele(vp); 1041404Sbill u.u_error = ENOTBLK; 1051404Sbill return; 1061404Sbill } 107*37729Smckusick dev = (dev_t)vp->v_rdev; 1081404Sbill if (major(dev) >= nblkdev) { 109*37729Smckusick vrele(vp); 1101404Sbill u.u_error = ENXIO; 1111404Sbill return; 1121404Sbill } 11317879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1141404Sbill if (sp->sw_dev == dev) { 1151404Sbill if (sp->sw_freed) { 116*37729Smckusick vrele(vp); 1171404Sbill u.u_error = EBUSY; 1181404Sbill return; 1191404Sbill } 120*37729Smckusick sp->sw_vp = vp; 121*37729Smckusick if (u.u_error = swfree(sp - swdevt)) { 122*37729Smckusick vrele(vp); 123*37729Smckusick return; 124*37729Smckusick } 1251404Sbill return; 1261404Sbill } 127*37729Smckusick vrele(vp); 12817879Sbloom u.u_error = EINVAL; 1291404Sbill } 1301404Sbill 1311404Sbill /* 1321404Sbill * Swfree(index) frees the index'th portion of the swap map. 1331404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 13412490Ssam * space, which is laid out with blocks of dmmax pages circularly 1351404Sbill * among the devices. 1361404Sbill */ 1371404Sbill swfree(index) 1381404Sbill int index; 1391404Sbill { 14030750Skarels register struct swdevt *sp; 1411404Sbill register swblk_t vsbase; 1428772Sroot register long blk; 143*37729Smckusick struct vnode *vp; 14412490Ssam register swblk_t dvbase; 14512490Ssam register int nblks; 14630750Skarels int error; 1471404Sbill 14830750Skarels sp = &swdevt[index]; 149*37729Smckusick vp = sp->sw_vp; 150*37729Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 15130750Skarels return (error); 15230750Skarels sp->sw_freed = 1; 15330750Skarels nblks = sp->sw_nblks; 15412490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 15512490Ssam blk = nblks - dvbase; 15612490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 15712490Ssam panic("swfree"); 15812490Ssam if (blk > dmmax) 15912490Ssam blk = dmmax; 1601404Sbill if (vsbase == 0) { 1611404Sbill /* 1621404Sbill * Can't free a block starting at 0 in the swapmap 1632788Swnj * but need some space for argmap so use 1/2 this 1641404Sbill * hunk which needs special treatment anyways. 1651404Sbill */ 16630750Skarels argdev = sp->sw_dev; 167*37729Smckusick if (argdev_vp) 168*37729Smckusick vrele(argdev_vp); 169*37729Smckusick vp->v_count++; 170*37729Smckusick argdev_vp = vp; 1718961Sroot rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 1728961Sroot (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 1732788Swnj /* 1742788Swnj * First of all chunks... initialize the swapmap 1752788Swnj * the second half of the hunk. 1762788Swnj */ 177*37729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 1788794Sroot "swap", nswapmap); 17930750Skarels } else if (dvbase == 0) { 18030750Skarels /* 18130750Skarels * Don't use the first cluster of the device 18230750Skarels * in case it starts with a label or boot block. 18330750Skarels */ 18430750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 18530750Skarels vsbase + ctod(CLSIZE)); 1861404Sbill } else 1872788Swnj rmfree(swapmap, blk, vsbase); 1881404Sbill } 18930750Skarels return (0); 1901404Sbill } 191