1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)vm_swap.c 7.11 (Berkeley) 03/27/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "buf.h" 23 #include "conf.h" 24 #include "user.h" 25 #include "vnode.h" 26 #include "specdev.h" 27 #include "map.h" 28 #include "file.h" 29 30 /* 31 * Indirect driver for multi-controller paging. 32 */ 33 swstrategy(bp) 34 register struct buf *bp; 35 { 36 int sz, off, seg, index; 37 register struct swdevt *sp; 38 struct vnode *vp; 39 40 #ifdef GENERIC 41 /* 42 * A mini-root gets copied into the front of the swap 43 * and we run over top of the swap area just long 44 * enough for us to do a mkfs and restor of the real 45 * root (sure beats rewriting standalone restor). 46 */ 47 #define MINIROOTSIZE 4096 48 if (rootdev == dumpdev) 49 bp->b_blkno += MINIROOTSIZE; 50 #endif 51 sz = howmany(bp->b_bcount, DEV_BSIZE); 52 if (bp->b_blkno+sz > nswap) { 53 bp->b_flags |= B_ERROR; 54 biodone(bp); 55 return; 56 } 57 if (nswdev > 1) { 58 off = bp->b_blkno % dmmax; 59 if (off+sz > dmmax) { 60 bp->b_flags |= B_ERROR; 61 biodone(bp); 62 return; 63 } 64 seg = bp->b_blkno / dmmax; 65 index = seg % nswdev; 66 seg /= nswdev; 67 bp->b_blkno = seg*dmmax + off; 68 } else 69 index = 0; 70 sp = &swdevt[index]; 71 if ((bp->b_dev = sp->sw_dev) == 0) 72 panic("swstrategy"); 73 if (sp->sw_vp == NULL) { 74 bp->b_error |= B_ERROR; 75 biodone(bp); 76 return; 77 } 78 VHOLD(sp->sw_vp); 79 if ((bp->b_flags & B_READ) == 0) { 80 if (vp = bp->b_vp) { 81 vp->v_numoutput--; 82 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 83 vp->v_flag &= ~VBWAIT; 84 wakeup((caddr_t)&vp->v_numoutput); 85 } 86 } 87 sp->sw_vp->v_numoutput++; 88 } 89 if (bp->b_vp != NULL) 90 brelvp(bp); 91 bp->b_vp = sp->sw_vp; 92 VOP_STRATEGY(bp); 93 } 94 95 /* 96 * System call swapon(name) enables swapping on device name, 97 * which must be in the swdevsw. Return EBUSY 98 * if already swapping on this device. 99 */ 100 swapon() 101 { 102 struct a { 103 char *name; 104 } *uap = (struct a *)u.u_ap; 105 register struct vnode *vp; 106 dev_t dev; 107 register struct swdevt *sp; 108 register struct nameidata *ndp = &u.u_nd; 109 110 if (u.u_error = suser(u.u_cred, &u.u_acflag)) 111 return; 112 ndp->ni_nameiop = LOOKUP | FOLLOW; 113 ndp->ni_segflg = UIO_USERSPACE; 114 ndp->ni_dirp = uap->name; 115 if (u.u_error = namei(ndp)) 116 return; 117 vp = ndp->ni_vp; 118 if (vp->v_type != VBLK) { 119 vrele(vp); 120 u.u_error = ENOTBLK; 121 return; 122 } 123 dev = (dev_t)vp->v_rdev; 124 if (major(dev) >= nblkdev) { 125 vrele(vp); 126 u.u_error = ENXIO; 127 return; 128 } 129 for (sp = &swdevt[0]; sp->sw_dev; sp++) 130 if (sp->sw_dev == dev) { 131 if (sp->sw_freed) { 132 vrele(vp); 133 u.u_error = EBUSY; 134 return; 135 } 136 sp->sw_vp = vp; 137 if (u.u_error = swfree(sp - swdevt)) { 138 vrele(vp); 139 return; 140 } 141 return; 142 } 143 vrele(vp); 144 u.u_error = EINVAL; 145 } 146 147 /* 148 * Swfree(index) frees the index'th portion of the swap map. 149 * Each of the nswdev devices provides 1/nswdev'th of the swap 150 * space, which is laid out with blocks of dmmax pages circularly 151 * among the devices. 152 */ 153 swfree(index) 154 int index; 155 { 156 register struct swdevt *sp; 157 register swblk_t vsbase; 158 register long blk; 159 struct vnode *vp; 160 register swblk_t dvbase; 161 register int nblks; 162 int error; 163 164 sp = &swdevt[index]; 165 vp = sp->sw_vp; 166 if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 167 return (error); 168 sp->sw_freed = 1; 169 nblks = sp->sw_nblks; 170 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 171 blk = nblks - dvbase; 172 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 173 panic("swfree"); 174 if (blk > dmmax) 175 blk = dmmax; 176 if (vsbase == 0) { 177 /* 178 * Can't free a block starting at 0 in the swapmap 179 * but need some space for argmap so use 1/2 this 180 * hunk which needs special treatment anyways. 181 */ 182 argdev = sp->sw_dev; 183 if (argdev_vp) 184 vrele(argdev_vp); 185 VREF(vp); 186 argdev_vp = vp; 187 rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 188 (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 189 /* 190 * First of all chunks... initialize the swapmap 191 * the second half of the hunk. 192 */ 193 rminit(swapmap, (long)(blk/2), (long)(blk/2), 194 "swap", nswapmap); 195 } else if (dvbase == 0) { 196 /* 197 * Don't use the first cluster of the device 198 * in case it starts with a label or boot block. 199 */ 200 rmfree(swapmap, blk - ctod(CLSIZE), 201 vsbase + ctod(CLSIZE)); 202 } else 203 rmfree(swapmap, blk, vsbase); 204 } 205 return (0); 206 } 207