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