xref: /csrg-svn/sys/ufs/lfs/lfs_alloc.c (revision 25471)
123394Smckusick /*
223394Smckusick  * Copyright (c) 1982 Regents of the University of California.
323394Smckusick  * All rights reserved.  The Berkeley software License Agreement
423394Smckusick  * specifies the terms and conditions for redistribution.
523394Smckusick  *
6*25471Smckusick  *	@(#)lfs_alloc.c	6.18 (Berkeley) 11/11/85
723394Smckusick  */
84359Smckusick 
917097Sbloom #include "param.h"
1017097Sbloom #include "systm.h"
1117097Sbloom #include "mount.h"
1217097Sbloom #include "fs.h"
1317097Sbloom #include "buf.h"
1417097Sbloom #include "inode.h"
1517097Sbloom #include "dir.h"
1617097Sbloom #include "user.h"
1717097Sbloom #include "quota.h"
1817097Sbloom #include "kernel.h"
1918307Sralph #include "syslog.h"
204359Smckusick 
215212Smckusic extern u_long		hashalloc();
229163Ssam extern ino_t		ialloccg();
239163Ssam extern daddr_t		alloccg();
244651Smckusic extern daddr_t		alloccgblk();
254651Smckusic extern daddr_t		fragextend();
264651Smckusic extern daddr_t		blkpref();
274651Smckusic extern daddr_t		mapsearch();
284607Smckusic extern int		inside[], around[];
295322Smckusic extern unsigned char	*fragtbl[];
304359Smckusick 
315375Smckusic /*
325375Smckusic  * Allocate a block in the file system.
335375Smckusic  *
345375Smckusic  * The size of the requested block is given, which must be some
355375Smckusic  * multiple of fs_fsize and <= fs_bsize.
365375Smckusic  * A preference may be optionally specified. If a preference is given
375375Smckusic  * the following hierarchy is used to allocate a block:
385375Smckusic  *   1) allocate the requested block.
395375Smckusic  *   2) allocate a rotationally optimal block in the same cylinder.
405375Smckusic  *   3) allocate a block in the same cylinder group.
415375Smckusic  *   4) quadradically rehash into other cylinder groups, until an
425375Smckusic  *      available block is located.
435375Smckusic  * If no block preference is given the following heirarchy is used
445375Smckusic  * to allocate a block:
455375Smckusic  *   1) allocate a block in the cylinder group that contains the
465375Smckusic  *      inode for the file.
475375Smckusic  *   2) quadradically rehash into other cylinder groups, until an
485375Smckusic  *      available block is located.
495375Smckusic  */
504359Smckusick struct buf *
515965Smckusic alloc(ip, bpref, size)
524463Smckusic 	register struct inode *ip;
534359Smckusick 	daddr_t bpref;
544359Smckusick 	int size;
554359Smckusick {
564359Smckusick 	daddr_t bno;
574359Smckusick 	register struct fs *fs;
584463Smckusic 	register struct buf *bp;
594359Smckusick 	int cg;
604359Smckusick 
615965Smckusic 	fs = ip->i_fs;
626716Smckusick 	if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
636716Smckusick 		printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
646716Smckusick 		    ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
654463Smckusic 		panic("alloc: bad size");
666716Smckusick 	}
675322Smckusic 	if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
684359Smckusick 		goto nospace;
6911638Ssam 	if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
704792Smckusic 		goto nospace;
717650Ssam #ifdef QUOTA
7212643Ssam 	u.u_error = chkdq(ip, (long)btodb(size), 0);
7312643Ssam 	if (u.u_error)
7412643Ssam 		return (NULL);
757483Skre #endif
764948Smckusic 	if (bpref >= fs->fs_size)
774948Smckusic 		bpref = 0;
784359Smckusick 	if (bpref == 0)
795377Smckusic 		cg = itog(fs, ip->i_number);
804359Smckusick 	else
815377Smckusic 		cg = dtog(fs, bpref);
829163Ssam 	bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size,
839163Ssam 		(u_long (*)())alloccg);
846567Smckusic 	if (bno <= 0)
854359Smckusick 		goto nospace;
8612643Ssam 	ip->i_blocks += btodb(size);
8712643Ssam 	ip->i_flag |= IUPD|ICHG;
885965Smckusic 	bp = getblk(ip->i_dev, fsbtodb(fs, bno), size);
894359Smckusick 	clrbuf(bp);
904359Smckusick 	return (bp);
914359Smckusick nospace:
924359Smckusick 	fserr(fs, "file system full");
934359Smckusick 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
944359Smckusick 	u.u_error = ENOSPC;
954359Smckusick 	return (NULL);
964359Smckusick }
974359Smckusick 
985375Smckusic /*
995375Smckusic  * Reallocate a fragment to a bigger size
1005375Smckusic  *
1015375Smckusic  * The number and size of the old block is given, and a preference
1025375Smckusic  * and new size is also specified. The allocator attempts to extend
1035375Smckusic  * the original block. Failing that, the regular block allocator is
1045375Smckusic  * invoked to get an appropriate block.
1055375Smckusic  */
1064426Smckusic struct buf *
1075965Smckusic realloccg(ip, bprev, bpref, osize, nsize)
1085965Smckusic 	register struct inode *ip;
1094651Smckusic 	daddr_t bprev, bpref;
1104426Smckusic 	int osize, nsize;
1114426Smckusic {
1124426Smckusic 	register struct fs *fs;
1134463Smckusic 	register struct buf *bp, *obp;
11424698Smckusick 	int cg, request;
115*25471Smckusick 	daddr_t bno, bn;
116*25471Smckusick 	int i, count, s;
117*25471Smckusick 	extern struct cmap *mfind();
1184426Smckusic 
1195965Smckusic 	fs = ip->i_fs;
1205960Smckusic 	if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
1216716Smckusick 	    (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
1226716Smckusick 		printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n",
1236716Smckusick 		    ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt);
1244463Smckusic 		panic("realloccg: bad size");
1256716Smckusick 	}
12611638Ssam 	if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
1274792Smckusic 		goto nospace;
1286716Smckusick 	if (bprev == 0) {
1296716Smckusick 		printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n",
1306716Smckusick 		    ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt);
1314463Smckusic 		panic("realloccg: bad bprev");
1326716Smckusick 	}
1337650Ssam #ifdef QUOTA
13412643Ssam 	u.u_error = chkdq(ip, (long)btodb(nsize - osize), 0);
13512643Ssam 	if (u.u_error)
13612643Ssam 		return (NULL);
1377483Skre #endif
1386294Smckusick 	cg = dtog(fs, bprev);
1395965Smckusic 	bno = fragextend(ip, cg, (long)bprev, osize, nsize);
1404463Smckusic 	if (bno != 0) {
1417187Sroot 		do {
1427187Sroot 			bp = bread(ip->i_dev, fsbtodb(fs, bno), osize);
1437187Sroot 			if (bp->b_flags & B_ERROR) {
1447187Sroot 				brelse(bp);
1457187Sroot 				return (NULL);
1467187Sroot 			}
1477187Sroot 		} while (brealloc(bp, nsize) == 0);
1487187Sroot 		bp->b_flags |= B_DONE;
1499163Ssam 		bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
15012643Ssam 		ip->i_blocks += btodb(nsize - osize);
15112643Ssam 		ip->i_flag |= IUPD|ICHG;
1524463Smckusic 		return (bp);
1534463Smckusic 	}
1544948Smckusic 	if (bpref >= fs->fs_size)
1554948Smckusic 		bpref = 0;
15625256Smckusick 	switch (fs->fs_optim) {
15725256Smckusick 	case FS_OPTSPACE:
15825256Smckusick 		/*
15925256Smckusick 		 * Allocate an exact sized fragment. Although this makes
16025256Smckusick 		 * best use of space, we will waste time relocating it if
16125256Smckusick 		 * the file continues to grow. If the fragmentation is
16225256Smckusick 		 * less than half of the minimum free reserve, we choose
16325256Smckusick 		 * to begin optimizing for time.
16425256Smckusick 		 */
16524698Smckusick 		request = nsize;
16625256Smckusick 		if (fs->fs_minfree < 5 ||
16725256Smckusick 		    fs->fs_cstotal.cs_nffree >
16825256Smckusick 		    fs->fs_dsize * fs->fs_minfree / (2 * 100))
16925256Smckusick 			break;
17025256Smckusick 		log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n",
17125256Smckusick 			fs->fs_fsmnt);
17225256Smckusick 		fs->fs_optim = FS_OPTTIME;
17325256Smckusick 		break;
17425256Smckusick 	case FS_OPTTIME:
17525256Smckusick 		/*
17625256Smckusick 		 * At this point we have discovered a file that is trying
17725256Smckusick 		 * to grow a small fragment to a larger fragment. To save
17825256Smckusick 		 * time, we allocate a full sized block, then free the
17925256Smckusick 		 * unused portion. If the file continues to grow, the
18025256Smckusick 		 * `fragextend' call above will be able to grow it in place
18125256Smckusick 		 * without further copying. If aberrant programs cause
18225256Smckusick 		 * disk fragmentation to grow within 2% of the free reserve,
18325256Smckusick 		 * we choose to begin optimizing for space.
18425256Smckusick 		 */
18524698Smckusick 		request = fs->fs_bsize;
18625256Smckusick 		if (fs->fs_cstotal.cs_nffree <
18725256Smckusick 		    fs->fs_dsize * (fs->fs_minfree - 2) / 100)
18825256Smckusick 			break;
18925256Smckusick 		log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n",
19025256Smckusick 			fs->fs_fsmnt);
19125256Smckusick 		fs->fs_optim = FS_OPTSPACE;
19225256Smckusick 		break;
19325256Smckusick 	default:
19425256Smckusick 		printf("dev = 0x%x, optim = %d, fs = %s\n",
19525256Smckusick 		    ip->i_dev, fs->fs_optim, fs->fs_fsmnt);
19625256Smckusick 		panic("realloccg: bad optim");
19725256Smckusick 		/* NOTREACHED */
19825256Smckusick 	}
19924698Smckusick 	bno = (daddr_t)hashalloc(ip, cg, (long)bpref, request,
2009163Ssam 		(u_long (*)())alloccg);
2016567Smckusic 	if (bno > 0) {
2025965Smckusic 		obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize);
2035960Smckusic 		if (obp->b_flags & B_ERROR) {
2045960Smckusic 			brelse(obp);
2056294Smckusick 			return (NULL);
2065960Smckusic 		}
207*25471Smckusick 		bn = fsbtodb(fs, bno);
208*25471Smckusick 		bp = getblk(ip->i_dev, bn, nsize);
20917658Smckusick 		bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
210*25471Smckusick 		count = howmany(osize, DEV_BSIZE);
211*25471Smckusick 		s = splimp();
212*25471Smckusick 		for (i = 0; i < count; i += CLBYTES / DEV_BSIZE)
213*25471Smckusick 			if (mfind(ip->i_dev, bn + i))
214*25471Smckusick 				munhash(ip->i_dev, bn + i);
215*25471Smckusick 		splx(s);
21617658Smckusick 		bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
21717658Smckusick 		if (obp->b_flags & B_DELWRI) {
21817658Smckusick 			obp->b_flags &= ~B_DELWRI;
21917658Smckusick 			u.u_ru.ru_oublock--;		/* delete charge */
22017658Smckusick 		}
2214463Smckusic 		brelse(obp);
2229163Ssam 		free(ip, bprev, (off_t)osize);
22324698Smckusick 		if (nsize < request)
22417709Smckusick 			free(ip, bno + numfrags(fs, nsize),
22524698Smckusick 				(off_t)(request - nsize));
22612643Ssam 		ip->i_blocks += btodb(nsize - osize);
22712643Ssam 		ip->i_flag |= IUPD|ICHG;
2286294Smckusick 		return (bp);
2294463Smckusic 	}
2304792Smckusic nospace:
2314463Smckusic 	/*
2324463Smckusic 	 * no space available
2334463Smckusic 	 */
2344426Smckusic 	fserr(fs, "file system full");
2354426Smckusic 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
2364426Smckusic 	u.u_error = ENOSPC;
2374426Smckusic 	return (NULL);
2384426Smckusic }
2394426Smckusic 
2405375Smckusic /*
2415375Smckusic  * Allocate an inode in the file system.
2425375Smckusic  *
2435375Smckusic  * A preference may be optionally specified. If a preference is given
2445375Smckusic  * the following hierarchy is used to allocate an inode:
2455375Smckusic  *   1) allocate the requested inode.
2465375Smckusic  *   2) allocate an inode in the same cylinder group.
2475375Smckusic  *   3) quadradically rehash into other cylinder groups, until an
2485375Smckusic  *      available inode is located.
2495375Smckusic  * If no inode preference is given the following heirarchy is used
2505375Smckusic  * to allocate an inode:
2515375Smckusic  *   1) allocate an inode in cylinder group 0.
2525375Smckusic  *   2) quadradically rehash into other cylinder groups, until an
2535375Smckusic  *      available inode is located.
2545375Smckusic  */
2554359Smckusick struct inode *
2565965Smckusic ialloc(pip, ipref, mode)
2575965Smckusic 	register struct inode *pip;
2584359Smckusick 	ino_t ipref;
2594359Smckusick 	int mode;
2604359Smckusick {
2615212Smckusic 	ino_t ino;
2624359Smckusick 	register struct fs *fs;
2634359Smckusick 	register struct inode *ip;
2644359Smckusick 	int cg;
2654359Smckusick 
2665965Smckusic 	fs = pip->i_fs;
2674792Smckusic 	if (fs->fs_cstotal.cs_nifree == 0)
2684359Smckusick 		goto noinodes;
2697650Ssam #ifdef QUOTA
27012643Ssam 	u.u_error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0);
27112643Ssam 	if (u.u_error)
27212643Ssam 		return (NULL);
2737483Skre #endif
2744948Smckusic 	if (ipref >= fs->fs_ncg * fs->fs_ipg)
2754948Smckusic 		ipref = 0;
2765377Smckusic 	cg = itog(fs, ipref);
2775965Smckusic 	ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
2784359Smckusick 	if (ino == 0)
2794359Smckusick 		goto noinodes;
2805965Smckusic 	ip = iget(pip->i_dev, pip->i_fs, ino);
2814359Smckusick 	if (ip == NULL) {
28215120Skarels 		ifree(pip, ino, 0);
2834359Smckusick 		return (NULL);
2844359Smckusick 	}
2856716Smckusick 	if (ip->i_mode) {
2866716Smckusick 		printf("mode = 0%o, inum = %d, fs = %s\n",
2876716Smckusick 		    ip->i_mode, ip->i_number, fs->fs_fsmnt);
2884359Smckusick 		panic("ialloc: dup alloc");
2896716Smckusick 	}
29012643Ssam 	if (ip->i_blocks) {				/* XXX */
29112643Ssam 		printf("free inode %s/%d had %d blocks\n",
29212643Ssam 		    fs->fs_fsmnt, ino, ip->i_blocks);
29312643Ssam 		ip->i_blocks = 0;
29412643Ssam 	}
2954359Smckusick 	return (ip);
2964359Smckusick noinodes:
2974359Smckusick 	fserr(fs, "out of inodes");
2986294Smckusick 	uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
2994359Smckusick 	u.u_error = ENOSPC;
3004359Smckusick 	return (NULL);
3014359Smckusick }
3024359Smckusick 
3034651Smckusic /*
3045375Smckusic  * Find a cylinder to place a directory.
3055375Smckusic  *
3065375Smckusic  * The policy implemented by this algorithm is to select from
3075375Smckusic  * among those cylinder groups with above the average number of
3085375Smckusic  * free inodes, the one with the smallest number of directories.
3094651Smckusic  */
3109163Ssam ino_t
3115965Smckusic dirpref(fs)
3125965Smckusic 	register struct fs *fs;
3134359Smckusick {
3144651Smckusic 	int cg, minndir, mincg, avgifree;
3154359Smckusick 
3164792Smckusic 	avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
3174651Smckusic 	minndir = fs->fs_ipg;
3184359Smckusick 	mincg = 0;
3194651Smckusic 	for (cg = 0; cg < fs->fs_ncg; cg++)
3205322Smckusic 		if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
3215322Smckusic 		    fs->fs_cs(fs, cg).cs_nifree >= avgifree) {
3224359Smckusick 			mincg = cg;
3235322Smckusic 			minndir = fs->fs_cs(fs, cg).cs_ndir;
3244359Smckusick 		}
3259163Ssam 	return ((ino_t)(fs->fs_ipg * mincg));
3264359Smckusick }
3274359Smckusick 
3284651Smckusic /*
3299163Ssam  * Select the desired position for the next block in a file.  The file is
3309163Ssam  * logically divided into sections. The first section is composed of the
3319163Ssam  * direct blocks. Each additional section contains fs_maxbpg blocks.
3329163Ssam  *
3339163Ssam  * If no blocks have been allocated in the first section, the policy is to
3349163Ssam  * request a block in the same cylinder group as the inode that describes
3359163Ssam  * the file. If no blocks have been allocated in any other section, the
3369163Ssam  * policy is to place the section in a cylinder group with a greater than
3379163Ssam  * average number of free blocks.  An appropriate cylinder group is found
33817696Smckusick  * by using a rotor that sweeps the cylinder groups. When a new group of
33917696Smckusick  * blocks is needed, the sweep begins in the cylinder group following the
34017696Smckusick  * cylinder group from which the previous allocation was made. The sweep
34117696Smckusick  * continues until a cylinder group with greater than the average number
34217696Smckusick  * of free blocks is found. If the allocation is for the first block in an
34317696Smckusick  * indirect block, the information on the previous allocation is unavailable;
34417696Smckusick  * here a best guess is made based upon the logical block number being
34517696Smckusick  * allocated.
3469163Ssam  *
3479163Ssam  * If a section is already partially allocated, the policy is to
3489163Ssam  * contiguously allocate fs_maxcontig blocks.  The end of one of these
3499163Ssam  * contiguous blocks and the beginning of the next is physically separated
3509163Ssam  * so that the disk head will be in transit between them for at least
3519163Ssam  * fs_rotdelay milliseconds.  This is to allow time for the processor to
3529163Ssam  * schedule another I/O transfer.
3534651Smckusic  */
3545212Smckusic daddr_t
3559163Ssam blkpref(ip, lbn, indx, bap)
3569163Ssam 	struct inode *ip;
3579163Ssam 	daddr_t lbn;
3589163Ssam 	int indx;
3599163Ssam 	daddr_t *bap;
3609163Ssam {
3615965Smckusic 	register struct fs *fs;
36217696Smckusick 	register int cg;
36317696Smckusick 	int avgbfree, startcg;
3649163Ssam 	daddr_t nextblk;
3654651Smckusic 
3669163Ssam 	fs = ip->i_fs;
3679163Ssam 	if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
3689163Ssam 		if (lbn < NDADDR) {
3699163Ssam 			cg = itog(fs, ip->i_number);
3705322Smckusic 			return (fs->fs_fpg * cg + fs->fs_frag);
3714651Smckusic 		}
3729163Ssam 		/*
3739163Ssam 		 * Find a cylinder with greater than average number of
3749163Ssam 		 * unused data blocks.
3759163Ssam 		 */
37617696Smckusick 		if (indx == 0 || bap[indx - 1] == 0)
37717696Smckusick 			startcg = itog(fs, ip->i_number) + lbn / fs->fs_maxbpg;
37817696Smckusick 		else
37917696Smckusick 			startcg = dtog(fs, bap[indx - 1]) + 1;
38017696Smckusick 		startcg %= fs->fs_ncg;
3819163Ssam 		avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
38217696Smckusick 		for (cg = startcg; cg < fs->fs_ncg; cg++)
3839163Ssam 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
3849163Ssam 				fs->fs_cgrotor = cg;
3859163Ssam 				return (fs->fs_fpg * cg + fs->fs_frag);
3869163Ssam 			}
38717696Smckusick 		for (cg = 0; cg <= startcg; cg++)
3889163Ssam 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
3899163Ssam 				fs->fs_cgrotor = cg;
3909163Ssam 				return (fs->fs_fpg * cg + fs->fs_frag);
3919163Ssam 			}
3929163Ssam 		return (NULL);
3939163Ssam 	}
3949163Ssam 	/*
3959163Ssam 	 * One or more previous blocks have been laid out. If less
3969163Ssam 	 * than fs_maxcontig previous blocks are contiguous, the
3979163Ssam 	 * next block is requested contiguously, otherwise it is
3989163Ssam 	 * requested rotationally delayed by fs_rotdelay milliseconds.
3999163Ssam 	 */
4009163Ssam 	nextblk = bap[indx - 1] + fs->fs_frag;
4019163Ssam 	if (indx > fs->fs_maxcontig &&
40211638Ssam 	    bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig)
4039163Ssam 	    != nextblk)
4049163Ssam 		return (nextblk);
4059163Ssam 	if (fs->fs_rotdelay != 0)
4069163Ssam 		/*
4079163Ssam 		 * Here we convert ms of delay to frags as:
4089163Ssam 		 * (frags) = (ms) * (rev/sec) * (sect/rev) /
4099163Ssam 		 *	((sect/frag) * (ms/sec))
4109163Ssam 		 * then round up to the next block.
4119163Ssam 		 */
4129163Ssam 		nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect /
4139163Ssam 		    (NSPF(fs) * 1000), fs->fs_frag);
4149163Ssam 	return (nextblk);
4154651Smckusic }
4164651Smckusic 
4175375Smckusic /*
4185375Smckusic  * Implement the cylinder overflow algorithm.
4195375Smckusic  *
4205375Smckusic  * The policy implemented by this algorithm is:
4215375Smckusic  *   1) allocate the block in its requested cylinder group.
4225375Smckusic  *   2) quadradically rehash on the cylinder group number.
4235375Smckusic  *   3) brute force search for a free block.
4245375Smckusic  */
4255212Smckusic /*VARARGS5*/
4265212Smckusic u_long
4275965Smckusic hashalloc(ip, cg, pref, size, allocator)
4285965Smckusic 	struct inode *ip;
4294359Smckusick 	int cg;
4304359Smckusick 	long pref;
4314359Smckusick 	int size;	/* size for data blocks, mode for inodes */
4325212Smckusic 	u_long (*allocator)();
4334359Smckusick {
4345965Smckusic 	register struct fs *fs;
4354359Smckusick 	long result;
4364359Smckusick 	int i, icg = cg;
4374359Smckusick 
4385965Smckusic 	fs = ip->i_fs;
4394359Smckusick 	/*
4404359Smckusick 	 * 1: preferred cylinder group
4414359Smckusick 	 */
4425965Smckusic 	result = (*allocator)(ip, cg, pref, size);
4434359Smckusick 	if (result)
4444359Smckusick 		return (result);
4454359Smckusick 	/*
4464359Smckusick 	 * 2: quadratic rehash
4474359Smckusick 	 */
4484359Smckusick 	for (i = 1; i < fs->fs_ncg; i *= 2) {
4494359Smckusick 		cg += i;
4504359Smckusick 		if (cg >= fs->fs_ncg)
4514359Smckusick 			cg -= fs->fs_ncg;
4525965Smckusic 		result = (*allocator)(ip, cg, 0, size);
4534359Smckusick 		if (result)
4544359Smckusick 			return (result);
4554359Smckusick 	}
4564359Smckusick 	/*
4574359Smckusick 	 * 3: brute force search
45810847Ssam 	 * Note that we start at i == 2, since 0 was checked initially,
45910847Ssam 	 * and 1 is always checked in the quadratic rehash.
4604359Smckusick 	 */
46110848Smckusick 	cg = (icg + 2) % fs->fs_ncg;
46210847Ssam 	for (i = 2; i < fs->fs_ncg; i++) {
4635965Smckusic 		result = (*allocator)(ip, cg, 0, size);
4644359Smckusick 		if (result)
4654359Smckusick 			return (result);
4664359Smckusick 		cg++;
4674359Smckusick 		if (cg == fs->fs_ncg)
4684359Smckusick 			cg = 0;
4694359Smckusick 	}
4706294Smckusick 	return (NULL);
4714359Smckusick }
4724359Smckusick 
4735375Smckusic /*
4745375Smckusic  * Determine whether a fragment can be extended.
4755375Smckusic  *
4765375Smckusic  * Check to see if the necessary fragments are available, and
4775375Smckusic  * if they are, allocate them.
4785375Smckusic  */
4794359Smckusick daddr_t
4805965Smckusic fragextend(ip, cg, bprev, osize, nsize)
4815965Smckusic 	struct inode *ip;
4824426Smckusic 	int cg;
4834463Smckusic 	long bprev;
4844426Smckusic 	int osize, nsize;
4854426Smckusic {
4865965Smckusic 	register struct fs *fs;
4874463Smckusic 	register struct buf *bp;
4884463Smckusic 	register struct cg *cgp;
4894463Smckusic 	long bno;
4904463Smckusic 	int frags, bbase;
4914426Smckusic 	int i;
4924426Smckusic 
4935965Smckusic 	fs = ip->i_fs;
49417224Smckusick 	if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
4956531Smckusick 		return (NULL);
4965960Smckusic 	frags = numfrags(fs, nsize);
49717224Smckusick 	bbase = fragnum(fs, bprev);
49817224Smckusick 	if (bbase > fragnum(fs, (bprev + frags - 1))) {
4994463Smckusic 		/* cannot extend across a block boundry */
5006294Smckusick 		return (NULL);
5014463Smckusic 	}
50210278Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
5036531Smckusick 	cgp = bp->b_un.b_cg;
5046531Smckusick 	if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) {
5055960Smckusic 		brelse(bp);
5066294Smckusick 		return (NULL);
5075960Smckusic 	}
5088105Sroot 	cgp->cg_time = time.tv_sec;
5095377Smckusic 	bno = dtogd(fs, bprev);
5105960Smckusic 	for (i = numfrags(fs, osize); i < frags; i++)
5115361Smckusic 		if (isclr(cgp->cg_free, bno + i)) {
5125361Smckusic 			brelse(bp);
5136294Smckusick 			return (NULL);
5145361Smckusic 		}
5155361Smckusic 	/*
5165361Smckusic 	 * the current fragment can be extended
5175361Smckusic 	 * deduct the count on fragment being extended into
5185361Smckusic 	 * increase the count on the remaining fragment (if any)
5195361Smckusic 	 * allocate the extended piece
5205361Smckusic 	 */
5215361Smckusic 	for (i = frags; i < fs->fs_frag - bbase; i++)
5224463Smckusic 		if (isclr(cgp->cg_free, bno + i))
5234463Smckusic 			break;
5245960Smckusic 	cgp->cg_frsum[i - numfrags(fs, osize)]--;
5255361Smckusic 	if (i != frags)
5265361Smckusic 		cgp->cg_frsum[i - frags]++;
5275960Smckusic 	for (i = numfrags(fs, osize); i < frags; i++) {
5285361Smckusic 		clrbit(cgp->cg_free, bno + i);
5295361Smckusic 		cgp->cg_cs.cs_nffree--;
5305361Smckusic 		fs->fs_cstotal.cs_nffree--;
5315361Smckusic 		fs->fs_cs(fs, cg).cs_nffree--;
5324463Smckusic 	}
5335361Smckusic 	fs->fs_fmod++;
5345361Smckusic 	bdwrite(bp);
5355361Smckusic 	return (bprev);
5364426Smckusic }
5374426Smckusic 
5385375Smckusic /*
5395375Smckusic  * Determine whether a block can be allocated.
5405375Smckusic  *
5415375Smckusic  * Check to see if a block of the apprpriate size is available,
5425375Smckusic  * and if it is, allocate it.
5435375Smckusic  */
5449163Ssam daddr_t
5455965Smckusic alloccg(ip, cg, bpref, size)
5465965Smckusic 	struct inode *ip;
5474359Smckusick 	int cg;
5484359Smckusick 	daddr_t bpref;
5494359Smckusick 	int size;
5504359Smckusick {
5515965Smckusic 	register struct fs *fs;
5524463Smckusic 	register struct buf *bp;
5534463Smckusic 	register struct cg *cgp;
5544463Smckusic 	int bno, frags;
5554463Smckusic 	int allocsiz;
5564463Smckusic 	register int i;
5574359Smckusick 
5585965Smckusic 	fs = ip->i_fs;
5595322Smckusic 	if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
5606294Smckusick 		return (NULL);
56110278Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
5626531Smckusick 	cgp = bp->b_un.b_cg;
56315950Smckusick 	if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC ||
56415950Smckusick 	    (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
5655960Smckusic 		brelse(bp);
5666294Smckusick 		return (NULL);
5675960Smckusic 	}
5688105Sroot 	cgp->cg_time = time.tv_sec;
5695322Smckusic 	if (size == fs->fs_bsize) {
5705212Smckusic 		bno = alloccgblk(fs, cgp, bpref);
5714463Smckusic 		bdwrite(bp);
5724463Smckusic 		return (bno);
5734463Smckusic 	}
5744463Smckusic 	/*
5754463Smckusic 	 * check to see if any fragments are already available
5764463Smckusic 	 * allocsiz is the size which will be allocated, hacking
5774463Smckusic 	 * it down to a smaller size if necessary
5784463Smckusic 	 */
5795960Smckusic 	frags = numfrags(fs, size);
5805322Smckusic 	for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
5814463Smckusic 		if (cgp->cg_frsum[allocsiz] != 0)
5824463Smckusic 			break;
5835322Smckusic 	if (allocsiz == fs->fs_frag) {
5844463Smckusic 		/*
5854463Smckusic 		 * no fragments were available, so a block will be
5864463Smckusic 		 * allocated, and hacked up
5874463Smckusic 		 */
5884792Smckusic 		if (cgp->cg_cs.cs_nbfree == 0) {
5894463Smckusic 			brelse(bp);
5906294Smckusick 			return (NULL);
5914463Smckusic 		}
5925212Smckusic 		bno = alloccgblk(fs, cgp, bpref);
5935377Smckusic 		bpref = dtogd(fs, bno);
5945322Smckusic 		for (i = frags; i < fs->fs_frag; i++)
5954463Smckusic 			setbit(cgp->cg_free, bpref + i);
5965322Smckusic 		i = fs->fs_frag - frags;
5974792Smckusic 		cgp->cg_cs.cs_nffree += i;
5984792Smckusic 		fs->fs_cstotal.cs_nffree += i;
5995322Smckusic 		fs->fs_cs(fs, cg).cs_nffree += i;
6009762Ssam 		fs->fs_fmod++;
6014463Smckusic 		cgp->cg_frsum[i]++;
6024463Smckusic 		bdwrite(bp);
6034463Smckusic 		return (bno);
6044463Smckusic 	}
6054651Smckusic 	bno = mapsearch(fs, cgp, bpref, allocsiz);
60615950Smckusick 	if (bno < 0) {
60715950Smckusick 		brelse(bp);
6086294Smckusick 		return (NULL);
60915950Smckusick 	}
6104463Smckusic 	for (i = 0; i < frags; i++)
6114463Smckusic 		clrbit(cgp->cg_free, bno + i);
6124792Smckusic 	cgp->cg_cs.cs_nffree -= frags;
6134792Smckusic 	fs->fs_cstotal.cs_nffree -= frags;
6145322Smckusic 	fs->fs_cs(fs, cg).cs_nffree -= frags;
6159762Ssam 	fs->fs_fmod++;
6164463Smckusic 	cgp->cg_frsum[allocsiz]--;
6174463Smckusic 	if (frags != allocsiz)
6184463Smckusic 		cgp->cg_frsum[allocsiz - frags]++;
6194463Smckusic 	bdwrite(bp);
6204463Smckusic 	return (cg * fs->fs_fpg + bno);
6214463Smckusic }
6224463Smckusic 
6235375Smckusic /*
6245375Smckusic  * Allocate a block in a cylinder group.
6255375Smckusic  *
6265375Smckusic  * This algorithm implements the following policy:
6275375Smckusic  *   1) allocate the requested block.
6285375Smckusic  *   2) allocate a rotationally optimal block in the same cylinder.
6295375Smckusic  *   3) allocate the next available block on the block rotor for the
6305375Smckusic  *      specified cylinder group.
6315375Smckusic  * Note that this routine only allocates fs_bsize blocks; these
6325375Smckusic  * blocks may be fragmented by the routine that allocates them.
6335375Smckusic  */
6344463Smckusic daddr_t
6355212Smckusic alloccgblk(fs, cgp, bpref)
6365965Smckusic 	register struct fs *fs;
6374463Smckusic 	register struct cg *cgp;
6384463Smckusic 	daddr_t bpref;
6394463Smckusic {
6404651Smckusic 	daddr_t bno;
6416294Smckusick 	int cylno, pos, delta;
6424651Smckusic 	short *cylbp;
6435361Smckusic 	register int i;
6444463Smckusic 
6454651Smckusic 	if (bpref == 0) {
6464651Smckusic 		bpref = cgp->cg_rotor;
6475361Smckusic 		goto norot;
6485361Smckusic 	}
64917224Smckusick 	bpref = blknum(fs, bpref);
6505377Smckusic 	bpref = dtogd(fs, bpref);
6515361Smckusic 	/*
6525361Smckusic 	 * if the requested block is available, use it
6535361Smckusic 	 */
65411638Ssam 	if (isblock(fs, cgp->cg_free, fragstoblks(fs, bpref))) {
6555361Smckusic 		bno = bpref;
6565361Smckusic 		goto gotit;
6575361Smckusic 	}
6585361Smckusic 	/*
6595361Smckusic 	 * check for a block available on the same cylinder
6605361Smckusic 	 */
6615361Smckusic 	cylno = cbtocylno(fs, bpref);
6625375Smckusic 	if (cgp->cg_btot[cylno] == 0)
6635375Smckusic 		goto norot;
6645375Smckusic 	if (fs->fs_cpc == 0) {
6655375Smckusic 		/*
6665375Smckusic 		 * block layout info is not available, so just have
6675375Smckusic 		 * to take any block in this cylinder.
6685375Smckusic 		 */
6695375Smckusic 		bpref = howmany(fs->fs_spc * cylno, NSPF(fs));
6705375Smckusic 		goto norot;
6715375Smckusic 	}
6725375Smckusic 	/*
6735361Smckusic 	 * check the summary information to see if a block is
6745361Smckusic 	 * available in the requested cylinder starting at the
6759163Ssam 	 * requested rotational position and proceeding around.
6765361Smckusic 	 */
6779163Ssam 	cylbp = cgp->cg_b[cylno];
6789163Ssam 	pos = cbtorpos(fs, bpref);
6795361Smckusic 	for (i = pos; i < NRPOS; i++)
6805361Smckusic 		if (cylbp[i] > 0)
6815361Smckusic 			break;
6825361Smckusic 	if (i == NRPOS)
6835361Smckusic 		for (i = 0; i < pos; i++)
6845361Smckusic 			if (cylbp[i] > 0)
6855361Smckusic 				break;
6865361Smckusic 	if (cylbp[i] > 0) {
6874651Smckusic 		/*
6885361Smckusic 		 * found a rotational position, now find the actual
6895361Smckusic 		 * block. A panic if none is actually there.
6904651Smckusic 		 */
6915361Smckusic 		pos = cylno % fs->fs_cpc;
6925361Smckusic 		bno = (cylno - pos) * fs->fs_spc / NSPB(fs);
6936716Smckusick 		if (fs->fs_postbl[pos][i] == -1) {
6946716Smckusick 			printf("pos = %d, i = %d, fs = %s\n",
6956716Smckusick 			    pos, i, fs->fs_fsmnt);
6965361Smckusic 			panic("alloccgblk: cyl groups corrupted");
6976716Smckusick 		}
6986294Smckusick 		for (i = fs->fs_postbl[pos][i];; ) {
6995361Smckusic 			if (isblock(fs, cgp->cg_free, bno + i)) {
70011638Ssam 				bno = blkstofrags(fs, (bno + i));
7015361Smckusic 				goto gotit;
7025361Smckusic 			}
7036294Smckusick 			delta = fs->fs_rotbl[i];
7046294Smckusick 			if (delta <= 0 || delta > MAXBPC - i)
7054651Smckusic 				break;
7066294Smckusick 			i += delta;
7074651Smckusic 		}
7086716Smckusick 		printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt);
7095361Smckusic 		panic("alloccgblk: can't find blk in cyl");
7104359Smckusick 	}
7115361Smckusic norot:
7125361Smckusic 	/*
7135361Smckusic 	 * no blocks in the requested cylinder, so take next
7145361Smckusic 	 * available one in this cylinder group.
7155361Smckusic 	 */
7168628Sroot 	bno = mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
7176567Smckusic 	if (bno < 0)
7186294Smckusick 		return (NULL);
7194651Smckusic 	cgp->cg_rotor = bno;
7204359Smckusick gotit:
72111638Ssam 	clrblock(fs, cgp->cg_free, (long)fragstoblks(fs, bno));
7224792Smckusic 	cgp->cg_cs.cs_nbfree--;
7234792Smckusic 	fs->fs_cstotal.cs_nbfree--;
7245322Smckusic 	fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--;
7255375Smckusic 	cylno = cbtocylno(fs, bno);
7265375Smckusic 	cgp->cg_b[cylno][cbtorpos(fs, bno)]--;
7275375Smckusic 	cgp->cg_btot[cylno]--;
7284359Smckusick 	fs->fs_fmod++;
7294651Smckusic 	return (cgp->cg_cgx * fs->fs_fpg + bno);
7304359Smckusick }
7314359Smckusick 
7325375Smckusic /*
7335375Smckusic  * Determine whether an inode can be allocated.
7345375Smckusic  *
7355375Smckusic  * Check to see if an inode is available, and if it is,
7365375Smckusic  * allocate it using the following policy:
7375375Smckusic  *   1) allocate the requested inode.
7385375Smckusic  *   2) allocate the next available inode after the requested
7395375Smckusic  *      inode in the specified cylinder group.
7405375Smckusic  */
7419163Ssam ino_t
7425965Smckusic ialloccg(ip, cg, ipref, mode)
7435965Smckusic 	struct inode *ip;
7444359Smckusick 	int cg;
7454359Smckusick 	daddr_t ipref;
7464359Smckusick 	int mode;
7474359Smckusick {
7485965Smckusic 	register struct fs *fs;
7494463Smckusic 	register struct cg *cgp;
75016784Smckusick 	struct buf *bp;
75116784Smckusick 	int start, len, loc, map, i;
7524359Smckusick 
7535965Smckusic 	fs = ip->i_fs;
7545322Smckusic 	if (fs->fs_cs(fs, cg).cs_nifree == 0)
7556294Smckusick 		return (NULL);
75610278Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
7576531Smckusick 	cgp = bp->b_un.b_cg;
75815950Smckusick 	if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC ||
75915950Smckusick 	    cgp->cg_cs.cs_nifree == 0) {
7605960Smckusic 		brelse(bp);
7616294Smckusick 		return (NULL);
7625960Smckusic 	}
7638105Sroot 	cgp->cg_time = time.tv_sec;
7644359Smckusick 	if (ipref) {
7654359Smckusick 		ipref %= fs->fs_ipg;
7664359Smckusick 		if (isclr(cgp->cg_iused, ipref))
7674359Smckusick 			goto gotit;
76816784Smckusick 	}
76916784Smckusick 	start = cgp->cg_irotor / NBBY;
77016784Smckusick 	len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY);
77116784Smckusick 	loc = skpc(0xff, len, &cgp->cg_iused[start]);
77216784Smckusick 	if (loc == 0) {
77317697Smckusick 		len = start + 1;
77417697Smckusick 		start = 0;
77517697Smckusick 		loc = skpc(0xff, len, &cgp->cg_iused[0]);
77617697Smckusick 		if (loc == 0) {
77717697Smckusick 			printf("cg = %s, irotor = %d, fs = %s\n",
77817697Smckusick 			    cg, cgp->cg_irotor, fs->fs_fsmnt);
77917697Smckusick 			panic("ialloccg: map corrupted");
78017697Smckusick 			/* NOTREACHED */
78117697Smckusick 		}
78216784Smckusick 	}
78316784Smckusick 	i = start + len - loc;
78416784Smckusick 	map = cgp->cg_iused[i];
78516784Smckusick 	ipref = i * NBBY;
78616784Smckusick 	for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
78716784Smckusick 		if ((map & i) == 0) {
7884359Smckusick 			cgp->cg_irotor = ipref;
7894359Smckusick 			goto gotit;
7904359Smckusick 		}
7914359Smckusick 	}
79216784Smckusick 	printf("fs = %s\n", fs->fs_fsmnt);
79316784Smckusick 	panic("ialloccg: block not in map");
79416784Smckusick 	/* NOTREACHED */
7954359Smckusick gotit:
7964359Smckusick 	setbit(cgp->cg_iused, ipref);
7974792Smckusic 	cgp->cg_cs.cs_nifree--;
7984792Smckusic 	fs->fs_cstotal.cs_nifree--;
7995322Smckusic 	fs->fs_cs(fs, cg).cs_nifree--;
8004359Smckusick 	fs->fs_fmod++;
8014359Smckusick 	if ((mode & IFMT) == IFDIR) {
8024792Smckusic 		cgp->cg_cs.cs_ndir++;
8034792Smckusic 		fs->fs_cstotal.cs_ndir++;
8045322Smckusic 		fs->fs_cs(fs, cg).cs_ndir++;
8054359Smckusick 	}
8064359Smckusick 	bdwrite(bp);
8074359Smckusick 	return (cg * fs->fs_ipg + ipref);
8084359Smckusick }
8094359Smckusick 
8105375Smckusic /*
8115375Smckusic  * Free a block or fragment.
8125375Smckusic  *
8135375Smckusic  * The specified block or fragment is placed back in the
8145375Smckusic  * free map. If a fragment is deallocated, a possible
8155375Smckusic  * block reassembly is checked.
8165375Smckusic  */
8179163Ssam free(ip, bno, size)
8185965Smckusic 	register struct inode *ip;
8194359Smckusick 	daddr_t bno;
8205212Smckusic 	off_t size;
8214359Smckusick {
8224359Smckusick 	register struct fs *fs;
8234359Smckusick 	register struct cg *cgp;
8244359Smckusick 	register struct buf *bp;
8254463Smckusic 	int cg, blk, frags, bbase;
8264463Smckusic 	register int i;
8274359Smckusick 
8285965Smckusic 	fs = ip->i_fs;
8296716Smckusick 	if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
8306716Smckusick 		printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
8316716Smckusick 		    ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
8324426Smckusic 		panic("free: bad size");
8336716Smckusick 	}
8345377Smckusic 	cg = dtog(fs, bno);
8356567Smckusic 	if (badblock(fs, bno)) {
8366567Smckusic 		printf("bad block %d, ino %d\n", bno, ip->i_number);
8374359Smckusick 		return;
8386567Smckusic 	}
83910278Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
8406531Smckusick 	cgp = bp->b_un.b_cg;
8416531Smckusick 	if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) {
8425960Smckusic 		brelse(bp);
8434359Smckusick 		return;
8445960Smckusic 	}
8458105Sroot 	cgp->cg_time = time.tv_sec;
8465377Smckusic 	bno = dtogd(fs, bno);
8475322Smckusic 	if (size == fs->fs_bsize) {
84811638Ssam 		if (isblock(fs, cgp->cg_free, fragstoblks(fs, bno))) {
8496716Smckusick 			printf("dev = 0x%x, block = %d, fs = %s\n",
8506716Smckusick 			    ip->i_dev, bno, fs->fs_fsmnt);
8514426Smckusic 			panic("free: freeing free block");
8526567Smckusic 		}
85311638Ssam 		setblock(fs, cgp->cg_free, fragstoblks(fs, bno));
8544792Smckusic 		cgp->cg_cs.cs_nbfree++;
8554792Smckusic 		fs->fs_cstotal.cs_nbfree++;
8565322Smckusic 		fs->fs_cs(fs, cg).cs_nbfree++;
8575375Smckusic 		i = cbtocylno(fs, bno);
8585375Smckusic 		cgp->cg_b[i][cbtorpos(fs, bno)]++;
8595375Smckusic 		cgp->cg_btot[i]++;
8604426Smckusic 	} else {
86117224Smckusick 		bbase = bno - fragnum(fs, bno);
8624463Smckusic 		/*
8634463Smckusic 		 * decrement the counts associated with the old frags
8644463Smckusic 		 */
8656294Smckusick 		blk = blkmap(fs, cgp->cg_free, bbase);
8665322Smckusic 		fragacct(fs, blk, cgp->cg_frsum, -1);
8674463Smckusic 		/*
8684463Smckusic 		 * deallocate the fragment
8694463Smckusic 		 */
8705960Smckusic 		frags = numfrags(fs, size);
8714463Smckusic 		for (i = 0; i < frags; i++) {
8726716Smckusick 			if (isset(cgp->cg_free, bno + i)) {
8736716Smckusick 				printf("dev = 0x%x, block = %d, fs = %s\n",
8746716Smckusick 				    ip->i_dev, bno + i, fs->fs_fsmnt);
8754426Smckusic 				panic("free: freeing free frag");
8766716Smckusick 			}
8774426Smckusic 			setbit(cgp->cg_free, bno + i);
8784426Smckusic 		}
8796294Smckusick 		cgp->cg_cs.cs_nffree += i;
8806294Smckusick 		fs->fs_cstotal.cs_nffree += i;
8816294Smckusick 		fs->fs_cs(fs, cg).cs_nffree += i;
8824463Smckusic 		/*
8834463Smckusic 		 * add back in counts associated with the new frags
8844463Smckusic 		 */
8856294Smckusick 		blk = blkmap(fs, cgp->cg_free, bbase);
8865322Smckusic 		fragacct(fs, blk, cgp->cg_frsum, 1);
8874463Smckusic 		/*
8884463Smckusic 		 * if a complete block has been reassembled, account for it
8894463Smckusic 		 */
89011638Ssam 		if (isblock(fs, cgp->cg_free, fragstoblks(fs, bbase))) {
8915322Smckusic 			cgp->cg_cs.cs_nffree -= fs->fs_frag;
8925322Smckusic 			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
8935322Smckusic 			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
8944792Smckusic 			cgp->cg_cs.cs_nbfree++;
8954792Smckusic 			fs->fs_cstotal.cs_nbfree++;
8965322Smckusic 			fs->fs_cs(fs, cg).cs_nbfree++;
8975375Smckusic 			i = cbtocylno(fs, bbase);
8985375Smckusic 			cgp->cg_b[i][cbtorpos(fs, bbase)]++;
8995375Smckusic 			cgp->cg_btot[i]++;
9004426Smckusic 		}
9014426Smckusic 	}
9024359Smckusick 	fs->fs_fmod++;
9034359Smckusick 	bdwrite(bp);
9044359Smckusick }
9054359Smckusick 
9065375Smckusic /*
9075375Smckusic  * Free an inode.
9085375Smckusic  *
9095375Smckusic  * The specified inode is placed back in the free map.
9105375Smckusic  */
9115965Smckusic ifree(ip, ino, mode)
9125965Smckusic 	struct inode *ip;
9134359Smckusick 	ino_t ino;
9144359Smckusick 	int mode;
9154359Smckusick {
9164359Smckusick 	register struct fs *fs;
9174359Smckusick 	register struct cg *cgp;
9184359Smckusick 	register struct buf *bp;
9194359Smckusick 	int cg;
9204359Smckusick 
9215965Smckusic 	fs = ip->i_fs;
9226716Smckusick 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
9236716Smckusick 		printf("dev = 0x%x, ino = %d, fs = %s\n",
9246716Smckusick 		    ip->i_dev, ino, fs->fs_fsmnt);
9254359Smckusick 		panic("ifree: range");
9266716Smckusick 	}
9275377Smckusic 	cg = itog(fs, ino);
92810278Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
9296531Smckusick 	cgp = bp->b_un.b_cg;
9306531Smckusick 	if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) {
9315960Smckusic 		brelse(bp);
9324359Smckusick 		return;
9335960Smckusic 	}
9348105Sroot 	cgp->cg_time = time.tv_sec;
9354359Smckusick 	ino %= fs->fs_ipg;
9366716Smckusick 	if (isclr(cgp->cg_iused, ino)) {
9376716Smckusick 		printf("dev = 0x%x, ino = %d, fs = %s\n",
9386716Smckusick 		    ip->i_dev, ino, fs->fs_fsmnt);
9394359Smckusick 		panic("ifree: freeing free inode");
9406716Smckusick 	}
9414359Smckusick 	clrbit(cgp->cg_iused, ino);
94216784Smckusick 	if (ino < cgp->cg_irotor)
94316784Smckusick 		cgp->cg_irotor = ino;
9444792Smckusic 	cgp->cg_cs.cs_nifree++;
9454792Smckusic 	fs->fs_cstotal.cs_nifree++;
9465322Smckusic 	fs->fs_cs(fs, cg).cs_nifree++;
9474359Smckusick 	if ((mode & IFMT) == IFDIR) {
9484792Smckusic 		cgp->cg_cs.cs_ndir--;
9494792Smckusic 		fs->fs_cstotal.cs_ndir--;
9505322Smckusic 		fs->fs_cs(fs, cg).cs_ndir--;
9514359Smckusick 	}
9524359Smckusick 	fs->fs_fmod++;
9534359Smckusick 	bdwrite(bp);
9544359Smckusick }
9554359Smckusick 
9564463Smckusic /*
9575375Smckusic  * Find a block of the specified size in the specified cylinder group.
9585375Smckusic  *
9594651Smckusic  * It is a panic if a request is made to find a block if none are
9604651Smckusic  * available.
9614651Smckusic  */
9624651Smckusic daddr_t
9634651Smckusic mapsearch(fs, cgp, bpref, allocsiz)
9644651Smckusic 	register struct fs *fs;
9654651Smckusic 	register struct cg *cgp;
9664651Smckusic 	daddr_t bpref;
9674651Smckusic 	int allocsiz;
9684651Smckusic {
9694651Smckusic 	daddr_t bno;
9704651Smckusic 	int start, len, loc, i;
9714651Smckusic 	int blk, field, subfield, pos;
9724651Smckusic 
9734651Smckusic 	/*
9744651Smckusic 	 * find the fragment by searching through the free block
9754651Smckusic 	 * map for an appropriate bit pattern
9764651Smckusic 	 */
9774651Smckusic 	if (bpref)
9785377Smckusic 		start = dtogd(fs, bpref) / NBBY;
9794651Smckusic 	else
9804651Smckusic 		start = cgp->cg_frotor / NBBY;
9815398Smckusic 	len = howmany(fs->fs_fpg, NBBY) - start;
98212755Ssam 	loc = scanc((unsigned)len, (caddr_t)&cgp->cg_free[start],
98312755Ssam 		(caddr_t)fragtbl[fs->fs_frag],
98412755Ssam 		(int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
9854651Smckusic 	if (loc == 0) {
9866531Smckusick 		len = start + 1;
9876531Smckusick 		start = 0;
98817697Smckusick 		loc = scanc((unsigned)len, (caddr_t)&cgp->cg_free[0],
98912755Ssam 			(caddr_t)fragtbl[fs->fs_frag],
99012755Ssam 			(int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
99116784Smckusick 		if (loc == 0) {
99216784Smckusick 			printf("start = %d, len = %d, fs = %s\n",
99316784Smckusick 			    start, len, fs->fs_fsmnt);
99416784Smckusick 			panic("alloccg: map corrupted");
99517697Smckusick 			/* NOTREACHED */
99616784Smckusick 		}
9974651Smckusic 	}
9984651Smckusic 	bno = (start + len - loc) * NBBY;
9994651Smckusic 	cgp->cg_frotor = bno;
10004651Smckusic 	/*
10014651Smckusic 	 * found the byte in the map
10024651Smckusic 	 * sift through the bits to find the selected frag
10034651Smckusic 	 */
10046294Smckusick 	for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
10056294Smckusick 		blk = blkmap(fs, cgp->cg_free, bno);
10064651Smckusic 		blk <<= 1;
10074651Smckusic 		field = around[allocsiz];
10084651Smckusic 		subfield = inside[allocsiz];
10095322Smckusic 		for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
10106294Smckusick 			if ((blk & field) == subfield)
10116294Smckusick 				return (bno + pos);
10124651Smckusic 			field <<= 1;
10134651Smckusic 			subfield <<= 1;
10144651Smckusic 		}
10154651Smckusic 	}
10166716Smckusick 	printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt);
10174651Smckusic 	panic("alloccg: block not in map");
10186531Smckusick 	return (-1);
10194651Smckusic }
10204651Smckusic 
10214651Smckusic /*
10225375Smckusic  * Fserr prints the name of a file system with an error diagnostic.
10235375Smckusic  *
10245375Smckusic  * The form of the error message is:
10254359Smckusick  *	fs: error message
10264359Smckusick  */
10274359Smckusick fserr(fs, cp)
10284359Smckusick 	struct fs *fs;
10294359Smckusick 	char *cp;
10304359Smckusick {
10314359Smckusick 
103224839Seric 	log(LOG_ERR, "%s: %s\n", fs->fs_fsmnt, cp);
10334359Smckusick }
1034