1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)vm_swap.c 7.1.1.1 (Berkeley) 04/02/87 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "buf.h" 12 #include "conf.h" 13 #include "dir.h" 14 #include "user.h" 15 #include "inode.h" 16 #include "map.h" 17 #include "uio.h" 18 #include "file.h" 19 #include "stat.h" 20 21 struct buf rswbuf; 22 /* 23 * Indirect driver for multi-controller paging. 24 */ 25 swstrategy(bp) 26 register struct buf *bp; 27 { 28 int sz, off, seg, index; 29 register struct swdevt *sp; 30 31 #ifdef GENERIC 32 /* 33 * A mini-root gets copied into the front of the swap 34 * and we run over top of the swap area just long 35 * enough for us to do a mkfs and restor of the real 36 * root (sure beats rewriting standalone restor). 37 */ 38 #define MINIROOTSIZE 4096 39 if (rootdev == dumpdev) 40 bp->b_blkno += MINIROOTSIZE; 41 #endif 42 sz = howmany(bp->b_bcount, DEV_BSIZE); 43 if (bp->b_blkno+sz > nswap) { 44 bp->b_flags |= B_ERROR; 45 biodone(bp); 46 return; 47 } 48 if (nswdev > 1) { 49 off = bp->b_blkno % dmmax; 50 if (off+sz > dmmax) { 51 bp->b_flags |= B_ERROR; 52 biodone(bp); 53 return; 54 } 55 seg = bp->b_blkno / dmmax; 56 index = seg % nswdev; 57 seg /= nswdev; 58 bp->b_blkno = seg*dmmax + off; 59 } else 60 index = 0; 61 sp = &swdevt[index]; 62 #ifdef SECSIZE 63 bp->b_blkno <<= sp->sw_bshift; 64 bp->b_blksize = sp->sw_blksize; 65 #endif SECSIZE 66 bp->b_dev = sp->sw_dev; 67 if (bp->b_dev == 0) 68 panic("swstrategy"); 69 (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 70 } 71 72 swread(dev, uio) 73 dev_t dev; 74 struct uio *uio; 75 { 76 77 return (physio(swstrategy, &rswbuf, dev, B_READ, minphys, uio)); 78 } 79 80 swwrite(dev, uio) 81 dev_t dev; 82 struct uio *uio; 83 { 84 85 return (physio(swstrategy, &rswbuf, dev, B_WRITE, minphys, uio)); 86 } 87 88 /* 89 * System call swapon(name) enables swapping on device name, 90 * which must be in the swdevsw. Return EBUSY 91 * if already swapping on this device. 92 */ 93 swapon() 94 { 95 struct a { 96 char *name; 97 } *uap = (struct a *)u.u_ap; 98 register struct inode *ip; 99 dev_t dev; 100 register struct swdevt *sp; 101 register struct nameidata *ndp = &u.u_nd; 102 103 if (!suser()) 104 return; 105 ndp->ni_nameiop = LOOKUP | FOLLOW; 106 ndp->ni_segflg = UIO_USERSPACE; 107 ndp->ni_dirp = uap->name; 108 ip = namei(ndp); 109 if (ip == NULL) 110 return; 111 if ((ip->i_mode&IFMT) != IFBLK) { 112 u.u_error = ENOTBLK; 113 iput(ip); 114 return; 115 } 116 dev = (dev_t)ip->i_rdev; 117 iput(ip); 118 if (major(dev) >= nblkdev) { 119 u.u_error = ENXIO; 120 return; 121 } 122 for (sp = &swdevt[0]; sp->sw_dev; sp++) 123 if (sp->sw_dev == dev) { 124 if (sp->sw_freed) { 125 u.u_error = EBUSY; 126 return; 127 } 128 u.u_error = swfree(sp - swdevt); 129 return; 130 } 131 u.u_error = EINVAL; 132 } 133 134 #ifdef SECSIZE 135 long argdbsize; /* XXX */ 136 137 #endif SECSIZE 138 /* 139 * Swfree(index) frees the index'th portion of the swap map. 140 * Each of the nswdev devices provides 1/nswdev'th of the swap 141 * space, which is laid out with blocks of dmmax pages circularly 142 * among the devices. 143 */ 144 swfree(index) 145 int index; 146 { 147 register struct swdevt *sp; 148 register swblk_t vsbase; 149 register long blk; 150 dev_t dev; 151 register swblk_t dvbase; 152 register int nblks; 153 int error; 154 155 sp = &swdevt[index]; 156 dev = sp->sw_dev; 157 if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK)) 158 return (error); 159 sp->sw_freed = 1; 160 nblks = sp->sw_nblks; 161 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { 162 blk = nblks - dvbase; 163 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) 164 panic("swfree"); 165 if (blk > dmmax) 166 blk = dmmax; 167 if (vsbase == 0) { 168 /* 169 * Can't free a block starting at 0 in the swapmap 170 * but need some space for argmap so use 1/2 this 171 * hunk which needs special treatment anyways. 172 */ 173 argdev = sp->sw_dev; 174 #ifdef SECSIZE 175 argdbsize = sp->sw_blksize; 176 rminit(argmap, 177 ((blk / 2) * DEV_BSIZE - CLBYTES) / argdbsize, 178 CLBYTES / argdbsize, "argmap", ARGMAPSIZE); 179 #else SECSIZE 180 rminit(argmap, (long)(blk/2-ctod(CLSIZE)), 181 (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); 182 #endif SECSIZE 183 /* 184 * First of all chunks... initialize the swapmap 185 * the second half of the hunk. 186 */ 187 rminit(swapmap, (long)blk/2, (long)blk/2, 188 "swap", nswapmap); 189 } else if (dvbase == 0) { 190 /* 191 * Don't use the first cluster of the device 192 * in case it starts with a label or boot block. 193 */ 194 rmfree(swapmap, blk - ctod(CLSIZE), 195 vsbase + ctod(CLSIZE)); 196 } else 197 rmfree(swapmap, blk, vsbase); 198 } 199 return (0); 200 } 201