xref: /original-bsd/sys/vm/vm_swap.c (revision feb5f8e2)
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.15 (Berkeley) 12/05/90
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "buf.h"
13 #include "conf.h"
14 #include "user.h"
15 #include "vnode.h"
16 #include "specdev.h"
17 #include "map.h"
18 #include "file.h"
19 
20 /*
21  * Indirect driver for multi-controller paging.
22  */
23 swstrategy(bp)
24 	register struct buf *bp;
25 {
26 	int sz, off, seg, index;
27 	register struct swdevt *sp;
28 	struct vnode *vp;
29 
30 #ifdef GENERIC
31 	/*
32 	 * A mini-root gets copied into the front of the swap
33 	 * and we run over top of the swap area just long
34 	 * enough for us to do a mkfs and restor of the real
35 	 * root (sure beats rewriting standalone restor).
36 	 */
37 #define	MINIROOTSIZE	4096
38 	if (rootdev == dumpdev)
39 		bp->b_blkno += MINIROOTSIZE;
40 #endif
41 	sz = howmany(bp->b_bcount, DEV_BSIZE);
42 	if (bp->b_blkno+sz > nswap) {
43 		bp->b_flags |= B_ERROR;
44 		biodone(bp);
45 		return;
46 	}
47 	if (nswdev > 1) {
48 		off = bp->b_blkno % dmmax;
49 		if (off+sz > dmmax) {
50 			bp->b_flags |= B_ERROR;
51 			biodone(bp);
52 			return;
53 		}
54 		seg = bp->b_blkno / dmmax;
55 		index = seg % nswdev;
56 		seg /= nswdev;
57 		bp->b_blkno = seg*dmmax + off;
58 	} else
59 		index = 0;
60 	sp = &swdevt[index];
61 	if ((bp->b_dev = sp->sw_dev) == 0)
62 		panic("swstrategy");
63 	if (sp->sw_vp == NULL) {
64 		bp->b_error |= B_ERROR;
65 		biodone(bp);
66 		return;
67 	}
68 	VHOLD(sp->sw_vp);
69 	if ((bp->b_flags & B_READ) == 0) {
70 		if (vp = bp->b_vp) {
71 			vp->v_numoutput--;
72 			if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
73 				vp->v_flag &= ~VBWAIT;
74 				wakeup((caddr_t)&vp->v_numoutput);
75 			}
76 		}
77 		sp->sw_vp->v_numoutput++;
78 	}
79 	if (bp->b_vp != NULL)
80 		brelvp(bp);
81 	bp->b_vp = sp->sw_vp;
82 	VOP_STRATEGY(bp);
83 }
84 
85 /*
86  * System call swapon(name) enables swapping on device name,
87  * which must be in the swdevsw.  Return EBUSY
88  * if already swapping on this device.
89  */
90 /* ARGSUSED */
91 swapon(p, uap, retval)
92 	struct proc *p;
93 	struct args {
94 		char	*name;
95 	} *uap;
96 	int *retval;
97 {
98 	register struct vnode *vp;
99 	register struct swdevt *sp;
100 	register struct nameidata *ndp = &u.u_nd;
101 	dev_t dev;
102 	int error;
103 
104 	if (error = suser(u.u_cred, &u.u_acflag))
105 		return (error);
106 	ndp->ni_nameiop = LOOKUP | FOLLOW;
107 	ndp->ni_segflg = UIO_USERSPACE;
108 	ndp->ni_dirp = uap->name;
109 	if (error = namei(ndp))
110 		return (error);
111 	vp = ndp->ni_vp;
112 	if (vp->v_type != VBLK) {
113 		vrele(vp);
114 		return (ENOTBLK);
115 	}
116 	dev = (dev_t)vp->v_rdev;
117 	if (major(dev) >= nblkdev) {
118 		vrele(vp);
119 		return (ENXIO);
120 	}
121 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
122 		if (sp->sw_dev == dev) {
123 			if (sp->sw_freed) {
124 				vrele(vp);
125 				return (EBUSY);
126 			}
127 			sp->sw_vp = vp;
128 			if (error = swfree(sp - swdevt)) {
129 				vrele(vp);
130 				return (error);
131 			}
132 			return (0);
133 		}
134 	vrele(vp);
135 	return (EINVAL);
136 }
137 
138 /*
139  * Swfree(index) frees the index'th portion of the swap map.
140  * Each of the nswdev devices provides 1/nswdev'th of the swap
141  * space, which is laid out with blocks of dmmax pages circularly
142  * among the devices.
143  */
144 swfree(index)
145 	int index;
146 {
147 	register struct swdevt *sp;
148 	register swblk_t vsbase;
149 	register long blk;
150 	struct vnode *vp;
151 	register swblk_t dvbase;
152 	register int nblks;
153 	int error;
154 
155 	sp = &swdevt[index];
156 	vp = sp->sw_vp;
157 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
158 		return (error);
159 	sp->sw_freed = 1;
160 	nblks = sp->sw_nblks;
161 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
162 		blk = nblks - dvbase;
163 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
164 			panic("swfree");
165 		if (blk > dmmax)
166 			blk = dmmax;
167 		if (vsbase == 0) {
168 			/*
169 			 * First of all chunks... initialize the swapmap
170 			 * the second half of the hunk.
171 			 */
172 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
173 			    "swap", nswapmap);
174 		} else if (dvbase == 0) {
175 			/*
176 			 * Don't use the first cluster of the device
177 			 * in case it starts with a label or boot block.
178 			 */
179 			rmfree(swapmap, blk - ctod(CLSIZE),
180 			    vsbase + ctod(CLSIZE));
181 		} else
182 			rmfree(swapmap, blk, vsbase);
183 	}
184 	return (0);
185 }
186