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