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