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 | * |
c4ec2128 KM |
5 | * Redistribution and use in source and binary forms are permitted |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
16 | * | |
0f93ba7b | 17 | * @(#)vm_swap.c 7.11 (Berkeley) %G% |
da7c5cc6 | 18 | */ |
013037be | 19 | |
94368568 JB |
20 | #include "param.h" |
21 | #include "systm.h" | |
22 | #include "buf.h" | |
23 | #include "conf.h" | |
94368568 | 24 | #include "user.h" |
c4ec2128 | 25 | #include "vnode.h" |
0f93ba7b | 26 | #include "specdev.h" |
94368568 | 27 | #include "map.h" |
94368568 | 28 | #include "file.h" |
ec67a3ce | 29 | #include "stat.h" |
013037be | 30 | |
013037be BJ |
31 | /* |
32 | * Indirect driver for multi-controller paging. | |
33 | */ | |
34 | swstrategy(bp) | |
35 | register struct buf *bp; | |
36 | { | |
ec67a3ce MK |
37 | int sz, off, seg, index; |
38 | register struct swdevt *sp; | |
013037be | 39 | |
b9ee5d20 BJ |
40 | #ifdef GENERIC |
41 | /* | |
42 | * A mini-root gets copied into the front of the swap | |
43 | * and we run over top of the swap area just long | |
44 | * enough for us to do a mkfs and restor of the real | |
45 | * root (sure beats rewriting standalone restor). | |
46 | */ | |
8c5046eb | 47 | #define MINIROOTSIZE 4096 |
b9ee5d20 BJ |
48 | if (rootdev == dumpdev) |
49 | bp->b_blkno += MINIROOTSIZE; | |
50 | #endif | |
ca1f746a | 51 | sz = howmany(bp->b_bcount, DEV_BSIZE); |
d668d9ba | 52 | if (bp->b_blkno+sz > nswap) { |
013037be | 53 | bp->b_flags |= B_ERROR; |
ec67a3ce | 54 | biodone(bp); |
013037be BJ |
55 | return; |
56 | } | |
d668d9ba SL |
57 | if (nswdev > 1) { |
58 | off = bp->b_blkno % dmmax; | |
59 | if (off+sz > dmmax) { | |
60 | bp->b_flags |= B_ERROR; | |
ec67a3ce | 61 | biodone(bp); |
d668d9ba SL |
62 | return; |
63 | } | |
64 | seg = bp->b_blkno / dmmax; | |
ec67a3ce | 65 | index = seg % nswdev; |
d668d9ba SL |
66 | seg /= nswdev; |
67 | bp->b_blkno = seg*dmmax + off; | |
68 | } else | |
ec67a3ce MK |
69 | index = 0; |
70 | sp = &swdevt[index]; | |
71 | #ifdef SECSIZE | |
72 | bp->b_blkno <<= sp->sw_bshift; | |
73 | bp->b_blksize = sp->sw_blksize; | |
74 | #endif SECSIZE | |
75 | bp->b_dev = sp->sw_dev; | |
76 | if (bp->b_dev == 0) | |
013037be | 77 | panic("swstrategy"); |
ec67a3ce | 78 | (*bdevsw[major(bp->b_dev)].d_strategy)(bp); |
013037be BJ |
79 | } |
80 | ||
013037be BJ |
81 | /* |
82 | * System call swapon(name) enables swapping on device name, | |
83 | * which must be in the swdevsw. Return EBUSY | |
84 | * if already swapping on this device. | |
85 | */ | |
2dfa06c1 | 86 | swapon() |
013037be | 87 | { |
2dfa06c1 SL |
88 | struct a { |
89 | char *name; | |
715baff1 | 90 | } *uap = (struct a *)u.u_ap; |
c4ec2128 | 91 | register struct vnode *vp; |
013037be BJ |
92 | dev_t dev; |
93 | register struct swdevt *sp; | |
715baff1 | 94 | register struct nameidata *ndp = &u.u_nd; |
013037be | 95 | |
849cbd39 | 96 | if (u.u_error = suser(u.u_cred, &u.u_acflag)) |
dca9bb95 | 97 | return; |
715baff1 KM |
98 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
99 | ndp->ni_segflg = UIO_USERSPACE; | |
100 | ndp->ni_dirp = uap->name; | |
c4ec2128 | 101 | if (u.u_error = namei(ndp)) |
013037be | 102 | return; |
c4ec2128 KM |
103 | vp = ndp->ni_vp; |
104 | if (vp->v_type != VBLK) { | |
105 | vrele(vp); | |
013037be | 106 | u.u_error = ENOTBLK; |
013037be BJ |
107 | return; |
108 | } | |
c4ec2128 | 109 | dev = (dev_t)vp->v_rdev; |
013037be | 110 | if (major(dev) >= nblkdev) { |
c4ec2128 | 111 | vrele(vp); |
013037be BJ |
112 | u.u_error = ENXIO; |
113 | return; | |
114 | } | |
ae0ffeb1 | 115 | for (sp = &swdevt[0]; sp->sw_dev; sp++) |
013037be BJ |
116 | if (sp->sw_dev == dev) { |
117 | if (sp->sw_freed) { | |
c4ec2128 | 118 | vrele(vp); |
013037be BJ |
119 | u.u_error = EBUSY; |
120 | return; | |
121 | } | |
ec67a3ce | 122 | u.u_error = swfree(sp - swdevt); |
013037be BJ |
123 | return; |
124 | } | |
c4ec2128 | 125 | vrele(vp); |
ae0ffeb1 | 126 | u.u_error = EINVAL; |
013037be BJ |
127 | } |
128 | ||
ec67a3ce MK |
129 | #ifdef SECSIZE |
130 | long argdbsize; /* XXX */ | |
131 | ||
132 | #endif SECSIZE | |
013037be BJ |
133 | /* |
134 | * Swfree(index) frees the index'th portion of the swap map. | |
135 | * Each of the nswdev devices provides 1/nswdev'th of the swap | |
d668d9ba | 136 | * space, which is laid out with blocks of dmmax pages circularly |
013037be BJ |
137 | * among the devices. |
138 | */ | |
139 | swfree(index) | |
140 | int index; | |
141 | { | |
609e7cfa | 142 | register struct swdevt *sp; |
ec67a3ce | 143 | register struct swdevt *sp; |
013037be | 144 | register swblk_t vsbase; |
39d536e6 | 145 | register long blk; |
c4ec2128 | 146 | struct vnode *vp; |
d668d9ba SL |
147 | register swblk_t dvbase; |
148 | register int nblks; | |
ec67a3ce | 149 | int error; |
609e7cfa | 150 | int error; |
013037be | 151 | |
ec67a3ce MK |
152 | sp = &swdevt[index]; |
153 | dev = sp->sw_dev; | |
154 | if (error = (*bdevsw[major(dev)].d_open)(dev, FREAD|FWRITE, S_IFBLK)) | |
155 | return (error); | |
156 | sp->sw_freed = 1; | |
157 | nblks = sp->sw_nblks; | |
d668d9ba SL |
158 | for (dvbase = 0; dvbase < nblks; dvbase += dmmax) { |
159 | blk = nblks - dvbase; | |
160 | if ((vsbase = index*dmmax + dvbase*nswdev) >= nswap) | |
161 | panic("swfree"); | |
162 | if (blk > dmmax) | |
163 | blk = dmmax; | |
013037be BJ |
164 | if (vsbase == 0) { |
165 | /* | |
166 | * Can't free a block starting at 0 in the swapmap | |
c84ff1f9 | 167 | * but need some space for argmap so use 1/2 this |
013037be BJ |
168 | * hunk which needs special treatment anyways. |
169 | */ | |
ec67a3ce MK |
170 | argdev = sp->sw_dev; |
171 | #ifdef SECSIZE | |
172 | argdbsize = sp->sw_blksize; | |
173 | rminit(argmap, | |
174 | ((blk / 2) * DEV_BSIZE - CLBYTES) / argdbsize, | |
175 | CLBYTES / argdbsize, "argmap", ARGMAPSIZE); | |
176 | #else SECSIZE | |
e438ed8e BJ |
177 | rminit(argmap, (long)(blk/2-ctod(CLSIZE)), |
178 | (long)ctod(CLSIZE), "argmap", ARGMAPSIZE); | |
ec67a3ce | 179 | #endif SECSIZE |
c84ff1f9 BJ |
180 | /* |
181 | * First of all chunks... initialize the swapmap | |
182 | * the second half of the hunk. | |
183 | */ | |
c4ec2128 | 184 | rminit(swapmap, (long)(blk/2), (long)(blk/2), |
a29f7995 | 185 | "swap", nswapmap); |
ec67a3ce MK |
186 | } else if (dvbase == 0) { |
187 | /* | |
188 | * Don't use the first cluster of the device | |
189 | * in case it starts with a label or boot block. | |
190 | */ | |
191 | rmfree(swapmap, blk - ctod(CLSIZE), | |
192 | vsbase + ctod(CLSIZE)); | |
609e7cfa MK |
193 | } else if (dvbase == 0) { |
194 | /* | |
195 | * Don't use the first cluster of the device | |
196 | * in case it starts with a label or boot block. | |
197 | */ | |
198 | rmfree(swapmap, blk - ctod(CLSIZE), | |
199 | vsbase + ctod(CLSIZE)); | |
013037be | 200 | } else |
c84ff1f9 | 201 | rmfree(swapmap, blk, vsbase); |
013037be | 202 | } |
ec67a3ce | 203 | return (0); |
609e7cfa | 204 | return (0); |
013037be | 205 | } |