xref: /csrg-svn/sys/vm/vm_swap.c (revision 16695)
1 /*	vm_swap.c	6.2	84/07/08	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/buf.h"
6 #include "../h/conf.h"
7 #include "../h/dir.h"
8 #include "../h/user.h"
9 #include "../h/inode.h"
10 #include "../h/map.h"
11 #include "../h/uio.h"
12 #include "../h/file.h"
13 
14 struct	buf rswbuf;
15 /*
16  * Indirect driver for multi-controller paging.
17  */
18 swstrategy(bp)
19 	register struct buf *bp;
20 {
21 	int sz, off, seg;
22 	dev_t dev;
23 
24 #ifdef GENERIC
25 	/*
26 	 * A mini-root gets copied into the front of the swap
27 	 * and we run over top of the swap area just long
28 	 * enough for us to do a mkfs and restor of the real
29 	 * root (sure beats rewriting standalone restor).
30 	 */
31 #define	MINIROOTSIZE	4096
32 	if (rootdev == dumpdev)
33 		bp->b_blkno += MINIROOTSIZE;
34 #endif
35 	sz = howmany(bp->b_bcount, DEV_BSIZE);
36 	if (bp->b_blkno+sz > nswap) {
37 		bp->b_flags |= B_ERROR;
38 		iodone(bp);
39 		return;
40 	}
41 	if (nswdev > 1) {
42 		off = bp->b_blkno % dmmax;
43 		if (off+sz > dmmax) {
44 			bp->b_flags |= B_ERROR;
45 			iodone(bp);
46 			return;
47 		}
48 		seg = bp->b_blkno / dmmax;
49 		dev = swdevt[seg % nswdev].sw_dev;
50 		seg /= nswdev;
51 		bp->b_blkno = seg*dmmax + off;
52 	} else
53 		dev = swdevt[0].sw_dev;
54 	bp->b_dev = dev;
55 	if (dev == 0)
56 		panic("swstrategy");
57 	(*bdevsw[major(dev)].d_strategy)(bp);
58 }
59 
60 swread(dev, uio)
61 	dev_t dev;
62 	struct uio *uio;
63 {
64 
65 	return (physio(swstrategy, &rswbuf, dev, B_READ, minphys, uio));
66 }
67 
68 swwrite(dev, uio)
69 	dev_t dev;
70 	struct uio *uio;
71 {
72 
73 	return (physio(swstrategy, &rswbuf, dev, B_WRITE, minphys, uio));
74 }
75 
76 /*
77  * System call swapon(name) enables swapping on device name,
78  * which must be in the swdevsw.  Return EBUSY
79  * if already swapping on this device.
80  */
81 swapon()
82 {
83 	struct a {
84 		char	*name;
85 	} *uap = (struct a *)u.u_ap;
86 	register struct inode *ip;
87 	dev_t dev;
88 	register struct swdevt *sp;
89 	register struct nameidata *ndp = &u.u_nd;
90 
91 	ndp->ni_nameiop = LOOKUP | FOLLOW;
92 	ndp->ni_segflg = UIO_USERSPACE;
93 	ndp->ni_dirp = uap->name;
94 	ip = namei(ndp);
95 	if (ip == NULL)
96 		return;
97 	if ((ip->i_mode&IFMT) != IFBLK) {
98 		u.u_error = ENOTBLK;
99 		iput(ip);
100 		return;
101 	}
102 	dev = (dev_t)ip->i_rdev;
103 	iput(ip);
104 	if (major(dev) >= nblkdev) {
105 		u.u_error = ENXIO;
106 		return;
107 	}
108 	/*
109 	 * Search starting at second table entry,
110 	 * since first (primary swap area) is freed at boot.
111 	 */
112 	for (sp = &swdevt[1]; sp->sw_dev; sp++)
113 		if (sp->sw_dev == dev) {
114 			if (sp->sw_freed) {
115 				u.u_error = EBUSY;
116 				return;
117 			}
118 			swfree(sp - swdevt);
119 			return;
120 		}
121 	u.u_error = ENODEV;
122 }
123 
124 /*
125  * Swfree(index) frees the index'th portion of the swap map.
126  * Each of the nswdev devices provides 1/nswdev'th of the swap
127  * space, which is laid out with blocks of dmmax pages circularly
128  * among the devices.
129  */
130 swfree(index)
131 	int index;
132 {
133 	register swblk_t vsbase;
134 	register long blk;
135 	dev_t dev;
136 	register swblk_t dvbase;
137 	register int nblks;
138 
139 	dev = swdevt[index].sw_dev;
140 	(*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE);
141 	swdevt[index].sw_freed = 1;
142 	nblks = swdevt[index].sw_nblks;
143 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
144 		blk = nblks - dvbase;
145 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
146 			panic("swfree");
147 		if (blk > dmmax)
148 			blk = dmmax;
149 		if (vsbase == 0) {
150 			/*
151 			 * Can't free a block starting at 0 in the swapmap
152 			 * but need some space for argmap so use 1/2 this
153 			 * hunk which needs special treatment anyways.
154 			 */
155 			argdev = swdevt[0].sw_dev;
156 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
157 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
158 			/*
159 			 * First of all chunks... initialize the swapmap
160 			 * the second half of the hunk.
161 			 */
162 			rminit(swapmap, (long)blk/2, (long)blk/2,
163 			    "swap", nswapmap);
164 		} else
165 			rmfree(swapmap, blk, vsbase);
166 	}
167 }
168