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