1 |
|
|
/* $OpenBSD: ffs_subr.c,v 1.32 2016/08/10 11:33:01 natano Exp $ */ |
2 |
|
|
/* $NetBSD: ffs_subr.c,v 1.6 1996/03/17 02:16:23 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1982, 1986, 1989, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
* |
32 |
|
|
* @(#)ffs_subr.c 8.2 (Berkeley) 9/21/93 |
33 |
|
|
*/ |
34 |
|
|
|
35 |
|
|
#include <sys/param.h> |
36 |
|
|
#include <ufs/ffs/fs.h> |
37 |
|
|
|
38 |
|
|
#ifdef _KERNEL |
39 |
|
|
#include <sys/systm.h> |
40 |
|
|
#include <sys/vnode.h> |
41 |
|
|
#include <sys/mount.h> |
42 |
|
|
#include <sys/buf.h> |
43 |
|
|
|
44 |
|
|
#include <ufs/ufs/quota.h> |
45 |
|
|
#include <ufs/ufs/inode.h> |
46 |
|
|
#include <ufs/ufs/ufsmount.h> |
47 |
|
|
#include <ufs/ufs/ufs_extern.h> |
48 |
|
|
|
49 |
|
|
#include <ufs/ffs/ffs_extern.h> |
50 |
|
|
|
51 |
|
|
/* |
52 |
|
|
* Return buffer with the contents of block "offset" from the beginning of |
53 |
|
|
* directory "ip". If "res" is non-zero, fill it in with a pointer to the |
54 |
|
|
* remaining space in the directory. |
55 |
|
|
*/ |
56 |
|
|
int |
57 |
|
|
ffs_bufatoff(struct inode *ip, off_t offset, char **res, struct buf **bpp) |
58 |
|
|
{ |
59 |
|
|
struct fs *fs; |
60 |
|
|
struct vnode *vp; |
61 |
|
|
struct buf *bp; |
62 |
|
|
daddr_t lbn; |
63 |
|
|
int bsize, error; |
64 |
|
|
|
65 |
|
|
vp = ITOV(ip); |
66 |
|
|
fs = ip->i_fs; |
67 |
|
|
lbn = lblkno(fs, offset); |
68 |
|
|
bsize = blksize(fs, ip, lbn); |
69 |
|
|
|
70 |
|
|
*bpp = NULL; |
71 |
|
|
if ((error = bread(vp, lbn, fs->fs_bsize, &bp)) != 0) { |
72 |
|
|
brelse(bp); |
73 |
|
|
return (error); |
74 |
|
|
} |
75 |
|
|
buf_adjcnt(bp, bsize); |
76 |
|
|
if (res) |
77 |
|
|
*res = (char *)bp->b_data + blkoff(fs, offset); |
78 |
|
|
*bpp = bp; |
79 |
|
|
return (0); |
80 |
|
|
} |
81 |
|
|
#else |
82 |
|
|
/* Prototypes for userland */ |
83 |
|
|
void ffs_fragacct(struct fs *, int, int32_t[], int); |
84 |
|
|
int ffs_isfreeblock(struct fs *, u_char *, daddr_t); |
85 |
|
|
int ffs_isblock(struct fs *, u_char *, daddr_t); |
86 |
|
|
void ffs_clrblock(struct fs *, u_char *, daddr_t); |
87 |
|
|
void ffs_setblock(struct fs *, u_char *, daddr_t); |
88 |
|
|
__dead void panic(const char *, ...); |
89 |
|
|
#endif |
90 |
|
|
|
91 |
|
|
/* |
92 |
|
|
* Update the frsum fields to reflect addition or deletion |
93 |
|
|
* of some frags. |
94 |
|
|
*/ |
95 |
|
|
void |
96 |
|
|
ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) |
97 |
|
|
{ |
98 |
|
|
int inblk; |
99 |
|
|
int field, subfield; |
100 |
|
|
int siz, pos; |
101 |
|
|
|
102 |
|
32 |
inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; |
103 |
|
16 |
fragmap <<= 1; |
104 |
✓✓ |
256 |
for (siz = 1; siz < fs->fs_frag; siz++) { |
105 |
✓✓ |
112 |
if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) |
106 |
|
|
continue; |
107 |
|
16 |
field = around[siz]; |
108 |
|
16 |
subfield = inside[siz]; |
109 |
✓✓ |
96 |
for (pos = siz; pos <= fs->fs_frag; pos++) { |
110 |
✓✓ |
32 |
if ((fragmap & field) == subfield) { |
111 |
|
16 |
fraglist[siz] += cnt; |
112 |
|
16 |
pos += siz; |
113 |
|
16 |
field <<= siz; |
114 |
|
16 |
subfield <<= siz; |
115 |
|
16 |
} |
116 |
|
32 |
field <<= 1; |
117 |
|
32 |
subfield <<= 1; |
118 |
|
|
} |
119 |
|
|
} |
120 |
|
16 |
} |
121 |
|
|
|
122 |
|
|
#if defined(_KERNEL) && defined(DIAGNOSTIC) |
123 |
|
|
void |
124 |
|
|
ffs_checkoverlap(struct buf *bp, struct inode *ip) |
125 |
|
|
{ |
126 |
|
|
daddr_t start, last; |
127 |
|
|
struct vnode *vp; |
128 |
|
|
struct buf *ep; |
129 |
|
|
|
130 |
|
|
start = bp->b_blkno; |
131 |
|
|
last = start + btodb(bp->b_bcount) - 1; |
132 |
|
|
LIST_FOREACH(ep, &bufhead, b_list) { |
133 |
|
|
if (ep == bp || (ep->b_flags & B_INVAL) || |
134 |
|
|
ep->b_vp == NULLVP) |
135 |
|
|
continue; |
136 |
|
|
if (VOP_BMAP(ep->b_vp, 0, &vp, NULL, NULL)) |
137 |
|
|
continue; |
138 |
|
|
if (vp != ip->i_devvp) |
139 |
|
|
continue; |
140 |
|
|
/* look for overlap */ |
141 |
|
|
if (ep->b_bcount == 0 || ep->b_blkno > last || |
142 |
|
|
ep->b_blkno + btodb(ep->b_bcount) <= start) |
143 |
|
|
continue; |
144 |
|
|
vprint("Disk overlap", vp); |
145 |
|
|
(void)printf("\tstart %lld, end %lld overlap start %llu, " |
146 |
|
|
"end %llu\n", (long long)start, (long long)last, |
147 |
|
|
(long long)ep->b_blkno, |
148 |
|
|
(long long)(ep->b_blkno + btodb(ep->b_bcount) - 1)); |
149 |
|
|
panic("Disk buffer overlap"); |
150 |
|
|
} |
151 |
|
|
} |
152 |
|
|
#endif /* DIAGNOSTIC */ |
153 |
|
|
|
154 |
|
|
/* |
155 |
|
|
* block operations |
156 |
|
|
* |
157 |
|
|
* check if a block is available |
158 |
|
|
*/ |
159 |
|
|
int |
160 |
|
|
ffs_isblock(struct fs *fs, u_char *cp, daddr_t h) |
161 |
|
|
{ |
162 |
|
|
u_char mask; |
163 |
|
|
|
164 |
|
|
switch (fs->fs_frag) { |
165 |
|
|
default: |
166 |
|
|
case 8: |
167 |
|
|
return (cp[h] == 0xff); |
168 |
|
|
case 4: |
169 |
|
|
mask = 0x0f << ((h & 0x1) << 2); |
170 |
|
|
return ((cp[h >> 1] & mask) == mask); |
171 |
|
|
case 2: |
172 |
|
|
mask = 0x03 << ((h & 0x3) << 1); |
173 |
|
|
return ((cp[h >> 2] & mask) == mask); |
174 |
|
|
case 1: |
175 |
|
|
mask = 0x01 << (h & 0x7); |
176 |
|
|
return ((cp[h >> 3] & mask) == mask); |
177 |
|
|
} |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
/* |
181 |
|
|
* take a block out of the map |
182 |
|
|
*/ |
183 |
|
|
void |
184 |
|
|
ffs_clrblock(struct fs *fs, u_char *cp, daddr_t h) |
185 |
|
|
{ |
186 |
|
|
|
187 |
|
|
switch (fs->fs_frag) { |
188 |
|
|
default: |
189 |
|
|
case 8: |
190 |
|
|
cp[h] = 0; |
191 |
|
|
return; |
192 |
|
|
case 4: |
193 |
|
|
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); |
194 |
|
|
return; |
195 |
|
|
case 2: |
196 |
|
|
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); |
197 |
|
|
return; |
198 |
|
|
case 1: |
199 |
|
|
cp[h >> 3] &= ~(0x01 << (h & 0x7)); |
200 |
|
|
return; |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
/* |
205 |
|
|
* put a block into the map |
206 |
|
|
*/ |
207 |
|
|
void |
208 |
|
|
ffs_setblock(struct fs *fs, u_char *cp, daddr_t h) |
209 |
|
|
{ |
210 |
|
|
|
211 |
|
|
switch (fs->fs_frag) { |
212 |
|
|
default: |
213 |
|
|
case 8: |
214 |
|
|
cp[h] = 0xff; |
215 |
|
|
return; |
216 |
|
|
case 4: |
217 |
|
|
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); |
218 |
|
|
return; |
219 |
|
|
case 2: |
220 |
|
|
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); |
221 |
|
|
return; |
222 |
|
|
case 1: |
223 |
|
|
cp[h >> 3] |= (0x01 << (h & 0x7)); |
224 |
|
|
return; |
225 |
|
|
} |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
/* |
229 |
|
|
* check if a block is free |
230 |
|
|
*/ |
231 |
|
|
int |
232 |
|
|
ffs_isfreeblock(struct fs *fs, u_char *cp, daddr_t h) |
233 |
|
|
{ |
234 |
|
|
|
235 |
|
|
switch (fs->fs_frag) { |
236 |
|
|
default: |
237 |
|
|
case 8: |
238 |
|
|
return (cp[h] == 0); |
239 |
|
|
case 4: |
240 |
|
|
return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); |
241 |
|
|
case 2: |
242 |
|
|
return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); |
243 |
|
|
case 1: |
244 |
|
|
return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); |
245 |
|
|
} |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
#ifdef _KERNEL |
249 |
|
|
/* |
250 |
|
|
* Initialize the vnode associated with a new inode, handle aliased |
251 |
|
|
* vnodes. |
252 |
|
|
*/ |
253 |
|
|
int |
254 |
|
|
ffs_vinit(struct mount *mntp, struct vnode **vpp) |
255 |
|
|
{ |
256 |
|
|
struct inode *ip; |
257 |
|
|
struct vnode *vp, *nvp; |
258 |
|
|
struct timeval mtv; |
259 |
|
|
|
260 |
|
|
vp = *vpp; |
261 |
|
|
ip = VTOI(vp); |
262 |
|
|
switch(vp->v_type = IFTOVT(DIP(ip, mode))) { |
263 |
|
|
case VCHR: |
264 |
|
|
case VBLK: |
265 |
|
|
vp->v_op = &ffs_specvops; |
266 |
|
|
if ((nvp = checkalias(vp, DIP(ip, rdev), mntp)) != NULL) { |
267 |
|
|
/* |
268 |
|
|
* Discard unneeded vnode, but save its inode. |
269 |
|
|
* Note that the lock is carried over in the inode |
270 |
|
|
* to the replacement vnode. |
271 |
|
|
*/ |
272 |
|
|
nvp->v_data = vp->v_data; |
273 |
|
|
vp->v_data = NULL; |
274 |
|
|
vp->v_op = &spec_vops; |
275 |
|
|
#ifdef VFSLCKDEBUG |
276 |
|
|
vp->v_flag &= ~VLOCKSWORK; |
277 |
|
|
#endif |
278 |
|
|
vrele(vp); |
279 |
|
|
vgone(vp); |
280 |
|
|
/* |
281 |
|
|
* Reinitialize aliased inode. |
282 |
|
|
*/ |
283 |
|
|
vp = nvp; |
284 |
|
|
ip->i_vnode = vp; |
285 |
|
|
} |
286 |
|
|
break; |
287 |
|
|
case VFIFO: |
288 |
|
|
#ifdef FIFO |
289 |
|
|
vp->v_op = &ffs_fifovops; |
290 |
|
|
break; |
291 |
|
|
#else |
292 |
|
|
return (EOPNOTSUPP); |
293 |
|
|
#endif |
294 |
|
|
case VNON: |
295 |
|
|
case VBAD: |
296 |
|
|
case VSOCK: |
297 |
|
|
case VLNK: |
298 |
|
|
case VDIR: |
299 |
|
|
case VREG: |
300 |
|
|
break; |
301 |
|
|
} |
302 |
|
|
if (ip->i_number == ROOTINO) |
303 |
|
|
vp->v_flag |= VROOT; |
304 |
|
|
/* |
305 |
|
|
* Initialize modrev times |
306 |
|
|
*/ |
307 |
|
|
getmicrouptime(&mtv); |
308 |
|
|
ip->i_modrev = (u_quad_t)mtv.tv_sec << 32; |
309 |
|
|
ip->i_modrev |= (u_quad_t)mtv.tv_usec * 4294; |
310 |
|
|
*vpp = vp; |
311 |
|
|
return (0); |
312 |
|
|
} |
313 |
|
|
#endif /* _KERNEL */ |