Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
c4ec2128 KM |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
af359dea C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
c4ec2128 | 20 | * |
af359dea C |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)vm_swap.c 7.18 (Berkeley) 5/6/91 | |
da7c5cc6 | 34 | */ |
013037be | 35 | |
94368568 JB |
36 | #include "param.h" |
37 | #include "systm.h" | |
38 | #include "buf.h" | |
39 | #include "conf.h" | |
be2fd2c3 MK |
40 | #include "proc.h" |
41 | #include "namei.h" | |
42 | #include "dmap.h" /* XXX */ | |
c4ec2128 | 43 | #include "vnode.h" |
0f93ba7b | 44 | #include "specdev.h" |
94368568 | 45 | #include "map.h" |
94368568 | 46 | #include "file.h" |
013037be | 47 | |
013037be BJ |
48 | /* |
49 | * Indirect driver for multi-controller paging. | |
50 | */ | |
be2fd2c3 | 51 | |
af359dea C |
52 | int nswap, nswdev; |
53 | ||
be2fd2c3 MK |
54 | /* |
55 | * Set up swap devices. | |
56 | * Initialize linked list of free swap | |
57 | * headers. These do not actually point | |
58 | * to buffers, but rather to pages that | |
59 | * are being swapped in and out. | |
60 | */ | |
61 | swapinit() | |
62 | { | |
63 | register int i; | |
64 | register struct buf *sp = swbuf; | |
65 | struct swdevt *swp; | |
66 | int error; | |
67 | ||
68 | /* | |
69 | * Count swap devices, and adjust total swap space available. | |
70 | * Some of this space will not be available until a swapon() | |
71 | * system is issued, usually when the system goes multi-user. | |
72 | */ | |
73 | nswdev = 0; | |
74 | nswap = 0; | |
75 | for (swp = swdevt; swp->sw_dev; swp++) { | |
76 | nswdev++; | |
77 | if (swp->sw_nblks > nswap) | |
78 | nswap = swp->sw_nblks; | |
79 | } | |
80 | if (nswdev == 0) | |
81 | panic("swapinit"); | |
82 | if (nswdev > 1) | |
83 | nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; | |
84 | nswap *= nswdev; | |
85 | if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) | |
86 | panic("swapvp"); | |
87 | if (error = swfree(&proc0, 0)) { | |
88 | printf("swfree errno %d\n", error); /* XXX */ | |
89 | panic("swapinit swfree 0"); | |
90 | } | |
91 | ||
92 | /* | |
93 | * Now set up swap buffer headers. | |
94 | */ | |
95 | bswlist.av_forw = sp; | |
96 | for (i = 0; i < nswbuf - 1; i++, sp++) | |
97 | sp->av_forw = sp + 1; | |
98 | sp->av_forw = NULL; | |
99 | } | |
100 | ||
013037be BJ |
101 | swstrategy(bp) |
102 | register struct buf *bp; | |
103 | { | |
ec67a3ce MK |
104 | int sz, off, seg, index; |
105 | register struct swdevt *sp; | |
1c15e888 | 106 | struct vnode *vp; |
013037be | 107 | |
b9ee5d20 BJ |
108 | #ifdef GENERIC |
109 | /* | |
110 | * A mini-root gets copied into the front of the swap | |
111 | * and we run over top of the swap area just long | |
112 | * enough for us to do a mkfs and restor of the real | |
113 | * root (sure beats rewriting standalone restor). | |
114 | */ | |
8c5046eb | 115 | #define MINIROOTSIZE 4096 |
b9ee5d20 BJ |
116 | if (rootdev == dumpdev) |
117 | bp->b_blkno += MINIROOTSIZE; | |
118 | #endif | |
ca1f746a | 119 | sz = howmany(bp->b_bcount, DEV_BSIZE); |
be2fd2c3 | 120 | if (bp->b_blkno + sz > nswap) { |
013037be | 121 | bp->b_flags |= B_ERROR; |
ec67a3ce | 122 | biodone(bp); |
013037be BJ |
123 | return; |
124 | } | |
d668d9ba SL |
125 | if (nswdev > 1) { |
126 | off = bp->b_blkno % dmmax; | |
127 | if (off+sz > dmmax) { | |
128 | bp->b_flags |= B_ERROR; | |
ec67a3ce | 129 | biodone(bp); |
d668d9ba SL |
130 | return; |
131 | } | |
132 | seg = bp->b_blkno / dmmax; | |
ec67a3ce | 133 | index = seg % nswdev; |
d668d9ba SL |
134 | seg /= nswdev; |
135 | bp->b_blkno = seg*dmmax + off; | |
136 | } else | |
ec67a3ce MK |
137 | index = 0; |
138 | sp = &swdevt[index]; | |
1c15e888 | 139 | if ((bp->b_dev = sp->sw_dev) == 0) |
013037be | 140 | panic("swstrategy"); |
1c15e888 C |
141 | if (sp->sw_vp == NULL) { |
142 | bp->b_error |= B_ERROR; | |
143 | biodone(bp); | |
144 | return; | |
145 | } | |
146 | VHOLD(sp->sw_vp); | |
147 | if ((bp->b_flags & B_READ) == 0) { | |
148 | if (vp = bp->b_vp) { | |
149 | vp->v_numoutput--; | |
150 | if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { | |
151 | vp->v_flag &= ~VBWAIT; | |
152 | wakeup((caddr_t)&vp->v_numoutput); | |
153 | } | |
154 | } | |
155 | sp->sw_vp->v_numoutput++; | |
156 | } | |
157 | if (bp->b_vp != NULL) | |
158 | brelvp(bp); | |
159 | bp->b_vp = sp->sw_vp; | |
160 | VOP_STRATEGY(bp); | |
013037be BJ |
161 | } |
162 | ||
013037be BJ |
163 | /* |
164 | * System call swapon(name) enables swapping on device name, | |
165 | * which must be in the swdevsw. Return EBUSY | |
166 | * if already swapping on this device. | |
167 | */ | |
f6c3fd73 KM |
168 | /* ARGSUSED */ |
169 | swapon(p, uap, retval) | |
170 | struct proc *p; | |
171 | struct args { | |
2dfa06c1 | 172 | char *name; |
f6c3fd73 KM |
173 | } *uap; |
174 | int *retval; | |
175 | { | |
c4ec2128 | 176 | register struct vnode *vp; |
013037be | 177 | register struct swdevt *sp; |
be2fd2c3 | 178 | register struct nameidata *ndp; |
f6c3fd73 KM |
179 | dev_t dev; |
180 | int error; | |
be2fd2c3 | 181 | struct nameidata nd; |
013037be | 182 | |
be2fd2c3 | 183 | if (error = suser(p->p_ucred, &p->p_acflag)) |
d9c2f47f | 184 | return (error); |
be2fd2c3 | 185 | ndp = &nd; |
715baff1 KM |
186 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
187 | ndp->ni_segflg = UIO_USERSPACE; | |
188 | ndp->ni_dirp = uap->name; | |
be2fd2c3 | 189 | if (error = namei(ndp, p)) |
d9c2f47f | 190 | return (error); |
c4ec2128 KM |
191 | vp = ndp->ni_vp; |
192 | if (vp->v_type != VBLK) { | |
193 | vrele(vp); | |
d9c2f47f | 194 | return (ENOTBLK); |
013037be | 195 | } |
c4ec2128 | 196 | dev = (dev_t)vp->v_rdev; |
013037be | 197 | if (major(dev) >= nblkdev) { |
c4ec2128 | 198 | vrele(vp); |
d9c2f47f | 199 | return (ENXIO); |
013037be | 200 | } |
ae0ffeb1 | 201 | for (sp = &swdevt[0]; sp->sw_dev; sp++) |
013037be BJ |
202 | if (sp->sw_dev == dev) { |
203 | if (sp->sw_freed) { | |
c4ec2128 | 204 | vrele(vp); |
d9c2f47f | 205 | return (EBUSY); |
013037be | 206 | } |
1c15e888 | 207 | sp->sw_vp = vp; |
af359dea | 208 | if (error = swfree(p, sp - swdevt)) { |
1c15e888 C |
209 | vrele(vp); |
210 | return (error); | |
211 | } | |
d9c2f47f | 212 | return (0); |
013037be | 213 | } |
c4ec2128 | 214 | vrele(vp); |
d9c2f47f | 215 | return (EINVAL); |
013037be BJ |
216 | } |
217 | ||
218 | /* | |
219 | * Swfree(index) frees the index'th portion of the swap map. | |
220 | * Each of the nswdev devices provides 1/nswdev'th of the swap | |
d668d9ba | 221 | * space, which is laid out with blocks of dmmax pages circularly |
013037be BJ |
222 | * among the devices. |
223 | */ | |
be2fd2c3 MK |
224 | swfree(p, index) |
225 | struct proc *p; | |
013037be BJ |
226 | int index; |
227 | { | |
ec67a3ce | 228 | register struct swdevt *sp; |
013037be | 229 | register swblk_t vsbase; |
39d536e6 | 230 | register long blk; |
c4ec2128 | 231 | struct vnode *vp; |
d668d9ba SL |
232 | register swblk_t dvbase; |
233 | register int nblks; | |
ec67a3ce | 234 | int error; |
013037be | 235 | |
ec67a3ce | 236 | sp = &swdevt[index]; |
1c15e888 | 237 | vp = sp->sw_vp; |
af359dea | 238 | if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)) |
ec67a3ce MK |
239 | return (error); |
240 | sp->sw_freed = 1; | |
241 | nblks = sp->sw_nblks; | |
d668d9ba SL |
242 | for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { |
243 | blk = nblks - dvbase; | |
244 | if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) | |
245 | panic("swfree"); | |
246 | if (blk > dmmax) | |
247 | blk = dmmax; | |
013037be | 248 | if (vsbase == 0) { |
c84ff1f9 BJ |
249 | /* |
250 | * First of all chunks... initialize the swapmap | |
251 | * the second half of the hunk. | |
252 | */ | |
c4ec2128 | 253 | rminit(swapmap, (long)(blk/2), (long)(blk/2), |
a29f7995 | 254 | "swap", nswapmap); |
ec67a3ce MK |
255 | } else if (dvbase == 0) { |
256 | /* | |
257 | * Don't use the first cluster of the device | |
258 | * in case it starts with a label or boot block. | |
259 | */ | |
260 | rmfree(swapmap, blk - ctod(CLSIZE), | |
261 | vsbase + ctod(CLSIZE)); | |
013037be | 262 | } else |
c84ff1f9 | 263 | rmfree(swapmap, blk, vsbase); |
013037be | 264 | } |
ec67a3ce | 265 | return (0); |
013037be | 266 | } |