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