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