ffs_subr.c revision 185222
1185222Ssam/*	$NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $	*/
2185222Ssam
3185222Ssam/*
4185222Ssam * Copyright (c) 1982, 1986, 1989, 1993
5185222Ssam *	The Regents of the University of California.  All rights reserved.
6185222Ssam *
7185222Ssam * Redistribution and use in source and binary forms, with or without
8185222Ssam * modification, are permitted provided that the following conditions
9185222Ssam * are met:
10185222Ssam * 1. Redistributions of source code must retain the above copyright
11185222Ssam *    notice, this list of conditions and the following disclaimer.
12185222Ssam * 2. Redistributions in binary form must reproduce the above copyright
13185222Ssam *    notice, this list of conditions and the following disclaimer in the
14185222Ssam *    documentation and/or other materials provided with the distribution.
15185222Ssam * 3. Neither the name of the University nor the names of its contributors
16185222Ssam *    may be used to endorse or promote products derived from this software
17185222Ssam *    without specific prior written permission.
18185222Ssam *
19185222Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20185222Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21185222Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22185222Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23185222Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24185222Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25185222Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26185222Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27185222Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28185222Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29185222Ssam * SUCH DAMAGE.
30185222Ssam *
31185222Ssam *	@(#)ffs_subr.c	8.5 (Berkeley) 3/21/95
32185222Ssam */
33185222Ssam
34185222Ssam#if HAVE_NBTOOL_CONFIG_H
35185222Ssam#include "nbtool_config.h"
36185222Ssam#endif
37185222Ssam
38185222Ssam#include <sys/cdefs.h>
39185222Ssam__KERNEL_RCSID(0, "$NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $");
40185222Ssam
41185222Ssam#include <sys/param.h>
42185222Ssam
43185222Ssam/* in ffs_tables.c */
44185222Ssamextern const int inside[], around[];
45185222Ssamextern const u_char * const fragtbl[];
46185222Ssam
47185222Ssam#ifndef _KERNEL
48185222Ssam#include <ufs/ufs/dinode.h>
49185222Ssam#include <ufs/ffs/fs.h>
50185222Ssam#include <ufs/ffs/ffs_extern.h>
51185222Ssam#include <ufs/ufs/ufs_bswap.h>
52185222Ssamvoid    panic __P((const char *, ...))
53185222Ssam    __attribute__((__noreturn__,__format__(__printf__,1,2)));
54185222Ssam
55185222Ssam#else	/* _KERNEL */
56185222Ssam#include <sys/systm.h>
57185222Ssam#include <sys/vnode.h>
58185222Ssam#include <sys/mount.h>
59185222Ssam#include <sys/buf.h>
60185222Ssam#include <sys/inttypes.h>
61185222Ssam#include <sys/pool.h>
62185222Ssam#include <ufs/ufs/inode.h>
63185222Ssam#include <ufs/ufs/ufsmount.h>
64185222Ssam#include <ufs/ufs/ufs_extern.h>
65185222Ssam#include <ufs/ffs/fs.h>
66185222Ssam#include <ufs/ffs/ffs_extern.h>
67185222Ssam#include <ufs/ufs/ufs_bswap.h>
68185222Ssam
69185222Ssam/*
70185222Ssam * Return buffer with the contents of block "offset" from the beginning of
71185222Ssam * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
72185222Ssam * remaining space in the directory.
73185222Ssam */
74185222Ssamint
75185222Ssamffs_blkatoff(v)
76185222Ssam	void *v;
77185222Ssam{
78185222Ssam	struct vop_blkatoff_args /* {
79185222Ssam		struct vnode *a_vp;
80185222Ssam		off_t a_offset;
81185222Ssam		char **a_res;
82185222Ssam		struct buf **a_bpp;
83185222Ssam	} */ *ap = v;
84185222Ssam	struct inode *ip;
85185222Ssam	struct fs *fs;
86185222Ssam	struct buf *bp;
87185222Ssam	daddr_t lbn;
88185222Ssam	int bsize, error;
89185222Ssam
90185222Ssam	ip = VTOI(ap->a_vp);
91185222Ssam	fs = ip->i_fs;
92185222Ssam	lbn = lblkno(fs, ap->a_offset);
93185222Ssam	bsize = blksize(fs, ip, lbn);
94185222Ssam
95185222Ssam	*ap->a_bpp = NULL;
96185222Ssam	if ((error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) != 0) {
97185222Ssam		brelse(bp);
98185222Ssam		return (error);
99185222Ssam	}
100185222Ssam	if (ap->a_res)
101185222Ssam		*ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset);
102185222Ssam	*ap->a_bpp = bp;
103185222Ssam	return (0);
104185222Ssam}
105185222Ssam
106185222Ssam
107185222Ssam/*
108185222Ssam * Load up the contents of an inode and copy the appropriate pieces
109185222Ssam * to the incore copy.
110185222Ssam */
111185222Ssamvoid
112185222Ssamffs_load_inode(bp, ip, fs, ino)
113185222Ssam	struct buf *bp;
114185222Ssam	struct inode *ip;
115185222Ssam	struct fs *fs;
116185222Ssam	ino_t ino;
117185222Ssam{
118185222Ssam	struct ufs1_dinode *dp1;
119185222Ssam	struct ufs2_dinode *dp2;
120185222Ssam
121185222Ssam	if (ip->i_ump->um_fstype == UFS1) {
122185222Ssam		dp1 = (struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
123185222Ssam#ifdef FFS_EI
124185222Ssam		if (UFS_FSNEEDSWAP(fs))
125185222Ssam			ffs_dinode1_swap(dp1, ip->i_din.ffs1_din);
126185222Ssam		else
127185222Ssam#endif
128185222Ssam		*ip->i_din.ffs1_din = *dp1;
129185222Ssam
130185222Ssam		ip->i_mode = ip->i_ffs1_mode;
131185222Ssam		ip->i_nlink = ip->i_ffs1_nlink;
132185222Ssam		ip->i_size = ip->i_ffs1_size;
133185222Ssam		ip->i_flags = ip->i_ffs1_flags;
134185222Ssam		ip->i_gen = ip->i_ffs1_gen;
135185222Ssam		ip->i_uid = ip->i_ffs1_uid;
136185222Ssam		ip->i_gid = ip->i_ffs1_gid;
137185222Ssam	} else {
138185222Ssam		dp2 = (struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino);
139185222Ssam#ifdef FFS_EI
140185222Ssam		if (UFS_FSNEEDSWAP(fs))
141185222Ssam			ffs_dinode2_swap(dp2, ip->i_din.ffs2_din);
142185222Ssam		else
143185222Ssam#endif
144185222Ssam		*ip->i_din.ffs2_din = *dp2;
145185222Ssam
146185222Ssam		ip->i_mode = ip->i_ffs2_mode;
147185222Ssam		ip->i_nlink = ip->i_ffs2_nlink;
148185222Ssam		ip->i_size = ip->i_ffs2_size;
149185222Ssam		ip->i_flags = ip->i_ffs2_flags;
150185222Ssam		ip->i_gen = ip->i_ffs2_gen;
151185222Ssam		ip->i_uid = ip->i_ffs2_uid;
152185222Ssam		ip->i_gid = ip->i_ffs2_gid;
153185222Ssam	}
154185222Ssam}
155185222Ssam
156185222Ssam#endif	/* _KERNEL */
157185222Ssam
158185222Ssam/*
159185222Ssam * Update the frsum fields to reflect addition or deletion
160185222Ssam * of some frags.
161185222Ssam */
162185222Ssamvoid
163185222Ssamffs_fragacct(fs, fragmap, fraglist, cnt, needswap)
164185222Ssam	struct fs *fs;
165185222Ssam	int fragmap;
166185222Ssam	int32_t fraglist[];
167185222Ssam	int cnt;
168185222Ssam	int needswap;
169185222Ssam{
170185222Ssam	int inblk;
171185222Ssam	int field, subfield;
172185222Ssam	int siz, pos;
173185222Ssam
174185222Ssam	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
175185222Ssam	fragmap <<= 1;
176185222Ssam	for (siz = 1; siz < fs->fs_frag; siz++) {
177185222Ssam		if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0)
178185222Ssam			continue;
179185222Ssam		field = around[siz];
180185222Ssam		subfield = inside[siz];
181185222Ssam		for (pos = siz; pos <= fs->fs_frag; pos++) {
182185222Ssam			if ((fragmap & field) == subfield) {
183185222Ssam				fraglist[siz] = ufs_rw32(
184185222Ssam				    ufs_rw32(fraglist[siz], needswap) + cnt,
185185222Ssam				    needswap);
186185222Ssam				pos += siz;
187185222Ssam				field <<= siz;
188185222Ssam				subfield <<= siz;
189185222Ssam			}
190185222Ssam			field <<= 1;
191185222Ssam			subfield <<= 1;
192185222Ssam		}
193185222Ssam	}
194185222Ssam}
195185222Ssam
196185222Ssam#if defined(_KERNEL) && defined(DIAGNOSTIC)
197185222Ssamvoid
198185222Ssamffs_checkoverlap(bp, ip)
199185222Ssam	struct buf *bp;
200185222Ssam	struct inode *ip;
201185222Ssam{
202185222Ssam#if 0
203185222Ssam	struct buf *ebp, *ep;
204185222Ssam	daddr_t start, last;
205185222Ssam	struct vnode *vp;
206185222Ssam
207185222Ssam	ebp = &buf[nbuf];
208185222Ssam	start = bp->b_blkno;
209185222Ssam	last = start + btodb(bp->b_bcount) - 1;
210185222Ssam	for (ep = buf; ep < ebp; ep++) {
211185222Ssam		if (ep == bp || (ep->b_flags & B_INVAL) ||
212185222Ssam		    ep->b_vp == NULLVP)
213185222Ssam			continue;
214185222Ssam		if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL))
215185222Ssam			continue;
216185222Ssam		if (vp != ip->i_devvp)
217185222Ssam			continue;
218185222Ssam		/* look for overlap */
219185222Ssam		if (ep->b_bcount == 0 || ep->b_blkno > last ||
220185222Ssam		    ep->b_blkno + btodb(ep->b_bcount) <= start)
221185222Ssam			continue;
222185222Ssam		vprint("Disk overlap", vp);
223185222Ssam		printf("\tstart %" PRId64 ", end %" PRId64 " overlap start "
224185222Ssam		    "%" PRId64 ", end %" PRId64 "\n",
225185222Ssam		    start, last, ep->b_blkno,
226185222Ssam		    ep->b_blkno + btodb(ep->b_bcount) - 1);
227185222Ssam		panic("Disk buffer overlap");
228185222Ssam	}
229185222Ssam#else
230185222Ssam	printf("ffs_checkoverlap disabled due to buffer cache implementation changes\n");
231185222Ssam#endif
232185222Ssam}
233185222Ssam#endif /* _KERNEL && DIAGNOSTIC */
234185222Ssam
235185222Ssam/*
236185222Ssam * block operations
237185222Ssam *
238185222Ssam * check if a block is available
239185222Ssam *  returns true if all the correponding bits in the free map are 1
240185222Ssam *  returns false if any corresponding bit in the free map is 0
241185222Ssam */
242185222Ssamint
243185222Ssamffs_isblock(fs, cp, h)
244185222Ssam	struct fs *fs;
245185222Ssam	u_char *cp;
246185222Ssam	int32_t h;
247185222Ssam{
248185222Ssam	u_char mask;
249185222Ssam
250185222Ssam	switch ((int)fs->fs_fragshift) {
251185222Ssam	case 3:
252185222Ssam		return (cp[h] == 0xff);
253185222Ssam	case 2:
254185222Ssam		mask = 0x0f << ((h & 0x1) << 2);
255185222Ssam		return ((cp[h >> 1] & mask) == mask);
256185222Ssam	case 1:
257185222Ssam		mask = 0x03 << ((h & 0x3) << 1);
258185222Ssam		return ((cp[h >> 2] & mask) == mask);
259185222Ssam	case 0:
260185222Ssam		mask = 0x01 << (h & 0x7);
261185222Ssam		return ((cp[h >> 3] & mask) == mask);
262185222Ssam	default:
263185222Ssam		panic("ffs_isblock: unknown fs_fragshift %d",
264185222Ssam		    (int)fs->fs_fragshift);
265185222Ssam	}
266185222Ssam}
267185222Ssam
268185222Ssam/*
269185222Ssam * check if a block is completely allocated
270185222Ssam *  returns true if all the corresponding bits in the free map are 0
271185222Ssam *  returns false if any corresponding bit in the free map is 1
272185222Ssam */
273185222Ssamint
274185222Ssamffs_isfreeblock(fs, cp, h)
275185222Ssam	struct fs *fs;
276185222Ssam	u_char *cp;
277185222Ssam	int32_t h;
278185222Ssam{
279185222Ssam
280185222Ssam	switch ((int)fs->fs_fragshift) {
281185222Ssam	case 3:
282185222Ssam		return (cp[h] == 0);
283185222Ssam	case 2:
284185222Ssam		return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
285185222Ssam	case 1:
286185222Ssam		return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
287185222Ssam	case 0:
288185222Ssam		return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
289185222Ssam	default:
290185222Ssam		panic("ffs_isfreeblock: unknown fs_fragshift %d",
291185222Ssam		    (int)fs->fs_fragshift);
292185222Ssam	}
293185222Ssam}
294185222Ssam
295185222Ssam/*
296185222Ssam * take a block out of the map
297185222Ssam */
298185222Ssamvoid
299185222Ssamffs_clrblock(fs, cp, h)
300185222Ssam	struct fs *fs;
301185222Ssam	u_char *cp;
302185222Ssam	int32_t h;
303185222Ssam{
304185222Ssam
305185222Ssam	switch ((int)fs->fs_fragshift) {
306185222Ssam	case 3:
307185222Ssam		cp[h] = 0;
308185222Ssam		return;
309185222Ssam	case 2:
310185222Ssam		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
311185222Ssam		return;
312185222Ssam	case 1:
313185222Ssam		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
314185222Ssam		return;
315185222Ssam	case 0:
316185222Ssam		cp[h >> 3] &= ~(0x01 << (h & 0x7));
317185222Ssam		return;
318185222Ssam	default:
319185222Ssam		panic("ffs_clrblock: unknown fs_fragshift %d",
320185222Ssam		    (int)fs->fs_fragshift);
321185222Ssam	}
322185222Ssam}
323185222Ssam
324185222Ssam/*
325185222Ssam * put a block into the map
326185222Ssam */
327185222Ssamvoid
328185222Ssamffs_setblock(fs, cp, h)
329185222Ssam	struct fs *fs;
330185222Ssam	u_char *cp;
331185222Ssam	int32_t h;
332185222Ssam{
333185222Ssam
334185222Ssam	switch ((int)fs->fs_fragshift) {
335185222Ssam	case 3:
336185222Ssam		cp[h] = 0xff;
337185222Ssam		return;
338185222Ssam	case 2:
339185222Ssam		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
340185222Ssam		return;
341185222Ssam	case 1:
342185222Ssam		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
343185222Ssam		return;
344185222Ssam	case 0:
345185222Ssam		cp[h >> 3] |= (0x01 << (h & 0x7));
346185222Ssam		return;
347185222Ssam	default:
348185222Ssam		panic("ffs_setblock: unknown fs_fragshift %d",
349185222Ssam		    (int)fs->fs_fragshift);
350185222Ssam	}
351185222Ssam}
352