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.6 (Berkeley) 06/27/89 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_dev == 0) 71 panic("swstrategy"); 72 if (bp->b_vp) 73 brelvp(bp); 74 VREF(sp->sw_vp); 75 bp->b_vp = sp->sw_vp; 76 VOP_STRATEGY(bp); 77 } 78 79 /* 80 * System call swapon(name) enables swapping on device name, 81 * which must be in the swdevsw. Return EBUSY 82 * if already swapping on this device. 83 */ 84 swapon() 85 { 86 struct a { 87 char *name; 88 } *uap = (struct a *)u.u_ap; 89 register struct vnode *vp; 90 dev_t dev; 91 register struct swdevt *sp; 92 register struct nameidata *ndp = &u.u_nd; 93 94 if (u.u_error = suser(u.u_cred, &u.u_acflag)) 95 return; 96 ndp->ni_nameiop = LOOKUP | FOLLOW; 97 ndp->ni_segflg = UIO_USERSPACE; 98 ndp->ni_dirp = uap->name; 99 if (u.u_error = namei(ndp)) 100 return; 101 vp = ndp->ni_vp; 102 if (vp->v_type != VBLK) { 103 vrele(vp); 104 u.u_error = ENOTBLK; 105 return; 106 } 107 dev = (dev_t)vp->v_rdev; 108 if (major(dev) >= nblkdev) { 109 vrele(vp); 110 u.u_error = ENXIO; 111 return; 112 } 113 for (sp = &swdevt[0]; sp->sw_dev; sp++) 114 if (sp->sw_dev == dev) { 115 if (sp->sw_freed) { 116 vrele(vp); 117 u.u_error = EBUSY; 118 return; 119 } 120 sp->sw_vp = vp; 121 if (u.u_error = swfree(sp - swdevt)) { 122 vrele(vp); 123 return; 124 } 125 return; 126 } 127 vrele(vp); 128 u.u_error = EINVAL; 129 } 130 131 /* 132 * Swfree(index) frees the index'th portion of the swap map. 133 * Each of the nswdev devices provides 1/nswdev'th of the swap 134 * space, which is laid out with blocks of dmmax pages circularly 135 * among the devices. 136 */ 137 swfree(index) 138 int index; 139 { 140 register struct swdevt *sp; 141 register swblk_t vsbase; 142 register long blk; 143 struct vnode *vp; 144 register swblk_t dvbase; 145 register int nblks; 146 int error; 147 148 sp = &swdevt[index]; 149 vp = sp->sw_vp; 150 if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred)) 151 return (error); 152 sp->sw_freed = 1; 153 nblks = sp->sw_nblks; 154 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 155 blk = nblks - dvbase; 156 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 157 panic("swfree"); 158 if (blk > dmmax) 159 blk = dmmax; 160 if (vsbase == 0) { 161 /* 162 * Can't free a block starting at 0 in the swapmap 163 * but need some space for argmap so use 1/2 this 164 * hunk which needs special treatment anyways. 165 */ 166 argdev = sp->sw_dev; 167 if (argdev_vp) 168 vrele(argdev_vp); 169 VREF(vp); 170 argdev_vp = vp; 171 rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 172 (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 173 /* 174 * First of all chunks... initialize the swapmap 175 * the second half of the hunk. 176 */ 177 rminit(swapmap, (long)(blk/2), (long)(blk/2), 178 "swap", nswapmap); 179 } else if (dvbase == 0) { 180 /* 181 * Don't use the first cluster of the device 182 * in case it starts with a label or boot block. 183 */ 184 rmfree(swapmap, blk - ctod(CLSIZE), 185 vsbase + ctod(CLSIZE)); 186 } else 187 rmfree(swapmap, blk, vsbase); 188 } 189 return (0); 190 } 191