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