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.12 (Berkeley) 06/21/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "buf.h" 23 #include "conf.h" 24 #include "syscontext.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 /* ARGSUSED */ 101 swapon(p, uap, retval) 102 struct proc *p; 103 struct args { 104 char *name; 105 } *uap; 106 int *retval; 107 { 108 register struct vnode *vp; 109 register struct swdevt *sp; 110 register struct nameidata *ndp = &u.u_nd; 111 dev_t dev; 112 int error; 113 114 if (error = suser(u.u_cred, &u.u_acflag)) 115 RETURN (error); 116 ndp->ni_nameiop = LOOKUP | FOLLOW; 117 ndp->ni_segflg = UIO_USERSPACE; 118 ndp->ni_dirp = uap->name; 119 if (error = namei(ndp)) 120 RETURN (error); 121 vp = ndp->ni_vp; 122 if (vp->v_type != VBLK) { 123 vrele(vp); 124 RETURN (ENOTBLK); 125 } 126 dev = (dev_t)vp->v_rdev; 127 if (major(dev) >= nblkdev) { 128 vrele(vp); 129 RETURN (ENXIO); 130 } 131 for (sp = &swdevt[0]; sp->sw_dev; sp++) 132 if (sp->sw_dev == dev) { 133 if (sp->sw_freed) { 134 vrele(vp); 135 RETURN (EBUSY); 136 } 137 sp->sw_vp = vp; 138 if (error = swfree(sp - swdevt)) { 139 vrele(vp); 140 RETURN (error); 141 } 142 RETURN (0); 143 } 144 vrele(vp); 145 RETURN (EINVAL); 146 } 147 148 /* 149 * Swfree(index) frees the index'th portion of the swap map. 150 * Each of the nswdev devices provides 1/nswdev'th of the swap 151 * space, which is laid out with blocks of dmmax pages circularly 152 * among the devices. 153 */ 154 swfree(index) 155 int index; 156 { 157 register struct swdevt *sp; 158 register swblk_t vsbase; 159 register long blk; 160 struct vnode *vp; 161 register swblk_t dvbase; 162 register int nblks; 163 int error; 164 165 sp = &swdevt[index]; 166 vp = sp->sw_vp; 167 if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 168 return (error); 169 sp->sw_freed = 1; 170 nblks = sp->sw_nblks; 171 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 172 blk = nblks - dvbase; 173 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 174 panic("swfree"); 175 if (blk > dmmax) 176 blk = dmmax; 177 if (vsbase == 0) { 178 /* 179 * Can't free a block starting at 0 in the swapmap 180 * but need some space for argmap so use 1/2 this 181 * hunk which needs special treatment anyways. 182 */ 183 argdev = sp->sw_dev; 184 if (argdev_vp) 185 vrele(argdev_vp); 186 VREF(vp); 187 argdev_vp = vp; 188 rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 189 (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 190 /* 191 * First of all chunks... initialize the swapmap 192 * the second half of the hunk. 193 */ 194 rminit(swapmap, (long)(blk/2), (long)(blk/2), 195 "swap", nswapmap); 196 } else if (dvbase == 0) { 197 /* 198 * Don't use the first cluster of the device 199 * in case it starts with a label or boot block. 200 */ 201 rmfree(swapmap, blk - ctod(CLSIZE), 202 vsbase + ctod(CLSIZE)); 203 } else 204 rmfree(swapmap, blk, vsbase); 205 } 206 return (0); 207 } 208