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