Line data Source code
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 0 : ffs_bufatoff(struct inode *ip, off_t offset, char **res, struct buf **bpp)
58 : {
59 : struct fs *fs;
60 : struct vnode *vp;
61 0 : struct buf *bp;
62 : daddr_t lbn;
63 : int bsize, error;
64 :
65 0 : vp = ITOV(ip);
66 0 : fs = ip->i_fs;
67 0 : lbn = lblkno(fs, offset);
68 0 : bsize = blksize(fs, ip, lbn);
69 :
70 0 : *bpp = NULL;
71 0 : if ((error = bread(vp, lbn, fs->fs_bsize, &bp)) != 0) {
72 0 : brelse(bp);
73 0 : return (error);
74 : }
75 0 : buf_adjcnt(bp, bsize);
76 0 : if (res)
77 0 : *res = (char *)bp->b_data + blkoff(fs, offset);
78 0 : *bpp = bp;
79 0 : return (0);
80 0 : }
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 0 : 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 0 : inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
103 0 : fragmap <<= 1;
104 0 : for (siz = 1; siz < fs->fs_frag; siz++) {
105 0 : if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
106 : continue;
107 0 : field = around[siz];
108 0 : subfield = inside[siz];
109 0 : for (pos = siz; pos <= fs->fs_frag; pos++) {
110 0 : if ((fragmap & field) == subfield) {
111 0 : fraglist[siz] += cnt;
112 0 : pos += siz;
113 0 : field <<= siz;
114 0 : subfield <<= siz;
115 0 : }
116 0 : field <<= 1;
117 0 : subfield <<= 1;
118 : }
119 : }
120 0 : }
121 :
122 : #if defined(_KERNEL) && defined(DIAGNOSTIC)
123 : void
124 0 : ffs_checkoverlap(struct buf *bp, struct inode *ip)
125 : {
126 : daddr_t start, last;
127 0 : struct vnode *vp;
128 : struct buf *ep;
129 :
130 0 : start = bp->b_blkno;
131 0 : last = start + btodb(bp->b_bcount) - 1;
132 0 : LIST_FOREACH(ep, &bufhead, b_list) {
133 0 : if (ep == bp || (ep->b_flags & B_INVAL) ||
134 0 : ep->b_vp == NULLVP)
135 : continue;
136 0 : if (VOP_BMAP(ep->b_vp, 0, &vp, NULL, NULL))
137 : continue;
138 0 : if (vp != ip->i_devvp)
139 : continue;
140 : /* look for overlap */
141 0 : if (ep->b_bcount == 0 || ep->b_blkno > last ||
142 0 : ep->b_blkno + btodb(ep->b_bcount) <= start)
143 : continue;
144 0 : vprint("Disk overlap", vp);
145 0 : (void)printf("\tstart %lld, end %lld overlap start %llu, "
146 : "end %llu\n", (long long)start, (long long)last,
147 0 : (long long)ep->b_blkno,
148 0 : (long long)(ep->b_blkno + btodb(ep->b_bcount) - 1));
149 0 : panic("Disk buffer overlap");
150 : }
151 0 : }
152 : #endif /* DIAGNOSTIC */
153 :
154 : /*
155 : * block operations
156 : *
157 : * check if a block is available
158 : */
159 : int
160 0 : ffs_isblock(struct fs *fs, u_char *cp, daddr_t h)
161 : {
162 : u_char mask;
163 :
164 0 : switch (fs->fs_frag) {
165 : default:
166 : case 8:
167 0 : return (cp[h] == 0xff);
168 : case 4:
169 0 : mask = 0x0f << ((h & 0x1) << 2);
170 0 : return ((cp[h >> 1] & mask) == mask);
171 : case 2:
172 0 : mask = 0x03 << ((h & 0x3) << 1);
173 0 : return ((cp[h >> 2] & mask) == mask);
174 : case 1:
175 0 : mask = 0x01 << (h & 0x7);
176 0 : return ((cp[h >> 3] & mask) == mask);
177 : }
178 0 : }
179 :
180 : /*
181 : * take a block out of the map
182 : */
183 : void
184 0 : ffs_clrblock(struct fs *fs, u_char *cp, daddr_t h)
185 : {
186 :
187 0 : switch (fs->fs_frag) {
188 : default:
189 : case 8:
190 0 : cp[h] = 0;
191 0 : return;
192 : case 4:
193 0 : cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
194 0 : return;
195 : case 2:
196 0 : cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
197 0 : return;
198 : case 1:
199 0 : cp[h >> 3] &= ~(0x01 << (h & 0x7));
200 0 : return;
201 : }
202 0 : }
203 :
204 : /*
205 : * put a block into the map
206 : */
207 : void
208 0 : ffs_setblock(struct fs *fs, u_char *cp, daddr_t h)
209 : {
210 :
211 0 : switch (fs->fs_frag) {
212 : default:
213 : case 8:
214 0 : cp[h] = 0xff;
215 0 : return;
216 : case 4:
217 0 : cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
218 0 : return;
219 : case 2:
220 0 : cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
221 0 : return;
222 : case 1:
223 0 : cp[h >> 3] |= (0x01 << (h & 0x7));
224 0 : return;
225 : }
226 0 : }
227 :
228 : /*
229 : * check if a block is free
230 : */
231 : int
232 0 : ffs_isfreeblock(struct fs *fs, u_char *cp, daddr_t h)
233 : {
234 :
235 0 : switch (fs->fs_frag) {
236 : default:
237 : case 8:
238 0 : return (cp[h] == 0);
239 : case 4:
240 0 : return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
241 : case 2:
242 0 : return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
243 : case 1:
244 0 : return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
245 : }
246 0 : }
247 :
248 : #ifdef _KERNEL
249 : /*
250 : * Initialize the vnode associated with a new inode, handle aliased
251 : * vnodes.
252 : */
253 : int
254 0 : ffs_vinit(struct mount *mntp, struct vnode **vpp)
255 : {
256 : struct inode *ip;
257 : struct vnode *vp, *nvp;
258 0 : struct timeval mtv;
259 :
260 0 : vp = *vpp;
261 0 : ip = VTOI(vp);
262 0 : switch(vp->v_type = IFTOVT(DIP(ip, mode))) {
263 : case VCHR:
264 : case VBLK:
265 0 : vp->v_op = &ffs_specvops;
266 0 : 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 0 : nvp->v_data = vp->v_data;
273 0 : vp->v_data = NULL;
274 0 : vp->v_op = &spec_vops;
275 : #ifdef VFSLCKDEBUG
276 : vp->v_flag &= ~VLOCKSWORK;
277 : #endif
278 0 : vrele(vp);
279 0 : vgone(vp);
280 : /*
281 : * Reinitialize aliased inode.
282 : */
283 : vp = nvp;
284 0 : ip->i_vnode = vp;
285 0 : }
286 : break;
287 : case VFIFO:
288 : #ifdef FIFO
289 0 : vp->v_op = &ffs_fifovops;
290 0 : 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 0 : if (ip->i_number == ROOTINO)
303 0 : vp->v_flag |= VROOT;
304 : /*
305 : * Initialize modrev times
306 : */
307 0 : getmicrouptime(&mtv);
308 0 : ip->i_modrev = (u_quad_t)mtv.tv_sec << 32;
309 0 : ip->i_modrev |= (u_quad_t)mtv.tv_usec * 4294;
310 0 : *vpp = vp;
311 0 : return (0);
312 0 : }
313 : #endif /* _KERNEL */
|