Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1982, 1986, 1989, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
dc71b7ab | 13 | * 3. Neither the name of the University nor the names of its contributors |
984263bc MD |
14 | * may be used to endorse or promote products derived from this software |
15 | * without specific prior written permission. | |
16 | * | |
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 | * SUCH DAMAGE. | |
28 | * | |
29 | * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 | |
30 | * $FreeBSD: src/sys/ufs/ffs/ffs_subr.c,v 1.25 1999/12/29 04:55:04 peter Exp $ | |
31 | */ | |
32 | ||
33 | #include <sys/param.h> | |
984263bc MD |
34 | |
35 | #ifndef _KERNEL | |
1f2de5d4 | 36 | #include "dinode.h" |
50e58362 | 37 | #include "fs.h" |
a3e9bf8f | 38 | extern void panic(const char *, ...) __printflike(1, 2) __dead2; |
984263bc | 39 | #else |
984263bc MD |
40 | #include <sys/systm.h> |
41 | #include <sys/lock.h> | |
42 | #include <sys/vnode.h> | |
43 | #include <sys/buf.h> | |
44 | #include <sys/ucred.h> | |
9ba4b517 | 45 | #include <sys/mount.h> |
984263bc | 46 | |
54341a3b MD |
47 | #include <sys/buf2.h> |
48 | ||
1f2de5d4 MD |
49 | #include "quota.h" |
50 | #include "inode.h" | |
50e58362 | 51 | #include "fs.h" |
1f2de5d4 | 52 | #include "ffs_extern.h" |
984263bc | 53 | |
984263bc MD |
54 | /* |
55 | * Return buffer with the contents of block "offset" from the beginning of | |
9ba4b517 MD |
56 | * vnode "vp". If "res" is non-zero, fill it in with a pointer to the |
57 | * remaining space in the vnode. | |
984263bc MD |
58 | */ |
59 | int | |
9ba4b517 | 60 | ffs_blkatoff(struct vnode *vp, off_t uoffset, char **res, struct buf **bpp) |
984263bc MD |
61 | { |
62 | struct inode *ip; | |
3ff2135f | 63 | struct fs *fs; |
984263bc MD |
64 | struct buf *bp; |
65 | ufs_daddr_t lbn; | |
66 | int bsize, error; | |
67 | ||
68 | ip = VTOI(vp); | |
69 | fs = ip->i_fs; | |
9ba4b517 | 70 | lbn = lblkno(fs, uoffset); |
984263bc MD |
71 | bsize = blksize(fs, ip, lbn); |
72 | ||
73 | *bpp = NULL; | |
54078292 | 74 | error = bread(vp, lblktodoff(fs, lbn), bsize, &bp); |
984263bc MD |
75 | if (error) { |
76 | brelse(bp); | |
77 | return (error); | |
78 | } | |
79 | if (res) | |
9ba4b517 | 80 | *res = (char *)bp->b_data + blkoff(fs, uoffset); |
984263bc MD |
81 | *bpp = bp; |
82 | return (0); | |
83 | } | |
9ba4b517 MD |
84 | |
85 | /* | |
86 | * Return buffer with the contents of block "offset" from the beginning of | |
87 | * vnode "vp". If "res" is non-zero, fill it in with a pointer to the | |
88 | * remaining space in the vnode. | |
89 | * | |
90 | * This version includes a read-ahead optimization. | |
91 | */ | |
92 | int | |
93 | ffs_blkatoff_ra(struct vnode *vp, off_t uoffset, char **res, struct buf **bpp, | |
94 | int seqcount) | |
95 | { | |
96 | struct inode *ip; | |
97 | struct fs *fs; | |
98 | struct buf *bp; | |
99 | ufs_daddr_t lbn; | |
100 | ufs_daddr_t nextlbn; | |
101 | off_t base_loffset; | |
102 | off_t next_loffset; | |
103 | int bsize, error; | |
104 | int nextbsize; | |
105 | ||
106 | ip = VTOI(vp); | |
107 | fs = ip->i_fs; | |
108 | lbn = lblkno(fs, uoffset); | |
109 | base_loffset = lblktodoff(fs, lbn); | |
110 | bsize = blksize(fs, ip, lbn); | |
111 | ||
112 | nextlbn = lbn + 1; | |
113 | next_loffset = lblktodoff(fs, nextlbn); | |
114 | ||
115 | ||
116 | *bpp = NULL; | |
117 | ||
118 | if (next_loffset >= ip->i_size) { | |
119 | /* | |
1c9602b3 MD |
120 | * Do not do readahead if this is the last block, |
121 | * bsize might represent a fragment. | |
9ba4b517 MD |
122 | */ |
123 | error = bread(vp, base_loffset, bsize, &bp); | |
124 | } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { | |
125 | /* | |
126 | * Try to cluster if we allowed to. | |
127 | */ | |
128 | error = cluster_read(vp, (off_t)ip->i_size, | |
129 | base_loffset, bsize, | |
dc6a6bd2 | 130 | bsize, seqcount * MAXBSIZE, &bp); |
9ba4b517 MD |
131 | } else if (seqcount > 1) { |
132 | /* | |
133 | * Faked read ahead | |
134 | */ | |
135 | nextbsize = blksize(fs, ip, nextlbn); | |
136 | error = breadn(vp, base_loffset, bsize, | |
137 | &next_loffset, &nextbsize, 1, &bp); | |
138 | } else { | |
139 | /* | |
140 | * Failing all of the above, just read what the | |
141 | * user asked for. Interestingly, the same as | |
142 | * the first option above. | |
143 | */ | |
144 | error = bread(vp, base_loffset, bsize, &bp); | |
145 | } | |
146 | if (error) { | |
147 | brelse(bp); | |
148 | return (error); | |
149 | } | |
150 | if (res) | |
151 | *res = (char *)bp->b_data + (int)(uoffset - base_loffset); | |
152 | *bpp = bp; | |
153 | return (0); | |
154 | } | |
155 | ||
984263bc MD |
156 | #endif |
157 | ||
158 | /* | |
159 | * Update the frsum fields to reflect addition or deletion | |
160 | * of some frags. | |
161 | */ | |
162 | void | |
0973c589 | 163 | ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) |
984263bc MD |
164 | { |
165 | int inblk; | |
3ff2135f RG |
166 | int field, subfield; |
167 | int siz, pos; | |
984263bc | 168 | |
5d5d3444 MD |
169 | /* |
170 | * inblk represents a bitmap of fragment sizes which may be | |
171 | * contained in the data 'fragmap'. e.g. if a fragment of size | |
172 | * 1 is available, bit 0 would be set. inblk is shifted left | |
173 | * by one so we do not have to calculate (1 << (siz - 1)). | |
174 | * | |
175 | * fragment represents the data pattern we are trying to decipher, | |
176 | * we shift it left by one to align it with the 'around' and 'inside' | |
177 | * masks. | |
178 | * | |
179 | * around represents the bits around the subfield and is a mask. | |
180 | * inside represents what we must match within the mask, it is | |
181 | * basically the mask with the first and last bit set to 0, allowing | |
182 | * us to represent a whole fragment. | |
183 | * | |
184 | * When we find a match we bump our position by the size of the | |
185 | * matching fragment, then bump the position again: | |
186 | * | |
187 | * 010101010 fragmap (shifted left by 1) | |
188 | * 111 around mask | |
189 | * 010 inside mask | |
190 | * 111 (shifted by siz) | |
191 | * 010 | |
192 | * 111 (shifted again) | |
193 | * 010 | |
194 | */ | |
984263bc MD |
195 | inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; |
196 | fragmap <<= 1; | |
197 | for (siz = 1; siz < fs->fs_frag; siz++) { | |
198 | if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) | |
199 | continue; | |
200 | field = around[siz]; | |
201 | subfield = inside[siz]; | |
202 | for (pos = siz; pos <= fs->fs_frag; pos++) { | |
203 | if ((fragmap & field) == subfield) { | |
204 | fraglist[siz] += cnt; | |
205 | pos += siz; | |
206 | field <<= siz; | |
207 | subfield <<= siz; | |
208 | } | |
209 | field <<= 1; | |
210 | subfield <<= 1; | |
211 | } | |
212 | } | |
213 | } | |
214 | ||
984263bc MD |
215 | /* |
216 | * block operations | |
217 | * | |
218 | * check if a block is available | |
219 | */ | |
220 | int | |
0973c589 | 221 | ffs_isblock(struct fs *fs, unsigned char *cp, ufs_daddr_t h) |
984263bc MD |
222 | { |
223 | unsigned char mask; | |
224 | ||
225 | switch ((int)fs->fs_frag) { | |
226 | case 8: | |
227 | return (cp[h] == 0xff); | |
228 | case 4: | |
229 | mask = 0x0f << ((h & 0x1) << 2); | |
230 | return ((cp[h >> 1] & mask) == mask); | |
231 | case 2: | |
232 | mask = 0x03 << ((h & 0x3) << 1); | |
233 | return ((cp[h >> 2] & mask) == mask); | |
234 | case 1: | |
235 | mask = 0x01 << (h & 0x7); | |
236 | return ((cp[h >> 3] & mask) == mask); | |
237 | default: | |
238 | panic("ffs_isblock"); | |
239 | } | |
240 | } | |
241 | ||
242 | /* | |
243 | * check if a block is free | |
244 | */ | |
245 | int | |
0973c589 | 246 | ffs_isfreeblock(struct fs *fs, unsigned char *cp, ufs_daddr_t h) |
984263bc | 247 | { |
984263bc MD |
248 | switch ((int)fs->fs_frag) { |
249 | case 8: | |
250 | return (cp[h] == 0); | |
251 | case 4: | |
252 | return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); | |
253 | case 2: | |
254 | return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); | |
255 | case 1: | |
256 | return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); | |
257 | default: | |
258 | panic("ffs_isfreeblock"); | |
259 | } | |
260 | } | |
261 | ||
262 | /* | |
263 | * take a block out of the map | |
264 | */ | |
265 | void | |
0973c589 | 266 | ffs_clrblock(struct fs *fs, u_char *cp, ufs_daddr_t h) |
984263bc | 267 | { |
984263bc MD |
268 | switch ((int)fs->fs_frag) { |
269 | case 8: | |
270 | cp[h] = 0; | |
271 | return; | |
272 | case 4: | |
273 | cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); | |
274 | return; | |
275 | case 2: | |
276 | cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); | |
277 | return; | |
278 | case 1: | |
279 | cp[h >> 3] &= ~(0x01 << (h & 0x7)); | |
280 | return; | |
281 | default: | |
282 | panic("ffs_clrblock"); | |
283 | } | |
284 | } | |
285 | ||
286 | /* | |
287 | * put a block into the map | |
288 | */ | |
289 | void | |
0973c589 | 290 | ffs_setblock(struct fs *fs, unsigned char *cp, ufs_daddr_t h) |
984263bc | 291 | { |
984263bc | 292 | switch ((int)fs->fs_frag) { |
984263bc MD |
293 | case 8: |
294 | cp[h] = 0xff; | |
295 | return; | |
296 | case 4: | |
297 | cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); | |
298 | return; | |
299 | case 2: | |
300 | cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); | |
301 | return; | |
302 | case 1: | |
303 | cp[h >> 3] |= (0x01 << (h & 0x7)); | |
304 | return; | |
305 | default: | |
306 | panic("ffs_setblock"); | |
307 | } | |
308 | } |