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