1 /*	$OpenBSD: ffs_subr.c,v 1.15 2004/01/20 03:44:06 tedu 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/extattr.h>
45 #include <ufs/ufs/quota.h>
46 #include <ufs/ufs/inode.h>
47 #include <ufs/ufs/ufsmount.h>
48 #include <ufs/ufs/ufs_extern.h>
49 
50 #include <ufs/ffs/ffs_extern.h>
51 
52 /*
53  * Return buffer with the contents of block "offset" from the beginning of
54  * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
55  * remaining space in the directory.
56  */
57 int
ffs_bufatoff(struct inode * ip,off_t offset,char ** res,struct buf ** bpp)58 ffs_bufatoff(struct inode *ip, off_t offset, char **res, struct buf **bpp)
59 {
60 	struct fs *fs;
61 	struct vnode *vp;
62 	struct buf *bp;
63 	daddr_t lbn;
64 	int bsize, error;
65 
66 	vp = ITOV(ip);
67 	fs = ip->i_fs;
68 	lbn = lblkno(fs, offset);
69 	bsize = blksize(fs, ip, lbn);
70 
71 	*bpp = NULL;
72 	if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
73 		brelse(bp);
74 		return (error);
75 	}
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 *, unsigned char *, daddr_t);
85 int	ffs_isblock(struct fs *, unsigned char *, daddr_t);
86 void	ffs_clrblock(struct fs *, u_char *, daddr_t);
87 void	ffs_setblock(struct fs *, unsigned 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
ffs_fragacct(fs,fragmap,fraglist,cnt)96 ffs_fragacct(fs, fragmap, fraglist, cnt)
97 	struct fs *fs;
98 	int fragmap;
99 	int32_t fraglist[];
100 	int cnt;
101 {
102 	int inblk;
103 	register int field, subfield;
104 	register int siz, pos;
105 
106 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
107 	fragmap <<= 1;
108 	for (siz = 1; siz < fs->fs_frag; siz++) {
109 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
110 			continue;
111 		field = around[siz];
112 		subfield = inside[siz];
113 		for (pos = siz; pos <= fs->fs_frag; pos++) {
114 			if ((fragmap & field) == subfield) {
115 				fraglist[siz] += cnt;
116 				pos += siz;
117 				field <<= siz;
118 				subfield <<= siz;
119 			}
120 			field <<= 1;
121 			subfield <<= 1;
122 		}
123 	}
124 }
125 
126 #if defined(_KERNEL) && defined(DIAGNOSTIC)
127 void
ffs_checkoverlap(bp,ip)128 ffs_checkoverlap(bp, ip)
129 	struct buf *bp;
130 	struct inode *ip;
131 {
132 	register struct buf *ebp, *ep;
133 	register daddr_t start, last;
134 	struct vnode *vp;
135 
136 	ebp = &buf[nbuf];
137 	start = bp->b_blkno;
138 	last = start + btodb(bp->b_bcount) - 1;
139 	for (ep = buf; ep < ebp; ep++) {
140 		if (ep == bp || (ep->b_flags & B_INVAL) ||
141 		    ep->b_vp == NULLVP)
142 			continue;
143 		if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL))
144 			continue;
145 		if (vp != ip->i_devvp)
146 			continue;
147 		/* look for overlap */
148 		if (ep->b_bcount == 0 || ep->b_blkno > last ||
149 		    ep->b_blkno + btodb(ep->b_bcount) <= start)
150 			continue;
151 		vprint("Disk overlap", vp);
152 		(void)printf("\tstart %d, end %d overlap start %d, end %ld\n",
153 			start, last, ep->b_blkno,
154 			ep->b_blkno + btodb(ep->b_bcount) - 1);
155 		panic("Disk buffer overlap");
156 	}
157 }
158 #endif /* DIAGNOSTIC */
159 
160 /*
161  * block operations
162  *
163  * check if a block is available
164  */
165 int
ffs_isblock(fs,cp,h)166 ffs_isblock(fs, cp, h)
167 	struct fs *fs;
168 	unsigned char *cp;
169 	daddr_t h;
170 {
171 	unsigned char mask;
172 
173 	switch ((int)fs->fs_frag) {
174 	case 8:
175 		return (cp[h] == 0xff);
176 	case 4:
177 		mask = 0x0f << ((h & 0x1) << 2);
178 		return ((cp[h >> 1] & mask) == mask);
179 	case 2:
180 		mask = 0x03 << ((h & 0x3) << 1);
181 		return ((cp[h >> 2] & mask) == mask);
182 	case 1:
183 		mask = 0x01 << (h & 0x7);
184 		return ((cp[h >> 3] & mask) == mask);
185 	default:
186 		panic("ffs_isblock");
187 	}
188 }
189 
190 /*
191  * take a block out of the map
192  */
193 void
ffs_clrblock(fs,cp,h)194 ffs_clrblock(fs, cp, h)
195 	struct fs *fs;
196 	u_char *cp;
197 	daddr_t h;
198 {
199 
200 	switch ((int)fs->fs_frag) {
201 	case 8:
202 		cp[h] = 0;
203 		return;
204 	case 4:
205 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
206 		return;
207 	case 2:
208 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
209 		return;
210 	case 1:
211 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
212 		return;
213 	default:
214 		panic("ffs_clrblock");
215 	}
216 }
217 
218 /*
219  * put a block into the map
220  */
221 void
ffs_setblock(fs,cp,h)222 ffs_setblock(fs, cp, h)
223 	struct fs *fs;
224 	unsigned char *cp;
225 	daddr_t h;
226 {
227 
228 	switch ((int)fs->fs_frag) {
229 
230 	case 8:
231 		cp[h] = 0xff;
232 		return;
233 	case 4:
234 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
235 		return;
236 	case 2:
237 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
238 		return;
239 	case 1:
240 		cp[h >> 3] |= (0x01 << (h & 0x7));
241 		return;
242 	default:
243 		panic("ffs_setblock");
244 	}
245 }
246 
247 
248 /*
249  * check if a block is free
250  */
251 int
ffs_isfreeblock(fs,cp,h)252 ffs_isfreeblock(fs, cp, h)
253 	struct fs *fs;
254 	unsigned char *cp;
255 	daddr_t h;
256 {
257 
258 	switch ((int)fs->fs_frag) {
259 	case 8:
260 		return (cp[h] == 0);
261 	case 4:
262 		return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
263 	case 2:
264 		return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
265 	case 1:
266 		return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
267 	default:
268 		panic("ffs_isfreeblock");
269 	}
270 }
271