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