xref: /csrg-svn/sys/vm/vm_swap.c (revision 30750)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)vm_swap.c	7.1.1.1 (Berkeley) 04/02/87
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "buf.h"
12 #include "conf.h"
13 #include "dir.h"
14 #include "user.h"
15 #include "inode.h"
16 #include "map.h"
17 #include "uio.h"
18 #include "file.h"
19 #include "stat.h"
20 
21 struct	buf rswbuf;
22 /*
23  * Indirect driver for multi-controller paging.
24  */
25 swstrategy(bp)
26 	register struct buf *bp;
27 {
28 	int sz, off, seg, index;
29 	register struct swdevt *sp;
30 
31 #ifdef GENERIC
32 	/*
33 	 * A mini-root gets copied into the front of the swap
34 	 * and we run over top of the swap area just long
35 	 * enough for us to do a mkfs and restor of the real
36 	 * root (sure beats rewriting standalone restor).
37 	 */
38 #define	MINIROOTSIZE	4096
39 	if (rootdev == dumpdev)
40 		bp->b_blkno += MINIROOTSIZE;
41 #endif
42 	sz = howmany(bp->b_bcount, DEV_BSIZE);
43 	if (bp->b_blkno+sz > nswap) {
44 		bp->b_flags |= B_ERROR;
45 		biodone(bp);
46 		return;
47 	}
48 	if (nswdev > 1) {
49 		off = bp->b_blkno % dmmax;
50 		if (off+sz > dmmax) {
51 			bp->b_flags |= B_ERROR;
52 			biodone(bp);
53 			return;
54 		}
55 		seg = bp->b_blkno / dmmax;
56 		index = seg % nswdev;
57 		seg /= nswdev;
58 		bp->b_blkno = seg*dmmax + off;
59 	} else
60 		index = 0;
61 	sp = &swdevt[index];
62 #ifdef SECSIZE
63 	bp->b_blkno <<= sp->sw_bshift;
64 	bp->b_blksize = sp->sw_blksize;
65 #endif SECSIZE
66 	bp->b_dev = sp->sw_dev;
67 	if (bp->b_dev == 0)
68 		panic("swstrategy");
69 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
70 }
71 
72 swread(dev, uio)
73 	dev_t dev;
74 	struct uio *uio;
75 {
76 
77 	return (physio(swstrategy, &rswbuf, dev, B_READ, minphys, uio));
78 }
79 
80 swwrite(dev, uio)
81 	dev_t dev;
82 	struct uio *uio;
83 {
84 
85 	return (physio(swstrategy, &rswbuf, dev, B_WRITE, minphys, uio));
86 }
87 
88 /*
89  * System call swapon(name) enables swapping on device name,
90  * which must be in the swdevsw.  Return EBUSY
91  * if already swapping on this device.
92  */
93 swapon()
94 {
95 	struct a {
96 		char	*name;
97 	} *uap = (struct a *)u.u_ap;
98 	register struct inode *ip;
99 	dev_t dev;
100 	register struct swdevt *sp;
101 	register struct nameidata *ndp = &u.u_nd;
102 
103 	if (!suser())
104 		return;
105 	ndp->ni_nameiop = LOOKUP | FOLLOW;
106 	ndp->ni_segflg = UIO_USERSPACE;
107 	ndp->ni_dirp = uap->name;
108 	ip = namei(ndp);
109 	if (ip == NULL)
110 		return;
111 	if ((ip->i_mode&IFMT) != IFBLK) {
112 		u.u_error = ENOTBLK;
113 		iput(ip);
114 		return;
115 	}
116 	dev = (dev_t)ip->i_rdev;
117 	iput(ip);
118 	if (major(dev) >= nblkdev) {
119 		u.u_error = ENXIO;
120 		return;
121 	}
122 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
123 		if (sp->sw_dev == dev) {
124 			if (sp->sw_freed) {
125 				u.u_error = EBUSY;
126 				return;
127 			}
128 			u.u_error = swfree(sp - swdevt);
129 			return;
130 		}
131 	u.u_error = EINVAL;
132 }
133 
134 #ifdef SECSIZE
135 long	argdbsize;		/* XXX */
136 
137 #endif SECSIZE
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 	dev_t dev;
151 	register swblk_t dvbase;
152 	register int nblks;
153 	int error;
154 
155 	sp = &swdevt[index];
156 	dev = sp->sw_dev;
157 	if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK))
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 			 * Can't free a block starting at 0 in the swapmap
170 			 * but need some space for argmap so use 1/2 this
171 			 * hunk which needs special treatment anyways.
172 			 */
173 			argdev = sp->sw_dev;
174 #ifdef SECSIZE
175 			argdbsize = sp->sw_blksize;
176 			rminit(argmap,
177 			   ((blk / 2) * DEV_BSIZE - CLBYTES) / argdbsize,
178 			   CLBYTES / argdbsize, "argmap", ARGMAPSIZE);
179 #else SECSIZE
180 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
181 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
182 #endif SECSIZE
183 			/*
184 			 * First of all chunks... initialize the swapmap
185 			 * the second half of the hunk.
186 			 */
187 			rminit(swapmap, (long)blk/2, (long)blk/2,
188 			    "swap", nswapmap);
189 		} else if (dvbase == 0) {
190 			/*
191 			 * Don't use the first cluster of the device
192 			 * in case it starts with a label or boot block.
193 			 */
194 			rmfree(swapmap, blk - ctod(CLSIZE),
195 			    vsbase + ctod(CLSIZE));
196 		} else
197 			rmfree(swapmap, blk, vsbase);
198 	}
199 	return (0);
200 }
201