Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
c4ec2128 KM |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
c4ec2128 | 6 | * |
dd89ed8a | 7 | * @(#)vm_swap.c 7.24 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
013037be | 9 | |
3266719e KB |
10 | #include <sys/param.h> |
11 | #include <sys/systm.h> | |
12 | #include <sys/buf.h> | |
13 | #include <sys/conf.h> | |
14 | #include <sys/proc.h> | |
15 | #include <sys/namei.h> | |
16 | #include <sys/dmap.h> /* XXX */ | |
17 | #include <sys/vnode.h> | |
18 | #include <sys/specdev.h> | |
19 | #include <sys/map.h> | |
20 | #include <sys/file.h> | |
ec67a3ce | 21 | #include "stat.h" |
013037be | 22 | |
013037be BJ |
23 | /* |
24 | * Indirect driver for multi-controller paging. | |
25 | */ | |
be2fd2c3 | 26 | |
fc703211 MK |
27 | int nswap, nswdev; |
28 | ||
be2fd2c3 MK |
29 | /* |
30 | * Set up swap devices. | |
31 | * Initialize linked list of free swap | |
32 | * headers. These do not actually point | |
33 | * to buffers, but rather to pages that | |
34 | * are being swapped in and out. | |
35 | */ | |
3266719e | 36 | void |
be2fd2c3 MK |
37 | swapinit() |
38 | { | |
39 | register int i; | |
40 | register struct buf *sp = swbuf; | |
baaa1646 | 41 | register struct proc *p = &proc0; /* XXX */ |
be2fd2c3 MK |
42 | struct swdevt *swp; |
43 | int error; | |
44 | ||
45 | /* | |
46 | * Count swap devices, and adjust total swap space available. | |
47 | * Some of this space will not be available until a swapon() | |
48 | * system is issued, usually when the system goes multi-user. | |
49 | */ | |
50 | nswdev = 0; | |
51 | nswap = 0; | |
52 | for (swp = swdevt; swp->sw_dev; swp++) { | |
53 | nswdev++; | |
54 | if (swp->sw_nblks > nswap) | |
55 | nswap = swp->sw_nblks; | |
56 | } | |
57 | if (nswdev == 0) | |
58 | panic("swapinit"); | |
59 | if (nswdev > 1) | |
60 | nswap = ((nswap + dmmax - 1) / dmmax) * dmmax; | |
61 | nswap *= nswdev; | |
62 | if (bdevvp(swdevt[0].sw_dev, &swdevt[0].sw_vp)) | |
63 | panic("swapvp"); | |
baaa1646 | 64 | if (error = swfree(p, 0)) { |
be2fd2c3 MK |
65 | printf("swfree errno %d\n", error); /* XXX */ |
66 | panic("swapinit swfree 0"); | |
67 | } | |
68 | ||
69 | /* | |
70 | * Now set up swap buffer headers. | |
71 | */ | |
72 | bswlist.av_forw = sp; | |
baaa1646 | 73 | for (i = 0; i < nswbuf - 1; i++, sp++) { |
be2fd2c3 | 74 | sp->av_forw = sp + 1; |
baaa1646 KM |
75 | sp->b_rcred = sp->b_wcred = p->p_ucred; |
76 | } | |
77 | sp->b_rcred = sp->b_wcred = p->p_ucred; | |
be2fd2c3 MK |
78 | sp->av_forw = NULL; |
79 | } | |
80 | ||
3266719e | 81 | void |
013037be BJ |
82 | swstrategy(bp) |
83 | register struct buf *bp; | |
84 | { | |
ec67a3ce MK |
85 | int sz, off, seg, index; |
86 | register struct swdevt *sp; | |
013037be | 87 | |
b9ee5d20 BJ |
88 | #ifdef GENERIC |
89 | /* | |
90 | * A mini-root gets copied into the front of the swap | |
91 | * and we run over top of the swap area just long | |
92 | * enough for us to do a mkfs and restor of the real | |
93 | * root (sure beats rewriting standalone restor). | |
94 | */ | |
8c5046eb | 95 | #define MINIROOTSIZE 4096 |
b9ee5d20 BJ |
96 | if (rootdev == dumpdev) |
97 | bp->b_blkno += MINIROOTSIZE; | |
98 | #endif | |
ca1f746a | 99 | sz = howmany(bp->b_bcount, DEV_BSIZE); |
be2fd2c3 | 100 | if (bp->b_blkno + sz > nswap) { |
013037be | 101 | bp->b_flags |= B_ERROR; |
ec67a3ce | 102 | biodone(bp); |
013037be BJ |
103 | return; |
104 | } | |
d668d9ba SL |
105 | if (nswdev > 1) { |
106 | off = bp->b_blkno % dmmax; | |
107 | if (off+sz > dmmax) { | |
108 | bp->b_flags |= B_ERROR; | |
ec67a3ce | 109 | biodone(bp); |
d668d9ba SL |
110 | return; |
111 | } | |
112 | seg = bp->b_blkno / dmmax; | |
ec67a3ce | 113 | index = seg % nswdev; |
d668d9ba SL |
114 | seg /= nswdev; |
115 | bp->b_blkno = seg*dmmax + off; | |
116 | } else | |
ec67a3ce MK |
117 | index = 0; |
118 | sp = &swdevt[index]; | |
119 | #ifdef SECSIZE | |
120 | bp->b_blkno <<= sp->sw_bshift; | |
121 | bp->b_blksize = sp->sw_blksize; | |
122 | #endif SECSIZE | |
123 | bp->b_dev = sp->sw_dev; | |
124 | if (bp->b_dev == 0) | |
013037be | 125 | panic("swstrategy"); |
ec67a3ce | 126 | (*bdevsw[major(bp->b_dev)].d_strategy)(bp); |
013037be BJ |
127 | } |
128 | ||
013037be BJ |
129 | /* |
130 | * System call swapon(name) enables swapping on device name, | |
131 | * which must be in the swdevsw. Return EBUSY | |
132 | * if already swapping on this device. | |
133 | */ | |
dd89ed8a CT |
134 | struct swapon_args { |
135 | char *name; | |
136 | }; | |
f6c3fd73 | 137 | /* ARGSUSED */ |
3266719e | 138 | int |
f6c3fd73 KM |
139 | swapon(p, uap, retval) |
140 | struct proc *p; | |
dd89ed8a | 141 | struct swapon_args *uap; |
f6c3fd73 KM |
142 | int *retval; |
143 | { | |
c4ec2128 | 144 | register struct vnode *vp; |
013037be | 145 | register struct swdevt *sp; |
f6c3fd73 KM |
146 | dev_t dev; |
147 | int error; | |
be2fd2c3 | 148 | struct nameidata nd; |
013037be | 149 | |
be2fd2c3 | 150 | if (error = suser(p->p_ucred, &p->p_acflag)) |
d9c2f47f | 151 | return (error); |
56b1696d KM |
152 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->name, p); |
153 | if (error = namei(&nd)) | |
d9c2f47f | 154 | return (error); |
56b1696d | 155 | vp = nd.ni_vp; |
c4ec2128 KM |
156 | if (vp->v_type != VBLK) { |
157 | vrele(vp); | |
d9c2f47f | 158 | return (ENOTBLK); |
013037be | 159 | } |
c4ec2128 | 160 | dev = (dev_t)vp->v_rdev; |
013037be | 161 | if (major(dev) >= nblkdev) { |
c4ec2128 | 162 | vrele(vp); |
d9c2f47f | 163 | return (ENXIO); |
013037be | 164 | } |
ae0ffeb1 | 165 | for (sp = &swdevt[0]; sp->sw_dev; sp++) |
013037be BJ |
166 | if (sp->sw_dev == dev) { |
167 | if (sp->sw_freed) { | |
c4ec2128 | 168 | vrele(vp); |
d9c2f47f | 169 | return (EBUSY); |
013037be | 170 | } |
ec67a3ce | 171 | u.u_error = swfree(sp - swdevt); |
d9c2f47f | 172 | return (0); |
013037be | 173 | } |
c4ec2128 | 174 | vrele(vp); |
d9c2f47f | 175 | return (EINVAL); |
013037be BJ |
176 | } |
177 | ||
ec67a3ce MK |
178 | #ifdef SECSIZE |
179 | long argdbsize; /* XXX */ | |
180 | ||
181 | #endif SECSIZE | |
013037be BJ |
182 | /* |
183 | * Swfree(index) frees the index'th portion of the swap map. | |
184 | * Each of the nswdev devices provides 1/nswdev'th of the swap | |
d668d9ba | 185 | * space, which is laid out with blocks of dmmax pages circularly |
013037be BJ |
186 | * among the devices. |
187 | */ | |
3266719e | 188 | int |
be2fd2c3 MK |
189 | swfree(p, index) |
190 | struct proc *p; | |
013037be BJ |
191 | int index; |
192 | { | |
609e7cfa | 193 | register struct swdevt *sp; |
ec67a3ce | 194 | register struct swdevt *sp; |
013037be | 195 | register swblk_t vsbase; |
39d536e6 | 196 | register long blk; |
c4ec2128 | 197 | struct vnode *vp; |
d668d9ba SL |
198 | register swblk_t dvbase; |
199 | register int nblks; | |
ec67a3ce | 200 | int error; |
609e7cfa | 201 | int error; |
013037be | 202 | |
ec67a3ce MK |
203 | sp = &swdevt[index]; |
204 | dev = sp->sw_dev; | |
205 | if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK)) | |
206 | return (error); | |
207 | sp->sw_freed = 1; | |
208 | nblks = sp->sw_nblks; | |
d668d9ba SL |
209 | for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { |
210 | blk = nblks - dvbase; | |
211 | if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) | |
212 | panic("swfree"); | |
213 | if (blk > dmmax) | |
214 | blk = dmmax; | |
013037be | 215 | if (vsbase == 0) { |
c84ff1f9 BJ |
216 | /* |
217 | * First of all chunks... initialize the swapmap | |
218 | * the second half of the hunk. | |
219 | */ | |
c4ec2128 | 220 | rminit(swapmap, (long)(blk/2), (long)(blk/2), |
a29f7995 | 221 | "swap", nswapmap); |
ec67a3ce MK |
222 | } else if (dvbase == 0) { |
223 | /* | |
224 | * Don't use the first cluster of the device | |
225 | * in case it starts with a label or boot block. | |
226 | */ | |
227 | rmfree(swapmap, blk - ctod(CLSIZE), | |
228 | vsbase + ctod(CLSIZE)); | |
609e7cfa MK |
229 | } else if (dvbase == 0) { |
230 | /* | |
231 | * Don't use the first cluster of the device | |
232 | * in case it starts with a label or boot block. | |
233 | */ | |
234 | rmfree(swapmap, blk - ctod(CLSIZE), | |
235 | vsbase + ctod(CLSIZE)); | |
013037be | 236 | } else |
c84ff1f9 | 237 | rmfree(swapmap, blk, vsbase); |
013037be | 238 | } |
ec67a3ce | 239 | return (0); |
609e7cfa | 240 | return (0); |
013037be | 241 | } |