This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / vm / vm_swap.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
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.
20 *
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 *
78ed81a3 33 * from: @(#)vm_swap.c 7.18 (Berkeley) 5/6/91
34 * $Id$
15637ed4 35 */
15637ed4
RG
36
37#include "param.h"
38#include "systm.h"
39#include "buf.h"
40#include "conf.h"
41#include "proc.h"
42#include "namei.h"
43#include "dmap.h" /* XXX */
44#include "vnode.h"
45#include "specdev.h"
46#include "file.h"
47#include "rlist.h"
48
49/*
50 * Indirect driver for multi-controller paging.
51 */
52
53int nswap, nswdev;
54
55/*
56 * Set up swap devices.
57 * Initialize linked list of free swap
58 * headers. These do not actually point
59 * to buffers, but rather to pages that
60 * are being swapped in and out.
61 */
62swapinit()
63{
64 register int i;
65 register struct buf *sp = swbuf;
66 struct swdevt *swp;
67 int error;
68
69 /*
70 * Count swap devices, and adjust total swap space available.
71 * Some of this space will not be available until a swapon()
72 * system is issued, usually when the system goes multi-user.
73 */
74 nswdev = 0;
75 nswap = 0;
76 for (swp = swdevt; swp->sw_dev; swp++) {
77 nswdev++;
78 if (swp->sw_nblks > nswap)
79 nswap = swp->sw_nblks;
80 }
81 if (nswdev == 0)
82 panic("swapinit");
83 if (nswdev > 1)
84 nswap = ((nswap + dmmax - 1) / dmmax) * dmmax;
85 nswap *= nswdev;
86 if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp))
87 panic("swapvp");
88 if (error = swfree(&proc0, 0)) {
89 printf("\nwarning: no swap space present (yet)\n");
90 /* printf("(swfree (..., 0) -> %d)\n", error); /* XXX */
91 /*panic("swapinit swfree 0");*/
92 }
93
94 /*
95 * Now set up swap buffer headers.
96 */
97 bswlist.av_forw = sp;
98 for (i = 0; i < nswbuf - 1; i++, sp++)
99 sp->av_forw = sp + 1;
100 sp->av_forw = NULL;
101}
102
103swstrategy(bp)
104 register struct buf *bp;
105{
106 int sz, off, seg, index;
107 register struct swdevt *sp;
108 struct vnode *vp;
109
110#ifdef GENERIC
111 /*
112 * A mini-root gets copied into the front of the swap
113 * and we run over top of the swap area just long
114 * enough for us to do a mkfs and restor of the real
115 * root (sure beats rewriting standalone restor).
116 */
117#define MINIROOTSIZE 4096
118 if (rootdev == dumpdev)
119 bp->b_blkno += MINIROOTSIZE;
120#endif
121 sz = howmany(bp->b_bcount, DEV_BSIZE);
122 if (bp->b_blkno + sz > nswap) {
123 bp->b_flags |= B_ERROR;
124 biodone(bp);
125 return;
126 }
127 if (nswdev > 1) {
128 off = bp->b_blkno % dmmax;
129 if (off+sz > dmmax) {
130 bp->b_flags |= B_ERROR;
131 biodone(bp);
132 return;
133 }
134 seg = bp->b_blkno / dmmax;
135 index = seg % nswdev;
136 seg /= nswdev;
137 bp->b_blkno = seg*dmmax + off;
138 } else
139 index = 0;
140 sp = &swdevt[index];
141 if ((bp->b_dev = sp->sw_dev) == 0)
142 panic("swstrategy");
143 if (sp->sw_vp == NULL) {
144 bp->b_error |= B_ERROR;
145 biodone(bp);
146 return;
147 }
148 VHOLD(sp->sw_vp);
149 if ((bp->b_flags & B_READ) == 0) {
150 if (vp = bp->b_vp) {
151 vp->v_numoutput--;
152 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
153 vp->v_flag &= ~VBWAIT;
154 wakeup((caddr_t)&vp->v_numoutput);
155 }
156 }
157 sp->sw_vp->v_numoutput++;
158 }
159 if (bp->b_vp != NULL)
160 brelvp(bp);
161 bp->b_vp = sp->sw_vp;
162 VOP_STRATEGY(bp);
163}
164
165/*
166 * System call swapon(name) enables swapping on device name,
167 * which must be in the swdevsw. Return EBUSY
168 * if already swapping on this device.
169 */
78ed81a3 170
171struct swapon_args {
172 char *name;
173};
174
15637ed4
RG
175/* ARGSUSED */
176swapon(p, uap, retval)
177 struct proc *p;
78ed81a3 178 struct swapon_args *uap;
15637ed4
RG
179 int *retval;
180{
181 register struct vnode *vp;
182 register struct swdevt *sp;
183 register struct nameidata *ndp;
184 dev_t dev;
185 int error;
186 struct nameidata nd;
187
188 if (error = suser(p->p_ucred, &p->p_acflag))
189 return (error);
190 ndp = &nd;
191 ndp->ni_nameiop = LOOKUP | FOLLOW;
192 ndp->ni_segflg = UIO_USERSPACE;
193 ndp->ni_dirp = uap->name;
194 if (error = namei(ndp, p))
195 return (error);
196 vp = ndp->ni_vp;
197 if (vp->v_type != VBLK) {
198 vrele(vp);
199 return (ENOTBLK);
200 }
201 dev = (dev_t)vp->v_rdev;
202 if (major(dev) >= nblkdev) {
203 vrele(vp);
204 return (ENXIO);
205 }
206 for (sp = &swdevt[0]; sp->sw_dev; sp++)
207 if (sp->sw_dev == dev) {
208 if (sp->sw_freed) {
209 vrele(vp);
210 return (EBUSY);
211 }
212 sp->sw_vp = vp;
15637ed4 213 if (error = swfree(p, sp - swdevt)) {
78ed81a3 214 printf("swap failed! (unchanged)\n");
15637ed4
RG
215 vrele(vp);
216 return (error);
217 }
218 return (0);
219 }
220 vrele(vp);
221 return (EINVAL);
222}
223
224/*
225 * Swfree(index) frees the index'th portion of the swap map.
226 * Each of the nswdev devices provides 1/nswdev'th of the swap
227 * space, which is laid out with blocks of dmmax pages circularly
228 * among the devices.
229 */
230swfree(p, index)
231 struct proc *p;
232 int index;
233{
234 register struct swdevt *sp;
235 register swblk_t vsbase;
236 register long blk;
237 struct vnode *vp;
238 register swblk_t dvbase;
239 register int nblks;
240 int error;
241
242 sp = &swdevt[index];
243 nblks = sp->sw_nblks;
244 if (nblks <= 0)
245 return(ENXIO);
246 vp = sp->sw_vp;
247 if (error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p))
248 return (error);
249 sp->sw_freed = 1;
250
251 /*printf("%d blocks from device %d/%d ",
252 sp->sw_nblks, major(sp->sw_dev), minor(sp->sw_dev));*/
253 for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
254 blk = nblks - dvbase;
255 if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
256 panic("swfree");
257 if (blk > dmmax)
258 blk = dmmax;
259 rlist_free(&swapmap, vsbase, vsbase + blk - 1);
260 }
261 return (0);
262}