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