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.18 (Berkeley) 05/06/91 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 register struct nameidata *ndp; 153 dev_t dev; 154 int error; 155 struct nameidata nd; 156 157 if (error = suser(p->p_ucred, &p->p_acflag)) 158 return (error); 159 ndp = &nd; 160 ndp->ni_nameiop = LOOKUP | FOLLOW; 161 ndp->ni_segflg = UIO_USERSPACE; 162 ndp->ni_dirp = uap->name; 163 if (error = namei(ndp, p)) 164 return (error); 165 vp = ndp->ni_vp; 166 if (vp->v_type != VBLK) { 167 vrele(vp); 168 return (ENOTBLK); 169 } 170 dev = (dev_t)vp->v_rdev; 171 if (major(dev) >= nblkdev) { 172 vrele(vp); 173 return (ENXIO); 174 } 175 for (sp = &swdevt[0]; sp->sw_dev; sp++) 176 if (sp->sw_dev == dev) { 177 if (sp->sw_freed) { 178 vrele(vp); 179 return (EBUSY); 180 } 181 sp->sw_vp = vp; 182 if (error = swfree(p, sp - swdevt)) { 183 vrele(vp); 184 return (error); 185 } 186 return (0); 187 } 188 vrele(vp); 189 return (EINVAL); 190 } 191 192 /* 193 * Swfree(index) frees the index'th portion of the swap map. 194 * Each of the nswdev devices provides 1/nswdev'th of the swap 195 * space, which is laid out with blocks of dmmax pages circularly 196 * among the devices. 197 */ 198 swfree(p, index) 199 struct proc *p; 200 int index; 201 { 202 register struct swdevt *sp; 203 register swblk_t vsbase; 204 register long blk; 205 struct vnode *vp; 206 register swblk_t dvbase; 207 register int nblks; 208 int error; 209 210 sp = &swdevt[index]; 211 vp = sp->sw_vp; 212 if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)) 213 return (error); 214 sp->sw_freed = 1; 215 nblks = sp->sw_nblks; 216 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 217 blk = nblks - dvbase; 218 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 219 panic("swfree"); 220 if (blk > dmmax) 221 blk = dmmax; 222 if (vsbase == 0) { 223 /* 224 * First of all chunks... initialize the swapmap 225 * the second half of the hunk. 226 */ 227 rminit(swapmap, (long)(blk/2), (long)(blk/2), 228 "swap", nswapmap); 229 } else if (dvbase == 0) { 230 /* 231 * Don't use the first cluster of the device 232 * in case it starts with a label or boot block. 233 */ 234 rmfree(swapmap, blk - ctod(CLSIZE), 235 vsbase + ctod(CLSIZE)); 236 } else 237 rmfree(swapmap, blk, vsbase); 238 } 239 return (0); 240 } 241