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*48041Smckusick * @(#)vm_swap.c 7.17 (Berkeley) 04/16/91 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 2647976Skarels /* 2747976Skarels * Set up swap devices. 2847976Skarels * Initialize linked list of free swap 2947976Skarels * headers. These do not actually point 3047976Skarels * to buffers, but rather to pages that 3147976Skarels * are being swapped in and out. 3247976Skarels */ 3347976Skarels swapinit() 3447976Skarels { 3547976Skarels register int i; 3647976Skarels register struct buf *sp = swbuf; 3747976Skarels struct swdevt *swp; 3847976Skarels int error; 3947976Skarels 4047976Skarels /* 4147976Skarels * Count swap devices, and adjust total swap space available. 4247976Skarels * Some of this space will not be available until a swapon() 4347976Skarels * system is issued, usually when the system goes multi-user. 4447976Skarels */ 4547976Skarels nswdev = 0; 4647976Skarels nswap = 0; 4747976Skarels for (swp = swdevt; swp->sw_dev; swp++) { 4847976Skarels nswdev++; 4947976Skarels if (swp->sw_nblks > nswap) 5047976Skarels nswap = swp->sw_nblks; 5147976Skarels } 5247976Skarels if (nswdev == 0) 5347976Skarels panic("swapinit"); 5447976Skarels if (nswdev > 1) 5547976Skarels nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; 5647976Skarels nswap *= nswdev; 5747976Skarels if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) 5847976Skarels panic("swapvp"); 5947976Skarels if (error = swfree(&proc0, 0)) { 6047976Skarels printf("swfree errno %d\n", error); /* XXX */ 6147976Skarels panic("swapinit swfree 0"); 6247976Skarels } 6347976Skarels 6447976Skarels /* 6547976Skarels * Now set up swap buffer headers. 6647976Skarels */ 6747976Skarels bswlist.av_forw = sp; 6847976Skarels for (i = 0; i < nswbuf - 1; i++, sp++) 6947976Skarels sp->av_forw = sp + 1; 7047976Skarels sp->av_forw = NULL; 7147976Skarels } 7247976Skarels 731404Sbill swstrategy(bp) 741404Sbill register struct buf *bp; 751404Sbill { 7630750Skarels int sz, off, seg, index; 7730750Skarels register struct swdevt *sp; 7839894Smckusick struct vnode *vp; 791404Sbill 807435Sroot #ifdef GENERIC 817435Sroot /* 827435Sroot * A mini-root gets copied into the front of the swap 837435Sroot * and we run over top of the swap area just long 847435Sroot * enough for us to do a mkfs and restor of the real 857435Sroot * root (sure beats rewriting standalone restor). 867435Sroot */ 8711051Ssam #define MINIROOTSIZE 4096 887435Sroot if (rootdev == dumpdev) 897435Sroot bp->b_blkno += MINIROOTSIZE; 907435Sroot #endif 919010Sroot sz = howmany(bp->b_bcount, DEV_BSIZE); 9247976Skarels if (bp->b_blkno + sz > nswap) { 931404Sbill bp->b_flags |= B_ERROR; 9430750Skarels biodone(bp); 951404Sbill return; 961404Sbill } 9712490Ssam if (nswdev > 1) { 9812490Ssam off = bp->b_blkno % dmmax; 9912490Ssam if (off+sz > dmmax) { 10012490Ssam bp->b_flags |= B_ERROR; 10130750Skarels biodone(bp); 10212490Ssam return; 10312490Ssam } 10412490Ssam seg = bp->b_blkno / dmmax; 10530750Skarels index = seg % nswdev; 10612490Ssam seg /= nswdev; 10712490Ssam bp->b_blkno = seg*dmmax + off; 10812490Ssam } else 10930750Skarels index = 0; 11030750Skarels sp = &swdevt[index]; 11139894Smckusick if ((bp->b_dev = sp->sw_dev) == 0) 1121404Sbill panic("swstrategy"); 11339304Smckusick if (sp->sw_vp == NULL) { 11439304Smckusick bp->b_error |= B_ERROR; 11539304Smckusick biodone(bp); 11639304Smckusick return; 11739304Smckusick } 11839806Smckusick VHOLD(sp->sw_vp); 11939880Smckusick if ((bp->b_flags & B_READ) == 0) { 12039894Smckusick if (vp = bp->b_vp) { 12139894Smckusick vp->v_numoutput--; 12239894Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 12339894Smckusick vp->v_flag &= ~VBWAIT; 12439894Smckusick wakeup((caddr_t)&vp->v_numoutput); 12539894Smckusick } 12639880Smckusick } 12739880Smckusick sp->sw_vp->v_numoutput++; 12839880Smckusick } 12939894Smckusick if (bp->b_vp != NULL) 13039894Smckusick brelvp(bp); 13137729Smckusick bp->b_vp = sp->sw_vp; 13237729Smckusick VOP_STRATEGY(bp); 1331404Sbill } 1341404Sbill 1351404Sbill /* 1361404Sbill * System call swapon(name) enables swapping on device name, 1371404Sbill * which must be in the swdevsw. Return EBUSY 1381404Sbill * if already swapping on this device. 1391404Sbill */ 14043376Smckusick /* ARGSUSED */ 14143376Smckusick swapon(p, uap, retval) 14243376Smckusick struct proc *p; 14343376Smckusick struct args { 14443376Smckusick char *name; 14543376Smckusick } *uap; 14643376Smckusick int *retval; 1471404Sbill { 14837729Smckusick register struct vnode *vp; 1491404Sbill register struct swdevt *sp; 15047976Skarels register struct nameidata *ndp; 15143376Smckusick dev_t dev; 15243376Smckusick int error; 15347976Skarels struct nameidata nd; 1541404Sbill 15547976Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 15644409Skarels return (error); 15747976Skarels ndp = &nd; 15816695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 15916695Smckusick ndp->ni_segflg = UIO_USERSPACE; 16016695Smckusick ndp->ni_dirp = uap->name; 16147976Skarels if (error = namei(ndp, p)) 16244409Skarels return (error); 16337729Smckusick vp = ndp->ni_vp; 16437729Smckusick if (vp->v_type != VBLK) { 16537729Smckusick vrele(vp); 16644409Skarels return (ENOTBLK); 1671404Sbill } 16837729Smckusick dev = (dev_t)vp->v_rdev; 1691404Sbill if (major(dev) >= nblkdev) { 17037729Smckusick vrele(vp); 17144409Skarels return (ENXIO); 1721404Sbill } 17317879Sbloom for (sp = &swdevt[0]; sp->sw_dev; sp++) 1741404Sbill if (sp->sw_dev == dev) { 1751404Sbill if (sp->sw_freed) { 17637729Smckusick vrele(vp); 17744409Skarels return (EBUSY); 1781404Sbill } 17937729Smckusick sp->sw_vp = vp; 18047976Skarels if (error = swfree(p, sp - swdevt)) { 18137729Smckusick vrele(vp); 18244409Skarels return (error); 18337729Smckusick } 18444409Skarels return (0); 1851404Sbill } 18637729Smckusick vrele(vp); 18744409Skarels return (EINVAL); 1881404Sbill } 1891404Sbill 1901404Sbill /* 1911404Sbill * Swfree(index) frees the index'th portion of the swap map. 1921404Sbill * Each of the nswdev devices provides 1/nswdev'th of the swap 19312490Ssam * space, which is laid out with blocks of dmmax pages circularly 1941404Sbill * among the devices. 1951404Sbill */ 19647976Skarels swfree(p, index) 19747976Skarels struct proc *p; 1981404Sbill int index; 1991404Sbill { 20030750Skarels register struct swdevt *sp; 2011404Sbill register swblk_t vsbase; 2028772Sroot register long blk; 20337729Smckusick struct vnode *vp; 20412490Ssam register swblk_t dvbase; 20512490Ssam register int nblks; 20630750Skarels int error; 2071404Sbill 20830750Skarels sp = &swdevt[index]; 20937729Smckusick vp = sp->sw_vp; 210*48041Smckusick if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)) 21130750Skarels return (error); 21230750Skarels sp->sw_freed = 1; 21330750Skarels nblks = sp->sw_nblks; 21412490Ssam for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 21512490Ssam blk = nblks - dvbase; 21612490Ssam if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 21712490Ssam panic("swfree"); 21812490Ssam if (blk > dmmax) 21912490Ssam blk = dmmax; 2201404Sbill if (vsbase == 0) { 2211404Sbill /* 2222788Swnj * First of all chunks... initialize the swapmap 2232788Swnj * the second half of the hunk. 2242788Swnj */ 22537729Smckusick rminit(swapmap, (long)(blk/2), (long)(blk/2), 2268794Sroot "swap", nswapmap); 22730750Skarels } else if (dvbase == 0) { 22830750Skarels /* 22930750Skarels * Don't use the first cluster of the device 23030750Skarels * in case it starts with a label or boot block. 23130750Skarels */ 23230750Skarels rmfree(swapmap, blk - ctod(CLSIZE), 23330750Skarels vsbase + ctod(CLSIZE)); 2341404Sbill } else 2352788Swnj rmfree(swapmap, blk, vsbase); 2361404Sbill } 23730750Skarels return (0); 2381404Sbill } 239