xref: /original-bsd/sys/vm/vm_swap.c (revision c73c5200)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)vm_swap.c	7.6 (Berkeley) 06/27/89
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "buf.h"
23 #include "conf.h"
24 #include "user.h"
25 #include "vnode.h"
26 #include "map.h"
27 #include "file.h"
28 
29 /*
30  * Indirect driver for multi-controller paging.
31  */
32 swstrategy(bp)
33 	register struct buf *bp;
34 {
35 	int sz, off, seg, index;
36 	register struct swdevt *sp;
37 
38 #ifdef GENERIC
39 	/*
40 	 * A mini-root gets copied into the front of the swap
41 	 * and we run over top of the swap area just long
42 	 * enough for us to do a mkfs and restor of the real
43 	 * root (sure beats rewriting standalone restor).
44 	 */
45 #define	MINIROOTSIZE	4096
46 	if (rootdev == dumpdev)
47 		bp->b_blkno += MINIROOTSIZE;
48 #endif
49 	sz = howmany(bp->b_bcount, DEV_BSIZE);
50 	if (bp->b_blkno+sz > nswap) {
51 		bp->b_flags |= B_ERROR;
52 		biodone(bp);
53 		return;
54 	}
55 	if (nswdev > 1) {
56 		off = bp->b_blkno % dmmax;
57 		if (off+sz > dmmax) {
58 			bp->b_flags |= B_ERROR;
59 			biodone(bp);
60 			return;
61 		}
62 		seg = bp->b_blkno / dmmax;
63 		index = seg % nswdev;
64 		seg /= nswdev;
65 		bp->b_blkno = seg*dmmax + off;
66 	} else
67 		index = 0;
68 	sp = &swdevt[index];
69 	bp->b_dev = sp->sw_dev;
70 	if (bp->b_dev == 0)
71 		panic("swstrategy");
72 	if (bp->b_vp)
73 		brelvp(bp);
74 	VREF(sp->sw_vp);
75 	bp->b_vp = sp->sw_vp;
76 	VOP_STRATEGY(bp);
77 }
78 
79 /*
80  * System call swapon(name) enables swapping on device name,
81  * which must be in the swdevsw.  Return EBUSY
82  * if already swapping on this device.
83  */
84 swapon()
85 {
86 	struct a {
87 		char	*name;
88 	} *uap = (struct a *)u.u_ap;
89 	register struct vnode *vp;
90 	dev_t dev;
91 	register struct swdevt *sp;
92 	register struct nameidata *ndp = &u.u_nd;
93 
94 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
95 		return;
96 	ndp->ni_nameiop = LOOKUP | FOLLOW;
97 	ndp->ni_segflg = UIO_USERSPACE;
98 	ndp->ni_dirp = uap->name;
99 	if (u.u_error = namei(ndp))
100 		return;
101 	vp = ndp->ni_vp;
102 	if (vp->v_type != VBLK) {
103 		vrele(vp);
104 		u.u_error = ENOTBLK;
105 		return;
106 	}
107 	dev = (dev_t)vp->v_rdev;
108 	if (major(dev) >= nblkdev) {
109 		vrele(vp);
110 		u.u_error = ENXIO;
111 		return;
112 	}
113 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
114 		if (sp->sw_dev == dev) {
115 			if (sp->sw_freed) {
116 				vrele(vp);
117 				u.u_error = EBUSY;
118 				return;
119 			}
120 			sp->sw_vp = vp;
121 			if (u.u_error = swfree(sp - swdevt)) {
122 				vrele(vp);
123 				return;
124 			}
125 			return;
126 		}
127 	vrele(vp);
128 	u.u_error = EINVAL;
129 }
130 
131 /*
132  * Swfree(index) frees the index'th portion of the swap map.
133  * Each of the nswdev devices provides 1/nswdev'th of the swap
134  * space, which is laid out with blocks of dmmax pages circularly
135  * among the devices.
136  */
137 swfree(index)
138 	int index;
139 {
140 	register struct swdevt *sp;
141 	register swblk_t vsbase;
142 	register long blk;
143 	struct vnode *vp;
144 	register swblk_t dvbase;
145 	register int nblks;
146 	int error;
147 
148 	sp = &swdevt[index];
149 	vp = sp->sw_vp;
150 	if (error = VOP_OPEN(vp, FREAD|FWRITE, u.u_cred))
151 		return (error);
152 	sp->sw_freed = 1;
153 	nblks = sp->sw_nblks;
154 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
155 		blk = nblks - dvbase;
156 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
157 			panic("swfree");
158 		if (blk > dmmax)
159 			blk = dmmax;
160 		if (vsbase == 0) {
161 			/*
162 			 * Can't free a block starting at 0 in the swapmap
163 			 * but need some space for argmap so use 1/2 this
164 			 * hunk which needs special treatment anyways.
165 			 */
166 			argdev = sp->sw_dev;
167 			if (argdev_vp)
168 				vrele(argdev_vp);
169 			VREF(vp);
170 			argdev_vp = vp;
171 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
172 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
173 			/*
174 			 * First of all chunks... initialize the swapmap
175 			 * the second half of the hunk.
176 			 */
177 			rminit(swapmap, (long)(blk/2), (long)(blk/2),
178 			    "swap", nswapmap);
179 		} else if (dvbase == 0) {
180 			/*
181 			 * Don't use the first cluster of the device
182 			 * in case it starts with a label or boot block.
183 			 */
184 			rmfree(swapmap, blk - ctod(CLSIZE),
185 			    vsbase + ctod(CLSIZE));
186 		} else
187 			rmfree(swapmap, blk, vsbase);
188 	}
189 	return (0);
190 }
191