xref: /csrg-svn/sys/vm/vm_swap.c (revision 30751)
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