123460Smckusick /* 237729Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337729Smckusick * All rights reserved. 423460Smckusick * 544462Sbostic * %sccs.include.redist.c% 637729Smckusick * 7*52308Smckusick * @(#)vm_swap.c 7.19 (Berkeley) 02/03/92 823460Smckusick */ 91404Sbill 1017107Sbloom #include "param.h" 1117107Sbloom #include "systm.h" 1217107Sbloom #include "buf.h" 1317107Sbloom #include "conf.h" 1447976Skarels #include "proc.h" 1547976Skarels #include "namei.h" 1647976Skarels #include "dmap.h" /* XXX */ 1737729Smckusick #include "vnode.h" 1840652Smckusick #include "specdev.h" 1917107Sbloom #include "map.h" 2017107Sbloom #include "file.h" 211404Sbill 221404Sbill /* 231404Sbill * Indirect driver for multi-controller paging. 241404Sbill */ 2547976Skarels 2649228Skarels int nswap, nswdev; 2749228Skarels 2847976Skarels /* 2947976Skarels * Set up swap devices. 3047976Skarels * Initialize linked list of free swap 3147976Skarels * headers. These do not actually point 3247976Skarels * to buffers, but rather to pages that 3347976Skarels * are being swapped in and out. 3447976Skarels */ 3547976Skarels swapinit() 3647976Skarels { 3747976Skarels register int i; 3847976Skarels register struct buf *sp = swbuf; 3947976Skarels struct swdevt *swp; 4047976Skarels int error; 4147976Skarels 4247976Skarels /* 4347976Skarels * Count swap devices, and adjust total swap space available. 4447976Skarels * Some of this space will not be available until a swapon() 4547976Skarels * system is issued, usually when the system goes multi-user. 4647976Skarels */ 4747976Skarels nswdev = 0; 4847976Skarels nswap = 0; 4947976Skarels for (swp = swdevt; swp->sw_dev; swp++) { 5047976Skarels nswdev++; 5147976Skarels if (swp->sw_nblks > nswap) 5247976Skarels nswap = swp->sw_nblks; 5347976Skarels } 5447976Skarels if (nswdev == 0) 5547976Skarels panic("swapinit"); 5647976Skarels if (nswdev > 1) 5747976Skarels nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; 5847976Skarels nswap *= nswdev; 5947976Skarels if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) 6047976Skarels panic("swapvp"); 6147976Skarels if (error = swfree(&proc0, 0)) { 6247976Skarels printf("swfree errno %d\n", error); /* XXX */ 6347976Skarels panic("swapinit swfree 0"); 6447976Skarels } 6547976Skarels 6647976Skarels /* 6747976Skarels * Now set up swap buffer headers. 6847976Skarels */ 6947976Skarels bswlist.av_forw = sp; 7047976Skarels for (i = 0; i < nswbuf - 1; i++, sp++) 7147976Skarels sp->av_forw = sp + 1; 7247976Skarels sp->av_forw = NULL; 7347976Skarels } 7447976Skarels 751404Sbill swstrategy(bp) 761404Sbill register struct buf *bp; 771404Sbill { 7830750Skarels int sz, off, seg, index; 7930750Skarels register struct swdevt *sp; 8039894Smckusick struct vnode *vp; 811404Sbill 827435Sroot #ifdef GENERIC 837435Sroot /* 847435Sroot * A mini-root gets copied into the front of the swap 857435Sroot * and we run over top of the swap area just long 867435Sroot * enough for us to do a mkfs and restor of the real 877435Sroot * root (sure beats rewriting standalone restor). 887435Sroot */ 8911051Ssam #define MINIROOTSIZE 4096 907435Sroot if (rootdev == dumpdev) 917435Sroot bp->b_blkno += MINIROOTSIZE; 927435Sroot #endif 939010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 9447976Skarels if (bp->b_blkno + sz > nswap) { 951404Sbill bp->b_flags |= B_ERROR; 9630750Skarels biodone(bp); 971404Sbill return; 981404Sbill } 9912490Ssam if (nswdev > 1) { 10012490Ssam off = bp->b_blkno % dmmax; 10112490Ssam if (off+sz > dmmax) { 10212490Ssam bp->b_flags |= B_ERROR; 10330750Skarels biodone(bp); 10412490Ssam return; 10512490Ssam } 10612490Ssam seg = bp->b_blkno / dmmax; 10730750Skarels index = seg % nswdev; 10812490Ssam seg /= nswdev; 10912490Ssam bp->b_blkno = seg*dmmax + off; 11012490Ssam } else 11130750Skarels index = 0; 11230750Skarels sp = &swdevt[index]; 11339894Smckusick if ((bp->b_dev = sp->sw_dev) == 0) 1141404Sbill panic("swstrategy"); 11539304Smckusick if (sp->sw_vp == NULL) { 11639304Smckusick bp->b_error |= B_ERROR; 11739304Smckusick biodone(bp); 11839304Smckusick return; 11939304Smckusick } 12039806Smckusick VHOLD(sp->sw_vp); 12139880Smckusick if ((bp->b_flags & B_READ) == 0) { 12239894Smckusick if (vp = bp->b_vp) { 12339894Smckusick vp->v_numoutput--; 12439894Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 12539894Smckusick vp->v_flag &= ~VBWAIT; 12639894Smckusick wakeup((caddr_t)&vp->v_numoutput); 12739894Smckusick } 12839880Smckusick } 12939880Smckusick sp->sw_vp->v_numoutput++; 13039880Smckusick } 13139894Smckusick if (bp->b_vp != NULL) 13239894Smckusick brelvp(bp); 13337729Smckusick bp->b_vp = sp->sw_vp; 13437729Smckusick VOP_STRATEGY(bp); 1351404Sbill } 1361404Sbill 1371404Sbill /* 1381404Sbill * System call swapon(name) enables swapping on device name, 1391404Sbill * which must be in the swdevsw. Return EBUSY 1401404Sbill * if already swapping on this device. 1411404Sbill */ 14243376Smckusick /* ARGSUSED */ 14343376Smckusick swapon(p, uap, retval) 14443376Smckusick struct proc *p; 14543376Smckusick struct args { 14643376Smckusick char *name; 14743376Smckusick } *uap; 14843376Smckusick int *retval; 1491404Sbill { 15037729Smckusick register struct vnode *vp; 1511404Sbill register struct swdevt *sp; 15243376Smckusick dev_t dev; 15343376Smckusick int error; 15447976Skarels struct nameidata nd; 1551404Sbill 15647976Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 15744409Skarels return (error); 158*52308Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->name, p); 159*52308Smckusick if (error = namei(&nd)) 16044409Skarels return (error); 161*52308Smckusick vp = nd.ni_vp; 16237729Smckusick if (vp->v_type != VBLK) { 16337729Smckusick vrele(vp); 16444409Skarels return (ENOTBLK); 1651404Sbill } 16637729Smckusick dev = (dev_t)vp->v_rdev; 1671404Sbill if (major(dev) >= nblkdev) { 16837729Smckusick vrele(vp); 16944409Skarels return (ENXIO); 1701404Sbill } 17117879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1721404Sbill if (sp->sw_dev == dev) { 1731404Sbill if (sp->sw_freed) { 17437729Smckusick vrele(vp); 17544409Skarels return (EBUSY); 1761404Sbill } 17737729Smckusick sp->sw_vp = vp; 17847976Skarels if (error = swfree(p, sp - swdevt)) { 17937729Smckusick vrele(vp); 18044409Skarels return (error); 18137729Smckusick } 18244409Skarels return (0); 1831404Sbill } 18437729Smckusick vrele(vp); 18544409Skarels return (EINVAL); 1861404Sbill } 1871404Sbill 1881404Sbill /* 1891404Sbill * Swfree(index) frees the index'th portion of the swap map. 1901404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 19112490Ssam * space, which is laid out with blocks of dmmax pages circularly 1921404Sbill * among the devices. 1931404Sbill */ 19447976Skarels swfree(p, index) 19547976Skarels struct proc *p; 1961404Sbill int index; 1971404Sbill { 19830750Skarels register struct swdevt *sp; 1991404Sbill register swblk_t vsbase; 2008772Sroot register long blk; 20137729Smckusick struct vnode *vp; 20212490Ssam register swblk_t dvbase; 20312490Ssam register int nblks; 20430750Skarels int error; 2051404Sbill 20630750Skarels sp = &swdevt[index]; 20737729Smckusick vp = sp->sw_vp; 20848041Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)) 20930750Skarels return (error); 21030750Skarels sp->sw_freed = 1; 21130750Skarels nblks = sp->sw_nblks; 21212490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 21312490Ssam blk = nblks - dvbase; 21412490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 21512490Ssam panic("swfree"); 21612490Ssam if (blk > dmmax) 21712490Ssam blk = dmmax; 2181404Sbill if (vsbase == 0) { 2191404Sbill /* 2202788Swnj * First of all chunks... initialize the swapmap 2212788Swnj * the second half of the hunk. 2222788Swnj */ 22337729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 2248794Sroot "swap", nswapmap); 22530750Skarels } else if (dvbase == 0) { 22630750Skarels /* 22730750Skarels * Don't use the first cluster of the device 22830750Skarels * in case it starts with a label or boot block. 22930750Skarels */ 23030750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 23130750Skarels vsbase + ctod(CLSIZE)); 2321404Sbill } else 2332788Swnj rmfree(swapmap, blk, vsbase); 2341404Sbill } 23530750Skarels return (0); 2361404Sbill } 237