xref: /csrg-svn/sys/vm/vm_swap.c (revision 37552)
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.4 (Berkeley) 04/26/89
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 /*
22  * Indirect driver for multi-controller paging.
23  */
24 swstrategy(bp)
25 	register struct buf *bp;
26 {
27 	int sz, off, seg, index;
28 	register struct swdevt *sp;
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 	bp->b_dev = sp->sw_dev;
62 	if (bp->b_dev == 0)
63 		panic("swstrategy");
64 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
65 }
66 
67 /*
68  * System call swapon(name) enables swapping on device name,
69  * which must be in the swdevsw.  Return EBUSY
70  * if already swapping on this device.
71  */
72 swapon()
73 {
74 	struct a {
75 		char	*name;
76 	} *uap = (struct a *)u.u_ap;
77 	register struct inode *ip;
78 	dev_t dev;
79 	register struct swdevt *sp;
80 	register struct nameidata *ndp = &u.u_nd;
81 
82 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
83 		return;
84 	ndp->ni_nameiop = LOOKUP | FOLLOW;
85 	ndp->ni_segflg = UIO_USERSPACE;
86 	ndp->ni_dirp = uap->name;
87 	ip = namei(ndp);
88 	if (ip == NULL)
89 		return;
90 	if ((ip->i_mode&IFMT) != IFBLK) {
91 		u.u_error = ENOTBLK;
92 		iput(ip);
93 		return;
94 	}
95 	dev = (dev_t)ip->i_rdev;
96 	iput(ip);
97 	if (major(dev) >= nblkdev) {
98 		u.u_error = ENXIO;
99 		return;
100 	}
101 	for (sp = &swdevt[0]; sp->sw_dev; sp++)
102 		if (sp->sw_dev == dev) {
103 			if (sp->sw_freed) {
104 				u.u_error = EBUSY;
105 				return;
106 			}
107 			u.u_error = swfree(sp - swdevt);
108 			return;
109 		}
110 	u.u_error = EINVAL;
111 }
112 
113 /*
114  * Swfree(index) frees the index'th portion of the swap map.
115  * Each of the nswdev devices provides 1/nswdev'th of the swap
116  * space, which is laid out with blocks of dmmax pages circularly
117  * among the devices.
118  */
119 swfree(index)
120 	int index;
121 {
122 	register struct swdevt *sp;
123 	register swblk_t vsbase;
124 	register long blk;
125 	dev_t dev;
126 	register swblk_t dvbase;
127 	register int nblks;
128 	int error;
129 
130 	sp = &swdevt[index];
131 	dev = sp->sw_dev;
132 	if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK))
133 		return (error);
134 	sp->sw_freed = 1;
135 	nblks = sp->sw_nblks;
136 	for (dvbase = 0; dvbase < nblks; dvbase += dmmax) {
137 		blk = nblks - dvbase;
138 		if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap)
139 			panic("swfree");
140 		if (blk > dmmax)
141 			blk = dmmax;
142 		if (vsbase == 0) {
143 			/*
144 			 * Can't free a block starting at 0 in the swapmap
145 			 * but need some space for argmap so use 1/2 this
146 			 * hunk which needs special treatment anyways.
147 			 */
148 			argdev = sp->sw_dev;
149 			rminit(argmap, (long)(blk/2-ctod(CLSIZE)),
150 			    (long)ctod(CLSIZE), "argmap", ARGMAPSIZE);
151 			/*
152 			 * First of all chunks... initialize the swapmap
153 			 * the second half of the hunk.
154 			 */
155 			rminit(swapmap, (long)blk/2, (long)blk/2,
156 			    "swap", nswapmap);
157 		} else if (dvbase == 0) {
158 			/*
159 			 * Don't use the first cluster of the device
160 			 * in case it starts with a label or boot block.
161 			 */
162 			rmfree(swapmap, blk - ctod(CLSIZE),
163 			    vsbase + ctod(CLSIZE));
164 		} else
165 			rmfree(swapmap, blk, vsbase);
166 	}
167 	return (0);
168 }
169