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.19 (Berkeley) 02/03/92 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "proc.h" 15 #include "namei.h" 16 #include "dmap.h" /* XXX */ 17 #include "vnode.h" 18 #include "specdev.h" 19 #include "map.h" 20 #include "file.h" 21 22 /* 23 * Indirect driver for multi-controller paging. 24 */ 25 26 int nswap, nswdev; 27 28 /* 29 * Set up swap devices. 30 * Initialize linked list of free swap 31 * headers. These do not actually point 32 * to buffers, but rather to pages that 33 * are being swapped in and out. 34 */ 35 swapinit() 36 { 37 register int i; 38 register struct buf *sp = swbuf; 39 struct swdevt *swp; 40 int error; 41 42 /* 43 * Count swap devices, and adjust total swap space available. 44 * Some of this space will not be available until a swapon() 45 * system is issued, usually when the system goes multi-user. 46 */ 47 nswdev = 0; 48 nswap = 0; 49 for (swp = swdevt; swp->sw_dev; swp++) { 50 nswdev++; 51 if (swp->sw_nblks > nswap) 52 nswap = swp->sw_nblks; 53 } 54 if (nswdev == 0) 55 panic("swapinit"); 56 if (nswdev > 1) 57 nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; 58 nswap *= nswdev; 59 if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) 60 panic("swapvp"); 61 if (error = swfree(&proc0, 0)) { 62 printf("swfree errno %d\n", error); /* XXX */ 63 panic("swapinit swfree 0"); 64 } 65 66 /* 67 * Now set up swap buffer headers. 68 */ 69 bswlist.av_forw = sp; 70 for (i = 0; i < nswbuf - 1; i++, sp++) 71 sp->av_forw = sp + 1; 72 sp->av_forw = NULL; 73 } 74 75 swstrategy(bp) 76 register struct buf *bp; 77 { 78 int sz, off, seg, index; 79 register struct swdevt *sp; 80 struct vnode *vp; 81 82 #ifdef GENERIC 83 /* 84 * A mini-root gets copied into the front of the swap 85 * and we run over top of the swap area just long 86 * enough for us to do a mkfs and restor of the real 87 * root (sure beats rewriting standalone restor). 88 */ 89 #define MINIROOTSIZE 4096 90 if (rootdev == dumpdev) 91 bp->b_blkno += MINIROOTSIZE; 92 #endif 93 sz = howmany(bp->b_bcount, DEV_BSIZE); 94 if (bp->b_blkno + sz > nswap) { 95 bp->b_flags |= B_ERROR; 96 biodone(bp); 97 return; 98 } 99 if (nswdev > 1) { 100 off = bp->b_blkno % dmmax; 101 if (off+sz > dmmax) { 102 bp->b_flags |= B_ERROR; 103 biodone(bp); 104 return; 105 } 106 seg = bp->b_blkno / dmmax; 107 index = seg % nswdev; 108 seg /= nswdev; 109 bp->b_blkno = seg*dmmax + off; 110 } else 111 index = 0; 112 sp = &swdevt[index]; 113 if ((bp->b_dev = sp->sw_dev) == 0) 114 panic("swstrategy"); 115 if (sp->sw_vp == NULL) { 116 bp->b_error |= B_ERROR; 117 biodone(bp); 118 return; 119 } 120 VHOLD(sp->sw_vp); 121 if ((bp->b_flags & B_READ) == 0) { 122 if (vp = bp->b_vp) { 123 vp->v_numoutput--; 124 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 125 vp->v_flag &= ~VBWAIT; 126 wakeup((caddr_t)&vp->v_numoutput); 127 } 128 } 129 sp->sw_vp->v_numoutput++; 130 } 131 if (bp->b_vp != NULL) 132 brelvp(bp); 133 bp->b_vp = sp->sw_vp; 134 VOP_STRATEGY(bp); 135 } 136 137 /* 138 * System call swapon(name) enables swapping on device name, 139 * which must be in the swdevsw. Return EBUSY 140 * if already swapping on this device. 141 */ 142 /* ARGSUSED */ 143 swapon(p, uap, retval) 144 struct proc *p; 145 struct args { 146 char *name; 147 } *uap; 148 int *retval; 149 { 150 register struct vnode *vp; 151 register struct swdevt *sp; 152 dev_t dev; 153 int error; 154 struct nameidata nd; 155 156 if (error = suser(p->p_ucred, &p->p_acflag)) 157 return (error); 158 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->name, p); 159 if (error = namei(&nd)) 160 return (error); 161 vp = nd.ni_vp; 162 if (vp->v_type != VBLK) { 163 vrele(vp); 164 return (ENOTBLK); 165 } 166 dev = (dev_t)vp->v_rdev; 167 if (major(dev) >= nblkdev) { 168 vrele(vp); 169 return (ENXIO); 170 } 171 for (sp = &swdevt[0]; sp->sw_dev; sp++) 172 if (sp->sw_dev == dev) { 173 if (sp->sw_freed) { 174 vrele(vp); 175 return (EBUSY); 176 } 177 sp->sw_vp = vp; 178 if (error = swfree(p, sp - swdevt)) { 179 vrele(vp); 180 return (error); 181 } 182 return (0); 183 } 184 vrele(vp); 185 return (EINVAL); 186 } 187 188 /* 189 * Swfree(index) frees the index'th portion of the swap map. 190 * Each of the nswdev devices provides 1/nswdev'th of the swap 191 * space, which is laid out with blocks of dmmax pages circularly 192 * among the devices. 193 */ 194 swfree(p, index) 195 struct proc *p; 196 int index; 197 { 198 register struct swdevt *sp; 199 register swblk_t vsbase; 200 register long blk; 201 struct vnode *vp; 202 register swblk_t dvbase; 203 register int nblks; 204 int error; 205 206 sp = &swdevt[index]; 207 vp = sp->sw_vp; 208 if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)) 209 return (error); 210 sp->sw_freed = 1; 211 nblks = sp->sw_nblks; 212 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 213 blk = nblks - dvbase; 214 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 215 panic("swfree"); 216 if (blk > dmmax) 217 blk = dmmax; 218 if (vsbase == 0) { 219 /* 220 * First of all chunks... initialize the swapmap 221 * the second half of the hunk. 222 */ 223 rminit(swapmap, (long)(blk/2), (long)(blk/2), 224 "swap", nswapmap); 225 } else if (dvbase == 0) { 226 /* 227 * Don't use the first cluster of the device 228 * in case it starts with a label or boot block. 229 */ 230 rmfree(swapmap, blk - ctod(CLSIZE), 231 vsbase + ctod(CLSIZE)); 232 } else 233 rmfree(swapmap, blk, vsbase); 234 } 235 return (0); 236 } 237