1/*	$OpenBSD: ffs_subr.c,v 1.34 2021/10/20 06:35:39 semarie 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 */
56int
57ffs_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 */
83void	ffs_fragacct(struct fs *, int, int32_t[], int);
84int	ffs_isfreeblock(struct fs *, u_char *, daddr_t);
85int	ffs_isblock(struct fs *, u_char *, daddr_t);
86void	ffs_clrblock(struct fs *, u_char *, daddr_t);
87void	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 */
95void
96ffs_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	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
103	fragmap <<= 1;
104	for (siz = 1; siz < fs->fs_frag; siz++) {
105		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
106			continue;
107		field = around[siz];
108		subfield = inside[siz];
109		for (pos = siz; pos <= fs->fs_frag; pos++) {
110			if ((fragmap & field) == subfield) {
111				fraglist[siz] += cnt;
112				pos += siz;
113				field <<= siz;
114				subfield <<= siz;
115			}
116			field <<= 1;
117			subfield <<= 1;
118		}
119	}
120}
121
122#if defined(_KERNEL) && defined(DIAGNOSTIC)
123void
124ffs_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 */
159int
160ffs_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 */
183void
184ffs_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 */
207void
208ffs_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 */
231int
232ffs_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 */
253int
254ffs_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 */
314