1139825Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 4. Neither the name of the University nor the names of its contributors
141541Srgrimes *    may be used to endorse or promote products derived from this software
151541Srgrimes *    without specific prior written permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
2922521Sdyson *	@(#)ffs_subr.c	8.5 (Berkeley) 3/21/95
301541Srgrimes */
311541Srgrimes
32116192Sobrien#include <sys/cdefs.h>
33116192Sobrien__FBSDID("$FreeBSD$");
34116192Sobrien
351541Srgrimes#include <sys/param.h>
3622521Sdyson
3755206Speter#ifndef _KERNEL
3822521Sdyson#include <ufs/ufs/dinode.h>
3998542Smckusick#include <ufs/ffs/fs.h>
4022521Sdyson#else
411541Srgrimes#include <sys/systm.h>
4231561Sbde#include <sys/lock.h>
4398542Smckusick#include <sys/malloc.h>
4498542Smckusick#include <sys/mount.h>
451541Srgrimes#include <sys/vnode.h>
4660041Sphk#include <sys/bio.h>
471541Srgrimes#include <sys/buf.h>
4834924Sbde#include <sys/ucred.h>
4934924Sbde
501541Srgrimes#include <ufs/ufs/quota.h>
511541Srgrimes#include <ufs/ufs/inode.h>
5298542Smckusick#include <ufs/ufs/extattr.h>
5398542Smckusick#include <ufs/ufs/ufsmount.h>
5498542Smckusick#include <ufs/ufs/ufs_extern.h>
5522521Sdyson#include <ufs/ffs/ffs_extern.h>
5698542Smckusick#include <ufs/ffs/fs.h>
571541Srgrimes
58131907Smarcel#ifdef KDB
5992728Salfredvoid	ffs_checkoverlap(struct buf *, struct inode *);
6031352Sbde#endif
6131352Sbde
621541Srgrimes/*
631541Srgrimes * Return buffer with the contents of block "offset" from the beginning of
641541Srgrimes * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
651541Srgrimes * remaining space in the directory.
661541Srgrimes */
671541Srgrimesint
6830474Sphkffs_blkatoff(vp, offset, res, bpp)
6930474Sphk	struct vnode *vp;
7030474Sphk	off_t offset;
7130474Sphk	char **res;
7230474Sphk	struct buf **bpp;
731541Srgrimes{
741541Srgrimes	struct inode *ip;
7596506Sphk	struct fs *fs;
761541Srgrimes	struct buf *bp;
7798542Smckusick	ufs_lbn_t lbn;
781541Srgrimes	int bsize, error;
791541Srgrimes
8030474Sphk	ip = VTOI(vp);
811541Srgrimes	fs = ip->i_fs;
8230474Sphk	lbn = lblkno(fs, offset);
831541Srgrimes	bsize = blksize(fs, ip, lbn);
841541Srgrimes
8530474Sphk	*bpp = NULL;
8630474Sphk	error = bread(vp, lbn, bsize, NOCRED, &bp);
873487Sphk	if (error) {
881541Srgrimes		brelse(bp);
891541Srgrimes		return (error);
901541Srgrimes	}
9130474Sphk	if (res)
9230474Sphk		*res = (char *)bp->b_data + blkoff(fs, offset);
9330474Sphk	*bpp = bp;
941541Srgrimes	return (0);
951541Srgrimes}
961541Srgrimes
971541Srgrimes/*
9898542Smckusick * Load up the contents of an inode and copy the appropriate pieces
9998542Smckusick * to the incore copy.
10098542Smckusick */
10198542Smckusickvoid
102108315Sphkffs_load_inode(bp, ip, fs, ino)
10398542Smckusick	struct buf *bp;
10498542Smckusick	struct inode *ip;
10598542Smckusick	struct fs *fs;
10698542Smckusick	ino_t ino;
10798542Smckusick{
10898542Smckusick
10998542Smckusick	if (ip->i_ump->um_fstype == UFS1) {
11098542Smckusick		*ip->i_din1 =
11198542Smckusick		    *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
11298542Smckusick		ip->i_mode = ip->i_din1->di_mode;
11398542Smckusick		ip->i_nlink = ip->i_din1->di_nlink;
11498542Smckusick		ip->i_size = ip->i_din1->di_size;
11598542Smckusick		ip->i_flags = ip->i_din1->di_flags;
11698542Smckusick		ip->i_gen = ip->i_din1->di_gen;
11798542Smckusick		ip->i_uid = ip->i_din1->di_uid;
11898542Smckusick		ip->i_gid = ip->i_din1->di_gid;
11998542Smckusick	} else {
12098542Smckusick		*ip->i_din2 =
12198542Smckusick		    *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
12298542Smckusick		ip->i_mode = ip->i_din2->di_mode;
12398542Smckusick		ip->i_nlink = ip->i_din2->di_nlink;
12498542Smckusick		ip->i_size = ip->i_din2->di_size;
12598542Smckusick		ip->i_flags = ip->i_din2->di_flags;
12698542Smckusick		ip->i_gen = ip->i_din2->di_gen;
12798542Smckusick		ip->i_uid = ip->i_din2->di_uid;
12898542Smckusick		ip->i_gid = ip->i_din2->di_gid;
12998542Smckusick	}
13098542Smckusick}
13198542Smckusick#endif /* KERNEL */
13298542Smckusick
13398542Smckusick/*
1348876Srgrimes * Update the frsum fields to reflect addition or deletion
1351541Srgrimes * of some frags.
1361541Srgrimes */
1371541Srgrimesvoid
1381541Srgrimesffs_fragacct(fs, fragmap, fraglist, cnt)
1391541Srgrimes	struct fs *fs;
1401541Srgrimes	int fragmap;
14122521Sdyson	int32_t fraglist[];
1421541Srgrimes	int cnt;
1431541Srgrimes{
1441541Srgrimes	int inblk;
14596506Sphk	int field, subfield;
14696506Sphk	int siz, pos;
1471541Srgrimes
1481541Srgrimes	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
1491541Srgrimes	fragmap <<= 1;
1501541Srgrimes	for (siz = 1; siz < fs->fs_frag; siz++) {
1511541Srgrimes		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
1521541Srgrimes			continue;
1531541Srgrimes		field = around[siz];
1541541Srgrimes		subfield = inside[siz];
1551541Srgrimes		for (pos = siz; pos <= fs->fs_frag; pos++) {
1561541Srgrimes			if ((fragmap & field) == subfield) {
1571541Srgrimes				fraglist[siz] += cnt;
1581541Srgrimes				pos += siz;
1591541Srgrimes				field <<= siz;
1601541Srgrimes				subfield <<= siz;
1611541Srgrimes			}
1621541Srgrimes			field <<= 1;
1631541Srgrimes			subfield <<= 1;
1641541Srgrimes		}
1651541Srgrimes	}
1661541Srgrimes}
1671541Srgrimes
168131907Smarcel#ifdef KDB
16942567Seivindvoid
1701541Srgrimesffs_checkoverlap(bp, ip)
1711541Srgrimes	struct buf *bp;
1721541Srgrimes	struct inode *ip;
1731541Srgrimes{
17496506Sphk	struct buf *ebp, *ep;
17598542Smckusick	ufs2_daddr_t start, last;
1761541Srgrimes	struct vnode *vp;
1771541Srgrimes
1781541Srgrimes	ebp = &buf[nbuf];
1791541Srgrimes	start = bp->b_blkno;
1801541Srgrimes	last = start + btodb(bp->b_bcount) - 1;
1811541Srgrimes	for (ep = buf; ep < ebp; ep++) {
1821541Srgrimes		if (ep == bp || (ep->b_flags & B_INVAL) ||
1831541Srgrimes		    ep->b_vp == NULLVP)
1841541Srgrimes			continue;
18576173Sphk		vp = ip->i_devvp;
1861541Srgrimes		/* look for overlap */
1871541Srgrimes		if (ep->b_bcount == 0 || ep->b_blkno > last ||
1881541Srgrimes		    ep->b_blkno + btodb(ep->b_bcount) <= start)
1891541Srgrimes			continue;
1901541Srgrimes		vprint("Disk overlap", vp);
19198687Smux		printf("\tstart %jd, end %jd overlap start %jd, end %jd\n",
19298542Smckusick		    (intmax_t)start, (intmax_t)last, (intmax_t)ep->b_blkno,
19398542Smckusick		    (intmax_t)(ep->b_blkno + btodb(ep->b_bcount) - 1));
19423560Smpp		panic("ffs_checkoverlap: Disk buffer overlap");
1951541Srgrimes	}
1961541Srgrimes}
197131907Smarcel#endif /* KDB */
1981541Srgrimes
1991541Srgrimes/*
2001541Srgrimes * block operations
2011541Srgrimes *
2021541Srgrimes * check if a block is available
2031541Srgrimes */
2041541Srgrimesint
2051541Srgrimesffs_isblock(fs, cp, h)
2061541Srgrimes	struct fs *fs;
2071541Srgrimes	unsigned char *cp;
20898542Smckusick	ufs1_daddr_t h;
2091541Srgrimes{
2101541Srgrimes	unsigned char mask;
2111541Srgrimes
2121541Srgrimes	switch ((int)fs->fs_frag) {
2131541Srgrimes	case 8:
2141541Srgrimes		return (cp[h] == 0xff);
2151541Srgrimes	case 4:
2161541Srgrimes		mask = 0x0f << ((h & 0x1) << 2);
2171541Srgrimes		return ((cp[h >> 1] & mask) == mask);
2181541Srgrimes	case 2:
2191541Srgrimes		mask = 0x03 << ((h & 0x3) << 1);
2201541Srgrimes		return ((cp[h >> 2] & mask) == mask);
2211541Srgrimes	case 1:
2221541Srgrimes		mask = 0x01 << (h & 0x7);
2231541Srgrimes		return ((cp[h >> 3] & mask) == mask);
2241541Srgrimes	default:
225207141Sjeff#ifdef _KERNEL
2261541Srgrimes		panic("ffs_isblock");
227207141Sjeff#endif
228207141Sjeff		break;
2291541Srgrimes	}
23073942Smckusick	return (0);
2311541Srgrimes}
2321541Srgrimes
2331541Srgrimes/*
234207141Sjeff * check if a block is free
235207141Sjeff */
236207141Sjeffint
237207141Sjeffffs_isfreeblock(fs, cp, h)
238207141Sjeff	struct fs *fs;
239207141Sjeff	u_char *cp;
240207141Sjeff	ufs1_daddr_t h;
241207141Sjeff{
242207141Sjeff
243207141Sjeff	switch ((int)fs->fs_frag) {
244207141Sjeff	case 8:
245207141Sjeff		return (cp[h] == 0);
246207141Sjeff	case 4:
247207141Sjeff		return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
248207141Sjeff	case 2:
249207141Sjeff		return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
250207141Sjeff	case 1:
251207141Sjeff		return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
252207141Sjeff	default:
253207141Sjeff#ifdef _KERNEL
254207141Sjeff		panic("ffs_isfreeblock");
255207141Sjeff#endif
256207141Sjeff		break;
257207141Sjeff	}
258207141Sjeff	return (0);
259207141Sjeff}
260207141Sjeff
261207141Sjeff/*
2621541Srgrimes * take a block out of the map
2631541Srgrimes */
2641541Srgrimesvoid
2651541Srgrimesffs_clrblock(fs, cp, h)
2661541Srgrimes	struct fs *fs;
2671541Srgrimes	u_char *cp;
26898542Smckusick	ufs1_daddr_t h;
2691541Srgrimes{
2701541Srgrimes
2711541Srgrimes	switch ((int)fs->fs_frag) {
2721541Srgrimes	case 8:
2731541Srgrimes		cp[h] = 0;
2741541Srgrimes		return;
2751541Srgrimes	case 4:
2761541Srgrimes		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
2771541Srgrimes		return;
2781541Srgrimes	case 2:
2791541Srgrimes		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
2801541Srgrimes		return;
2811541Srgrimes	case 1:
2821541Srgrimes		cp[h >> 3] &= ~(0x01 << (h & 0x7));
2831541Srgrimes		return;
2841541Srgrimes	default:
285207141Sjeff#ifdef _KERNEL
2861541Srgrimes		panic("ffs_clrblock");
287207141Sjeff#endif
288207141Sjeff		break;
2891541Srgrimes	}
2901541Srgrimes}
2911541Srgrimes
2921541Srgrimes/*
2931541Srgrimes * put a block into the map
2941541Srgrimes */
2951541Srgrimesvoid
2961541Srgrimesffs_setblock(fs, cp, h)
2971541Srgrimes	struct fs *fs;
2981541Srgrimes	unsigned char *cp;
29998542Smckusick	ufs1_daddr_t h;
3001541Srgrimes{
3011541Srgrimes
3021541Srgrimes	switch ((int)fs->fs_frag) {
3031541Srgrimes
3041541Srgrimes	case 8:
3051541Srgrimes		cp[h] = 0xff;
3061541Srgrimes		return;
3071541Srgrimes	case 4:
3081541Srgrimes		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
3091541Srgrimes		return;
3101541Srgrimes	case 2:
3111541Srgrimes		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
3121541Srgrimes		return;
3131541Srgrimes	case 1:
3141541Srgrimes		cp[h >> 3] |= (0x01 << (h & 0x7));
3151541Srgrimes		return;
3161541Srgrimes	default:
317207141Sjeff#ifdef _KERNEL
3181541Srgrimes		panic("ffs_setblock");
319207141Sjeff#endif
320207141Sjeff		break;
3211541Srgrimes	}
3221541Srgrimes}
323207141Sjeff
324207141Sjeff/*
325207141Sjeff * Update the cluster map because of an allocation or free.
326207141Sjeff *
327207141Sjeff * Cnt == 1 means free; cnt == -1 means allocating.
328207141Sjeff */
329207141Sjeffvoid
330207141Sjeffffs_clusteracct(fs, cgp, blkno, cnt)
331207141Sjeff	struct fs *fs;
332207141Sjeff	struct cg *cgp;
333207141Sjeff	ufs1_daddr_t blkno;
334207141Sjeff	int cnt;
335207141Sjeff{
336207141Sjeff	int32_t *sump;
337207141Sjeff	int32_t *lp;
338207141Sjeff	u_char *freemapp, *mapp;
339207141Sjeff	int i, start, end, forw, back, map, bit;
340207141Sjeff
341207141Sjeff	if (fs->fs_contigsumsize <= 0)
342207141Sjeff		return;
343207141Sjeff	freemapp = cg_clustersfree(cgp);
344207141Sjeff	sump = cg_clustersum(cgp);
345207141Sjeff	/*
346207141Sjeff	 * Allocate or clear the actual block.
347207141Sjeff	 */
348207141Sjeff	if (cnt > 0)
349207141Sjeff		setbit(freemapp, blkno);
350207141Sjeff	else
351207141Sjeff		clrbit(freemapp, blkno);
352207141Sjeff	/*
353207141Sjeff	 * Find the size of the cluster going forward.
354207141Sjeff	 */
355207141Sjeff	start = blkno + 1;
356207141Sjeff	end = start + fs->fs_contigsumsize;
357207141Sjeff	if (end >= cgp->cg_nclusterblks)
358207141Sjeff		end = cgp->cg_nclusterblks;
359207141Sjeff	mapp = &freemapp[start / NBBY];
360207141Sjeff	map = *mapp++;
361207141Sjeff	bit = 1 << (start % NBBY);
362207141Sjeff	for (i = start; i < end; i++) {
363207141Sjeff		if ((map & bit) == 0)
364207141Sjeff			break;
365207141Sjeff		if ((i & (NBBY - 1)) != (NBBY - 1)) {
366207141Sjeff			bit <<= 1;
367207141Sjeff		} else {
368207141Sjeff			map = *mapp++;
369207141Sjeff			bit = 1;
370207141Sjeff		}
371207141Sjeff	}
372207141Sjeff	forw = i - start;
373207141Sjeff	/*
374207141Sjeff	 * Find the size of the cluster going backward.
375207141Sjeff	 */
376207141Sjeff	start = blkno - 1;
377207141Sjeff	end = start - fs->fs_contigsumsize;
378207141Sjeff	if (end < 0)
379207141Sjeff		end = -1;
380207141Sjeff	mapp = &freemapp[start / NBBY];
381207141Sjeff	map = *mapp--;
382207141Sjeff	bit = 1 << (start % NBBY);
383207141Sjeff	for (i = start; i > end; i--) {
384207141Sjeff		if ((map & bit) == 0)
385207141Sjeff			break;
386207141Sjeff		if ((i & (NBBY - 1)) != 0) {
387207141Sjeff			bit >>= 1;
388207141Sjeff		} else {
389207141Sjeff			map = *mapp--;
390207141Sjeff			bit = 1 << (NBBY - 1);
391207141Sjeff		}
392207141Sjeff	}
393207141Sjeff	back = start - i;
394207141Sjeff	/*
395207141Sjeff	 * Account for old cluster and the possibly new forward and
396207141Sjeff	 * back clusters.
397207141Sjeff	 */
398207141Sjeff	i = back + forw + 1;
399207141Sjeff	if (i > fs->fs_contigsumsize)
400207141Sjeff		i = fs->fs_contigsumsize;
401207141Sjeff	sump[i] += cnt;
402207141Sjeff	if (back > 0)
403207141Sjeff		sump[back] -= cnt;
404207141Sjeff	if (forw > 0)
405207141Sjeff		sump[forw] -= cnt;
406207141Sjeff	/*
407207141Sjeff	 * Update cluster summary information.
408207141Sjeff	 */
409207141Sjeff	lp = &sump[fs->fs_contigsumsize];
410207141Sjeff	for (i = fs->fs_contigsumsize; i > 0; i--)
411207141Sjeff		if (*lp-- > 0)
412207141Sjeff			break;
413207141Sjeff	fs->fs_maxcluster[cgp->cg_cgx] = i;
414207141Sjeff}
415