1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vm_swap.c 7.15 (Berkeley) 12/05/90 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "user.h" 15 #include "vnode.h" 16 #include "specdev.h" 17 #include "map.h" 18 #include "file.h" 19 20 /* 21 * Indirect driver for multi-controller paging. 22 */ 23 swstrategy(bp) 24 register struct buf *bp; 25 { 26 int sz, off, seg, index; 27 register struct swdevt *sp; 28 struct vnode *vp; 29 30 #ifdef GENERIC 31 /* 32 * A mini-root gets copied into the front of the swap 33 * and we run over top of the swap area just long 34 * enough for us to do a mkfs and restor of the real 35 * root (sure beats rewriting standalone restor). 36 */ 37 #define MINIROOTSIZE 4096 38 if (rootdev == dumpdev) 39 bp->b_blkno += MINIROOTSIZE; 40 #endif 41 sz = howmany(bp->b_bcount, DEV_BSIZE); 42 if (bp->b_blkno+sz > nswap) { 43 bp->b_flags |= B_ERROR; 44 biodone(bp); 45 return; 46 } 47 if (nswdev > 1) { 48 off = bp->b_blkno % dmmax; 49 if (off+sz > dmmax) { 50 bp->b_flags |= B_ERROR; 51 biodone(bp); 52 return; 53 } 54 seg = bp->b_blkno / dmmax; 55 index = seg % nswdev; 56 seg /= nswdev; 57 bp->b_blkno = seg*dmmax + off; 58 } else 59 index = 0; 60 sp = &swdevt[index]; 61 if ((bp->b_dev = sp->sw_dev) == 0) 62 panic("swstrategy"); 63 if (sp->sw_vp == NULL) { 64 bp->b_error |= B_ERROR; 65 biodone(bp); 66 return; 67 } 68 VHOLD(sp->sw_vp); 69 if ((bp->b_flags & B_READ) == 0) { 70 if (vp = bp->b_vp) { 71 vp->v_numoutput--; 72 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 73 vp->v_flag &= ~VBWAIT; 74 wakeup((caddr_t)&vp->v_numoutput); 75 } 76 } 77 sp->sw_vp->v_numoutput++; 78 } 79 if (bp->b_vp != NULL) 80 brelvp(bp); 81 bp->b_vp = sp->sw_vp; 82 VOP_STRATEGY(bp); 83 } 84 85 /* 86 * System call swapon(name) enables swapping on device name, 87 * which must be in the swdevsw. Return EBUSY 88 * if already swapping on this device. 89 */ 90 /* ARGSUSED */ 91 swapon(p, uap, retval) 92 struct proc *p; 93 struct args { 94 char *name; 95 } *uap; 96 int *retval; 97 { 98 register struct vnode *vp; 99 register struct swdevt *sp; 100 register struct nameidata *ndp = &u.u_nd; 101 dev_t dev; 102 int error; 103 104 if (error = suser(u.u_cred, &u.u_acflag)) 105 return (error); 106 ndp->ni_nameiop = LOOKUP | FOLLOW; 107 ndp->ni_segflg = UIO_USERSPACE; 108 ndp->ni_dirp = uap->name; 109 if (error = namei(ndp)) 110 return (error); 111 vp = ndp->ni_vp; 112 if (vp->v_type != VBLK) { 113 vrele(vp); 114 return (ENOTBLK); 115 } 116 dev = (dev_t)vp->v_rdev; 117 if (major(dev) >= nblkdev) { 118 vrele(vp); 119 return (ENXIO); 120 } 121 for (sp = &swdevt[0]; sp->sw_dev; sp++) 122 if (sp->sw_dev == dev) { 123 if (sp->sw_freed) { 124 vrele(vp); 125 return (EBUSY); 126 } 127 sp->sw_vp = vp; 128 if (error = swfree(sp - swdevt)) { 129 vrele(vp); 130 return (error); 131 } 132 return (0); 133 } 134 vrele(vp); 135 return (EINVAL); 136 } 137 138 /* 139 * Swfree(index) frees the index'th portion of the swap map. 140 * Each of the nswdev devices provides 1/nswdev'th of the swap 141 * space, which is laid out with blocks of dmmax pages circularly 142 * among the devices. 143 */ 144 swfree(index) 145 int index; 146 { 147 register struct swdevt *sp; 148 register swblk_t vsbase; 149 register long blk; 150 struct vnode *vp; 151 register swblk_t dvbase; 152 register int nblks; 153 int error; 154 155 sp = &swdevt[index]; 156 vp = sp->sw_vp; 157 if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 158 return (error); 159 sp->sw_freed = 1; 160 nblks = sp->sw_nblks; 161 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 162 blk = nblks - dvbase; 163 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 164 panic("swfree"); 165 if (blk > dmmax) 166 blk = dmmax; 167 if (vsbase == 0) { 168 /* 169 * First of all chunks... initialize the swapmap 170 * the second half of the hunk. 171 */ 172 rminit(swapmap, (long)(blk/2), (long)(blk/2), 173 "swap", nswapmap); 174 } else if (dvbase == 0) { 175 /* 176 * Don't use the first cluster of the device 177 * in case it starts with a label or boot block. 178 */ 179 rmfree(swapmap, blk - ctod(CLSIZE), 180 vsbase + ctod(CLSIZE)); 181 } else 182 rmfree(swapmap, blk, vsbase); 183 } 184 return (0); 185 } 186