xref: /csrg-svn/sys/ufs/lfs/lfs_alloc.c (revision 5212)
14359Smckusick /* Copyright (c) 1981 Regents of the University of California */
24359Smckusick 
3*5212Smckusic static char vers[] = "@(#)lfs_alloc.c 1.10 12/09/81";
44359Smckusick 
54359Smckusick /*	alloc.c	4.8	81/03/08	*/
64359Smckusick 
74359Smckusick #include "../h/param.h"
84359Smckusick #include "../h/systm.h"
94359Smckusick #include "../h/mount.h"
104359Smckusick #include "../h/fs.h"
114359Smckusick #include "../h/conf.h"
124359Smckusick #include "../h/buf.h"
134359Smckusick #include "../h/inode.h"
144359Smckusick #include "../h/dir.h"
154359Smckusick #include "../h/user.h"
164359Smckusick 
17*5212Smckusic extern u_long		hashalloc();
18*5212Smckusic extern ino_t		ialloccg();
194651Smckusic extern daddr_t		alloccg();
204651Smckusic extern daddr_t		alloccgblk();
214651Smckusic extern daddr_t		fragextend();
224651Smckusic extern daddr_t		blkpref();
234651Smckusic extern daddr_t		mapsearch();
244607Smckusic extern int		inside[], around[];
254607Smckusic extern unsigned char	fragtbl[];
264359Smckusick 
274359Smckusick struct buf *
284359Smckusick alloc(dev, ip, bpref, size)
294359Smckusick 	dev_t dev;
304463Smckusic 	register struct inode *ip;
314359Smckusick 	daddr_t bpref;
324359Smckusick 	int size;
334359Smckusick {
344359Smckusick 	daddr_t bno;
354359Smckusick 	register struct fs *fs;
364463Smckusic 	register struct buf *bp;
374359Smckusick 	int cg;
384359Smckusick 
394463Smckusic 	if ((unsigned)size > BSIZE || size % FSIZE != 0)
404463Smckusic 		panic("alloc: bad size");
414359Smckusick 	fs = getfs(dev);
424792Smckusic 	if (size == BSIZE && fs->fs_cstotal.cs_nbfree == 0)
434359Smckusick 		goto nospace;
444792Smckusic 	if (u.u_uid != 0 &&
454792Smckusic 	    fs->fs_cstotal.cs_nbfree * FRAG + fs->fs_cstotal.cs_nffree <
464792Smckusic 	      fs->fs_dsize * minfree / 100)
474792Smckusic 		goto nospace;
484948Smckusic 	if (bpref >= fs->fs_size)
494948Smckusic 		bpref = 0;
504359Smckusick 	if (bpref == 0)
514359Smckusick 		cg = itog(ip->i_number, fs);
524359Smckusick 	else
534359Smckusick 		cg = dtog(bpref, fs);
54*5212Smckusic 	bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, size, alloccg);
554359Smckusick 	if (bno == 0)
564359Smckusick 		goto nospace;
574426Smckusic 	bp = getblk(dev, bno, size);
584359Smckusick 	clrbuf(bp);
594359Smckusick 	return (bp);
604359Smckusick nospace:
614359Smckusick 	fserr(fs, "file system full");
624359Smckusick 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
634359Smckusick 	u.u_error = ENOSPC;
644359Smckusick 	return (NULL);
654359Smckusick }
664359Smckusick 
674426Smckusic struct buf *
68*5212Smckusic realloccg(dev, bprev, bpref, osize, nsize)
694426Smckusic 	dev_t dev;
704651Smckusic 	daddr_t bprev, bpref;
714426Smckusic 	int osize, nsize;
724426Smckusic {
734426Smckusic 	daddr_t bno;
744426Smckusic 	register struct fs *fs;
754463Smckusic 	register struct buf *bp, *obp;
764463Smckusic 	caddr_t cp;
774426Smckusic 	int cg;
784426Smckusic 
794463Smckusic 	if ((unsigned)osize > BSIZE || osize % FSIZE != 0 ||
804463Smckusic 	    (unsigned)nsize > BSIZE || nsize % FSIZE != 0)
814463Smckusic 		panic("realloccg: bad size");
824426Smckusic 	fs = getfs(dev);
834792Smckusic 	if (u.u_uid != 0 &&
844792Smckusic 	    fs->fs_cstotal.cs_nbfree * FRAG + fs->fs_cstotal.cs_nffree <
854792Smckusic 	      fs->fs_dsize * minfree / 100)
864792Smckusic 		goto nospace;
874463Smckusic 	if (bprev == 0)
884463Smckusic 		panic("realloccg: bad bprev");
894426Smckusic 	else
904463Smckusic 		cg = dtog(bprev, fs);
914463Smckusic 	bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize);
924463Smckusic 	if (bno != 0) {
934463Smckusic 		bp = bread(dev, bno, osize);
944463Smckusic 		bp->b_bcount = nsize;
954463Smckusic 		blkclr(bp->b_un.b_addr + osize, nsize - osize);
964463Smckusic 		return (bp);
974463Smckusic 	}
984948Smckusic 	if (bpref >= fs->fs_size)
994948Smckusic 		bpref = 0;
100*5212Smckusic 	bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg);
1014463Smckusic 	if (bno != 0) {
1024463Smckusic 		/*
1034463Smckusic 		 * make a new copy
1044463Smckusic 		 */
1054463Smckusic 		obp = bread(dev, bprev, osize);
1064463Smckusic 		bp = getblk(dev, bno, nsize);
1074463Smckusic 		cp = bp->b_un.b_addr;
1084463Smckusic 		bp->b_un.b_addr = obp->b_un.b_addr;
1094463Smckusic 		obp->b_un.b_addr = cp;
1104463Smckusic 		obp->b_flags |= B_INVAL;
1114463Smckusic 		brelse(obp);
112*5212Smckusic 		fre(dev, bprev, (off_t)osize);
1134463Smckusic 		blkclr(bp->b_un.b_addr + osize, nsize - osize);
1144463Smckusic 		return(bp);
1154463Smckusic 	}
1164792Smckusic nospace:
1174463Smckusic 	/*
1184463Smckusic 	 * no space available
1194463Smckusic 	 */
1204426Smckusic 	fserr(fs, "file system full");
1214426Smckusic 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
1224426Smckusic 	u.u_error = ENOSPC;
1234426Smckusic 	return (NULL);
1244426Smckusic }
1254426Smckusic 
1264359Smckusick struct inode *
1274359Smckusick ialloc(dev, ipref, mode)
1284359Smckusick 	dev_t dev;
1294359Smckusick 	ino_t ipref;
1304359Smckusick 	int mode;
1314359Smckusick {
132*5212Smckusic 	ino_t ino;
1334359Smckusick 	register struct fs *fs;
1344359Smckusick 	register struct inode *ip;
1354359Smckusick 	int cg;
1364359Smckusick 
1374359Smckusick 	fs = getfs(dev);
1384792Smckusic 	if (fs->fs_cstotal.cs_nifree == 0)
1394359Smckusick 		goto noinodes;
1404948Smckusic 	if (ipref >= fs->fs_ncg * fs->fs_ipg)
1414948Smckusic 		ipref = 0;
1424359Smckusick 	cg = itog(ipref, fs);
143*5212Smckusic 	ino = (ino_t)hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg);
1444359Smckusick 	if (ino == 0)
1454359Smckusick 		goto noinodes;
1464359Smckusick 	ip = iget(dev, ino);
1474359Smckusick 	if (ip == NULL) {
148*5212Smckusic 		ifree(dev, ino, 0);
1494359Smckusick 		return (NULL);
1504359Smckusick 	}
1514359Smckusick 	if (ip->i_mode)
1524359Smckusick 		panic("ialloc: dup alloc");
1534359Smckusick 	return (ip);
1544359Smckusick noinodes:
1554359Smckusick 	fserr(fs, "out of inodes");
1564359Smckusick 	uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt);
1574359Smckusick 	u.u_error = ENOSPC;
1584359Smckusick 	return (NULL);
1594359Smckusick }
1604359Smckusick 
1614651Smckusic /*
1624651Smckusic  * find a cylinder to place a directory
1634651Smckusic  */
1644651Smckusic dirpref(dev)
1654359Smckusick 	dev_t dev;
1664359Smckusick {
1674359Smckusick 	register struct fs *fs;
1684651Smckusic 	int cg, minndir, mincg, avgifree;
1694359Smckusick 
1704359Smckusick 	fs = getfs(dev);
1714792Smckusic 	avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
1724651Smckusic 	minndir = fs->fs_ipg;
1734359Smckusick 	mincg = 0;
1744651Smckusic 	for (cg = 0; cg < fs->fs_ncg; cg++)
1754651Smckusic 		if (fs->fs_cs(cg).cs_ndir < minndir &&
1764651Smckusic 		    fs->fs_cs(cg).cs_nifree >= avgifree) {
1774359Smckusick 			mincg = cg;
1784651Smckusic 			minndir = fs->fs_cs(cg).cs_ndir;
1794359Smckusick 		}
1804359Smckusick 	return (fs->fs_ipg * mincg);
1814359Smckusick }
1824359Smckusick 
1834651Smckusic /*
1844651Smckusic  * select a cylinder to place a large block of data
1854651Smckusic  */
186*5212Smckusic daddr_t
1874651Smckusic blkpref(dev)
1884651Smckusic 	dev_t dev;
1894651Smckusic {
1904651Smckusic 	register struct fs *fs;
1914651Smckusic 	int cg, avgbfree;
1924651Smckusic 
1934651Smckusic 	fs = getfs(dev);
1944792Smckusic 	avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
1954651Smckusic 	for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++)
1964651Smckusic 		if (fs->fs_cs(cg).cs_nbfree >= avgbfree) {
1974651Smckusic 			fs->fs_cgrotor = cg;
1984651Smckusic 			return (fs->fs_fpg * cg + FRAG);
1994651Smckusic 		}
2004651Smckusic 	for (cg = 0; cg <= fs->fs_cgrotor; cg++)
2014651Smckusic 		if (fs->fs_cs(cg).cs_nbfree >= avgbfree) {
2024651Smckusic 			fs->fs_cgrotor = cg;
2034651Smckusic 			return (fs->fs_fpg * cg + FRAG);
2044651Smckusic 		}
2054651Smckusic 	return (0);
2064651Smckusic }
2074651Smckusic 
208*5212Smckusic /*VARARGS5*/
209*5212Smckusic u_long
2104359Smckusick hashalloc(dev, fs, cg, pref, size, allocator)
2114359Smckusick 	dev_t dev;
2124359Smckusick 	register struct fs *fs;
2134359Smckusick 	int cg;
2144359Smckusick 	long pref;
2154359Smckusick 	int size;	/* size for data blocks, mode for inodes */
216*5212Smckusic 	u_long (*allocator)();
2174359Smckusick {
2184359Smckusick 	long result;
2194359Smckusick 	int i, icg = cg;
2204359Smckusick 
2214359Smckusick 	/*
2224359Smckusick 	 * 1: preferred cylinder group
2234359Smckusick 	 */
2244359Smckusick 	result = (*allocator)(dev, fs, cg, pref, size);
2254359Smckusick 	if (result)
2264359Smckusick 		return (result);
2274359Smckusick 	/*
2284359Smckusick 	 * 2: quadratic rehash
2294359Smckusick 	 */
2304359Smckusick 	for (i = 1; i < fs->fs_ncg; i *= 2) {
2314359Smckusick 		cg += i;
2324359Smckusick 		if (cg >= fs->fs_ncg)
2334359Smckusick 			cg -= fs->fs_ncg;
2344359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
2354359Smckusick 		if (result)
2364359Smckusick 			return (result);
2374359Smckusick 	}
2384359Smckusick 	/*
2394359Smckusick 	 * 3: brute force search
2404359Smckusick 	 */
2414359Smckusick 	cg = icg;
2424359Smckusick 	for (i = 0; i < fs->fs_ncg; i++) {
2434359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
2444359Smckusick 		if (result)
2454359Smckusick 			return (result);
2464359Smckusick 		cg++;
2474359Smckusick 		if (cg == fs->fs_ncg)
2484359Smckusick 			cg = 0;
2494359Smckusick 	}
2504359Smckusick 	return (0);
2514359Smckusick }
2524359Smckusick 
2534359Smckusick daddr_t
2544463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize)
2554426Smckusic 	dev_t dev;
2564426Smckusic 	register struct fs *fs;
2574426Smckusic 	int cg;
2584463Smckusic 	long bprev;
2594426Smckusic 	int osize, nsize;
2604426Smckusic {
2614463Smckusic 	register struct buf *bp;
2624463Smckusic 	register struct cg *cgp;
2634463Smckusic 	long bno;
2644463Smckusic 	int frags, bbase;
2654426Smckusic 	int i;
2664426Smckusic 
2674463Smckusic 	frags = nsize / FSIZE;
2684463Smckusic 	bbase = bprev % FRAG;
2694463Smckusic 	if (bbase > (bprev + frags - 1) % FRAG) {
2704463Smckusic 		/* cannot extend across a block boundry */
2714463Smckusic 		return (0);
2724463Smckusic 	}
2734426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
2744426Smckusic 	if (bp->b_flags & B_ERROR)
2754426Smckusic 		return (0);
2764426Smckusic 	cgp = bp->b_un.b_cg;
2774463Smckusic 	bno = bprev % fs->fs_fpg;
2784463Smckusic 	for (i = osize / FSIZE; i < frags; i++) {
2794463Smckusic 		if (isclr(cgp->cg_free, bno + i))
2804463Smckusic 			break;
2814463Smckusic 	}
2824463Smckusic 	if (i == frags) {
2834463Smckusic 		/*
2844463Smckusic 		 * the current fragment can be extended
2854463Smckusic 		 * deduct the count on fragment being extended into
2864463Smckusic 		 * increase the count on the remaining fragment (if any)
2874463Smckusic 		 * allocate the extended piece
2884463Smckusic 		 */
2894463Smckusic 		for (i = frags; i < FRAG - bbase; i++)
2904463Smckusic 			if (isclr(cgp->cg_free, bno + i))
2914426Smckusic 				break;
2924463Smckusic 		cgp->cg_frsum[i - osize / FSIZE]--;
2934463Smckusic 		if (i != frags)
2944463Smckusic 			cgp->cg_frsum[i - frags]++;
2954463Smckusic 		for (i = osize / FSIZE; i < frags; i++) {
2964463Smckusic 			clrbit(cgp->cg_free, bno + i);
2974792Smckusic 			cgp->cg_cs.cs_nffree--;
2984792Smckusic 			fs->fs_cstotal.cs_nffree--;
2994792Smckusic 			fs->fs_cs(cg).cs_nffree--;
3004426Smckusic 		}
3014463Smckusic 		fs->fs_fmod++;
3024463Smckusic 		bdwrite(bp);
3034463Smckusic 		return (bprev);
3044426Smckusic 	}
3054426Smckusic 	brelse(bp);
3064426Smckusic 	return (0);
3074426Smckusic }
3084426Smckusic 
3094426Smckusic daddr_t
3104359Smckusick alloccg(dev, fs, cg, bpref, size)
3114359Smckusick 	dev_t dev;
3124463Smckusic 	register struct fs *fs;
3134359Smckusick 	int cg;
3144359Smckusick 	daddr_t bpref;
3154359Smckusick 	int size;
3164359Smckusick {
3174463Smckusic 	register struct buf *bp;
3184463Smckusic 	register struct cg *cgp;
3194463Smckusic 	int bno, frags;
3204463Smckusic 	int allocsiz;
3214463Smckusic 	register int i;
3224359Smckusick 
3234792Smckusic 	if (fs->fs_cs(cg).cs_nbfree == 0 && size == BSIZE)
3244792Smckusic 		return (0);
3254426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
3264359Smckusick 	if (bp->b_flags & B_ERROR)
3274359Smckusick 		return (0);
3284359Smckusick 	cgp = bp->b_un.b_cg;
3294463Smckusic 	if (size == BSIZE) {
330*5212Smckusic 		bno = alloccgblk(fs, cgp, bpref);
3314463Smckusic 		bdwrite(bp);
3324463Smckusic 		return (bno);
3334463Smckusic 	}
3344463Smckusic 	/*
3354463Smckusic 	 * check to see if any fragments are already available
3364463Smckusic 	 * allocsiz is the size which will be allocated, hacking
3374463Smckusic 	 * it down to a smaller size if necessary
3384463Smckusic 	 */
3394463Smckusic 	frags = size / FSIZE;
3404463Smckusic 	for (allocsiz = frags; allocsiz < FRAG; allocsiz++)
3414463Smckusic 		if (cgp->cg_frsum[allocsiz] != 0)
3424463Smckusic 			break;
3434463Smckusic 	if (allocsiz == FRAG) {
3444463Smckusic 		/*
3454463Smckusic 		 * no fragments were available, so a block will be
3464463Smckusic 		 * allocated, and hacked up
3474463Smckusic 		 */
3484792Smckusic 		if (cgp->cg_cs.cs_nbfree == 0) {
3494463Smckusic 			brelse(bp);
3504463Smckusic 			return (0);
3514463Smckusic 		}
352*5212Smckusic 		bno = alloccgblk(fs, cgp, bpref);
3534463Smckusic 		bpref = bno % fs->fs_fpg;
3544463Smckusic 		for (i = frags; i < FRAG; i++)
3554463Smckusic 			setbit(cgp->cg_free, bpref + i);
3564463Smckusic 		i = FRAG - frags;
3574792Smckusic 		cgp->cg_cs.cs_nffree += i;
3584792Smckusic 		fs->fs_cstotal.cs_nffree += i;
3594792Smckusic 		fs->fs_cs(cg).cs_nffree += i;
3604463Smckusic 		cgp->cg_frsum[i]++;
3614463Smckusic 		bdwrite(bp);
3624463Smckusic 		return (bno);
3634463Smckusic 	}
3644651Smckusic 	bno = mapsearch(fs, cgp, bpref, allocsiz);
3654651Smckusic 	if (bno == 0)
3664651Smckusic 		return (0);
3674463Smckusic 	for (i = 0; i < frags; i++)
3684463Smckusic 		clrbit(cgp->cg_free, bno + i);
3694792Smckusic 	cgp->cg_cs.cs_nffree -= frags;
3704792Smckusic 	fs->fs_cstotal.cs_nffree -= frags;
3714792Smckusic 	fs->fs_cs(cg).cs_nffree -= frags;
3724463Smckusic 	cgp->cg_frsum[allocsiz]--;
3734463Smckusic 	if (frags != allocsiz)
3744463Smckusic 		cgp->cg_frsum[allocsiz - frags]++;
3754463Smckusic 	bdwrite(bp);
3764463Smckusic 	return (cg * fs->fs_fpg + bno);
3774463Smckusic }
3784463Smckusic 
3794463Smckusic daddr_t
380*5212Smckusic alloccgblk(fs, cgp, bpref)
3814463Smckusic 	struct fs *fs;
3824463Smckusic 	register struct cg *cgp;
3834463Smckusic 	daddr_t bpref;
3844463Smckusic {
3854651Smckusic 	daddr_t bno;
3864651Smckusic 	int cylno, pos;
3874651Smckusic 	short *cylbp;
3884651Smckusic 	int i, j;
3894463Smckusic 
3904651Smckusic 	if (bpref == 0) {
3914651Smckusic 		bpref = cgp->cg_rotor;
3924651Smckusic 	} else {
3934463Smckusic 		bpref &= ~(FRAG - 1);
3944359Smckusick 		bpref %= fs->fs_fpg;
3954651Smckusic 		/*
3964651Smckusic 		 * if the requested block is available, use it
3974651Smckusic 		 */
3984359Smckusick 		if (isblock(cgp->cg_free, bpref/FRAG)) {
3994651Smckusic 			bno = bpref;
4004359Smckusick 			goto gotit;
4014359Smckusick 		}
4024651Smckusic 		/*
4034651Smckusic 		 * check for a block available on the same cylinder
4044651Smckusic 		 * beginning with one which is rotationally optimal
4054651Smckusic 		 */
4064651Smckusic 		i = bpref * NSPF;
4074651Smckusic 		cylno = i / fs->fs_spc;
4084651Smckusic 		cylbp = cgp->cg_b[cylno];
4094651Smckusic 		pos = (i + (ROTDELAY == 0) ?
4104651Smckusic 			0 : 1 + ROTDELAY * HZ * fs->fs_nsect / (NSPF * 1000)) %
4114651Smckusic 			fs->fs_nsect * NRPOS / fs->fs_nsect;
4124651Smckusic 		for (i = pos; i < NRPOS; i++)
4134651Smckusic 			if (cylbp[i] > 0)
4144651Smckusic 				break;
4154651Smckusic 		if (i == NRPOS)
4164651Smckusic 			for (i = 0; i < pos; i++)
4174651Smckusic 				if (cylbp[i] > 0)
4184651Smckusic 					break;
4194651Smckusic 		if (cylbp[i] > 0) {
4204651Smckusic 			bpref = cylno * fs->fs_spc / (NSPF * FRAG);
4214651Smckusic 			for (j = fs->fs_postbl[i]; j > -1; j = fs->fs_rotbl[j]) {
4224651Smckusic 				if (isblock(cgp->cg_free, bpref + j)) {
4234651Smckusic 					bno = (bpref + j) * FRAG;
4244651Smckusic 					goto gotit;
4254651Smckusic 				}
4264651Smckusic 			}
4274651Smckusic 			panic("alloccgblk: can't find blk in cyl");
4284651Smckusic 		}
4294359Smckusick 	}
4304651Smckusic 	bno = mapsearch(fs, cgp, bpref, FRAG);
4314651Smckusic 	if (bno == 0)
4324651Smckusic 		return (0);
4334651Smckusic 	cgp->cg_rotor = bno;
4344359Smckusick gotit:
4354651Smckusic 	clrblock(cgp->cg_free, bno/FRAG);
4364792Smckusic 	cgp->cg_cs.cs_nbfree--;
4374792Smckusic 	fs->fs_cstotal.cs_nbfree--;
4384651Smckusic 	fs->fs_cs(cgp->cg_cgx).cs_nbfree--;
4394651Smckusic 	i = bno * NSPF;
4404463Smckusic 	cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--;
4414359Smckusick 	fs->fs_fmod++;
4424651Smckusic 	return (cgp->cg_cgx * fs->fs_fpg + bno);
4434359Smckusick }
4444359Smckusick 
445*5212Smckusic ino_t
4464359Smckusick ialloccg(dev, fs, cg, ipref, mode)
4474359Smckusick 	dev_t dev;
4484463Smckusic 	register struct fs *fs;
4494359Smckusick 	int cg;
4504359Smckusick 	daddr_t ipref;
4514359Smckusick 	int mode;
4524359Smckusick {
4534463Smckusic 	register struct buf *bp;
4544463Smckusic 	register struct cg *cgp;
4554359Smckusick 	int i;
4564359Smckusick 
4574792Smckusic 	if (fs->fs_cs(cg).cs_nifree == 0)
4584792Smckusic 		return (0);
4594426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
4604359Smckusick 	if (bp->b_flags & B_ERROR)
4614359Smckusick 		return (0);
4624359Smckusick 	cgp = bp->b_un.b_cg;
4634359Smckusick 	if (ipref) {
4644359Smckusick 		ipref %= fs->fs_ipg;
4654359Smckusick 		if (isclr(cgp->cg_iused, ipref))
4664359Smckusick 			goto gotit;
4674359Smckusick 	} else
4684359Smckusick 		ipref = cgp->cg_irotor;
4694359Smckusick 	for (i = 0; i < fs->fs_ipg; i++) {
4704359Smckusick 		ipref++;
4714359Smckusick 		if (ipref >= fs->fs_ipg)
4724359Smckusick 			ipref = 0;
4734359Smckusick 		if (isclr(cgp->cg_iused, ipref)) {
4744359Smckusick 			cgp->cg_irotor = ipref;
4754359Smckusick 			goto gotit;
4764359Smckusick 		}
4774359Smckusick 	}
4784359Smckusick 	brelse(bp);
4794359Smckusick 	return (0);
4804359Smckusick gotit:
4814359Smckusick 	setbit(cgp->cg_iused, ipref);
4824792Smckusic 	cgp->cg_cs.cs_nifree--;
4834792Smckusic 	fs->fs_cstotal.cs_nifree--;
4844651Smckusic 	fs->fs_cs(cg).cs_nifree--;
4854359Smckusick 	fs->fs_fmod++;
4864359Smckusick 	if ((mode & IFMT) == IFDIR) {
4874792Smckusic 		cgp->cg_cs.cs_ndir++;
4884792Smckusic 		fs->fs_cstotal.cs_ndir++;
4894651Smckusic 		fs->fs_cs(cg).cs_ndir++;
4904359Smckusick 	}
4914359Smckusick 	bdwrite(bp);
4924359Smckusick 	return (cg * fs->fs_ipg + ipref);
4934359Smckusick }
4944359Smckusick 
4954359Smckusick fre(dev, bno, size)
4964359Smckusick 	dev_t dev;
4974359Smckusick 	daddr_t bno;
498*5212Smckusic 	off_t size;
4994359Smckusick {
5004359Smckusick 	register struct fs *fs;
5014359Smckusick 	register struct cg *cgp;
5024359Smckusick 	register struct buf *bp;
5034463Smckusic 	int cg, blk, frags, bbase;
5044463Smckusic 	register int i;
5054359Smckusick 
5064426Smckusic 	if ((unsigned)size > BSIZE || size % FSIZE != 0)
5074426Smckusic 		panic("free: bad size");
5084359Smckusick 	fs = getfs(dev);
5094359Smckusick 	cg = dtog(bno, fs);
5104359Smckusick 	if (badblock(fs, bno))
5114359Smckusick 		return;
5124426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
5134359Smckusick 	if (bp->b_flags & B_ERROR)
5144359Smckusick 		return;
5154359Smckusick 	cgp = bp->b_un.b_cg;
5164359Smckusick 	bno %= fs->fs_fpg;
5174426Smckusic 	if (size == BSIZE) {
5184426Smckusic 		if (isblock(cgp->cg_free, bno/FRAG))
5194426Smckusic 			panic("free: freeing free block");
5204426Smckusic 		setblock(cgp->cg_free, bno/FRAG);
5214792Smckusic 		cgp->cg_cs.cs_nbfree++;
5224792Smckusic 		fs->fs_cstotal.cs_nbfree++;
5234651Smckusic 		fs->fs_cs(cg).cs_nbfree++;
5244426Smckusic 		i = bno * NSPF;
5254426Smckusic 		cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++;
5264426Smckusic 	} else {
5274463Smckusic 		bbase = bno - (bno % FRAG);
5284463Smckusic 		/*
5294463Smckusic 		 * decrement the counts associated with the old frags
5304463Smckusic 		 */
5314463Smckusic 		blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) &
5324463Smckusic 		       (0xff >> (NBBY - FRAG)));
5334463Smckusic 		fragacct(blk, cgp->cg_frsum, -1);
5344463Smckusic 		/*
5354463Smckusic 		 * deallocate the fragment
5364463Smckusic 		 */
5374463Smckusic 		frags = size / FSIZE;
5384463Smckusic 		for (i = 0; i < frags; i++) {
5394426Smckusic 			if (isset(cgp->cg_free, bno + i))
5404426Smckusic 				panic("free: freeing free frag");
5414426Smckusic 			setbit(cgp->cg_free, bno + i);
5424792Smckusic 			cgp->cg_cs.cs_nffree++;
5434792Smckusic 			fs->fs_cstotal.cs_nffree++;
5444792Smckusic 			fs->fs_cs(cg).cs_nffree++;
5454426Smckusic 		}
5464463Smckusic 		/*
5474463Smckusic 		 * add back in counts associated with the new frags
5484463Smckusic 		 */
5494463Smckusic 		blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) &
5504463Smckusic 		       (0xff >> (NBBY - FRAG)));
5514463Smckusic 		fragacct(blk, cgp->cg_frsum, 1);
5524463Smckusic 		/*
5534463Smckusic 		 * if a complete block has been reassembled, account for it
5544463Smckusic 		 */
5554463Smckusic 		if (isblock(cgp->cg_free, bbase / FRAG)) {
5564792Smckusic 			cgp->cg_cs.cs_nffree -= FRAG;
5574792Smckusic 			fs->fs_cstotal.cs_nffree -= FRAG;
5584792Smckusic 			fs->fs_cs(cg).cs_nffree -= FRAG;
5594792Smckusic 			cgp->cg_cs.cs_nbfree++;
5604792Smckusic 			fs->fs_cstotal.cs_nbfree++;
5614651Smckusic 			fs->fs_cs(cg).cs_nbfree++;
5624463Smckusic 			i = bbase * NSPF;
5634426Smckusic 			cgp->cg_b[i / fs->fs_spc]
5644426Smckusic 				 [i % fs->fs_nsect * NRPOS / fs->fs_nsect]++;
5654426Smckusic 		}
5664426Smckusic 	}
5674359Smckusick 	fs->fs_fmod++;
5684359Smckusick 	bdwrite(bp);
5694359Smckusick }
5704359Smckusick 
5714359Smckusick ifree(dev, ino, mode)
5724359Smckusick 	dev_t dev;
5734359Smckusick 	ino_t ino;
5744359Smckusick 	int mode;
5754359Smckusick {
5764359Smckusick 	register struct fs *fs;
5774359Smckusick 	register struct cg *cgp;
5784359Smckusick 	register struct buf *bp;
5794359Smckusick 	int cg;
5804359Smckusick 
5814359Smckusick 	fs = getfs(dev);
5824359Smckusick 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
5834359Smckusick 		panic("ifree: range");
5844359Smckusick 	cg = itog(ino, fs);
5854426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
5864359Smckusick 	if (bp->b_flags & B_ERROR)
5874359Smckusick 		return;
5884359Smckusick 	cgp = bp->b_un.b_cg;
5894359Smckusick 	ino %= fs->fs_ipg;
5904359Smckusick 	if (isclr(cgp->cg_iused, ino))
5914359Smckusick 		panic("ifree: freeing free inode");
5924359Smckusick 	clrbit(cgp->cg_iused, ino);
5934792Smckusic 	cgp->cg_cs.cs_nifree++;
5944792Smckusic 	fs->fs_cstotal.cs_nifree++;
5954651Smckusic 	fs->fs_cs(cg).cs_nifree++;
5964359Smckusick 	if ((mode & IFMT) == IFDIR) {
5974792Smckusic 		cgp->cg_cs.cs_ndir--;
5984792Smckusic 		fs->fs_cstotal.cs_ndir--;
5994651Smckusic 		fs->fs_cs(cg).cs_ndir--;
6004359Smckusick 	}
6014359Smckusick 	fs->fs_fmod++;
6024359Smckusick 	bdwrite(bp);
6034359Smckusick }
6044359Smckusick 
6054463Smckusic /*
6064651Smckusic  * find a block of the specified size in the specified cylinder group
6074651Smckusic  * It is a panic if a request is made to find a block if none are
6084651Smckusic  * available.
6094651Smckusic  */
6104651Smckusic daddr_t
6114651Smckusic mapsearch(fs, cgp, bpref, allocsiz)
6124651Smckusic 	register struct fs *fs;
6134651Smckusic 	register struct cg *cgp;
6144651Smckusic 	daddr_t bpref;
6154651Smckusic 	int allocsiz;
6164651Smckusic {
6174651Smckusic 	daddr_t bno;
6184651Smckusic 	int start, len, loc, i;
6194651Smckusic 	int blk, field, subfield, pos;
6204651Smckusic 
6214651Smckusic 	/*
6224651Smckusic 	 * find the fragment by searching through the free block
6234651Smckusic 	 * map for an appropriate bit pattern
6244651Smckusic 	 */
6254651Smckusic 	if (bpref)
6264651Smckusic 		start = bpref % fs->fs_fpg / NBBY;
6274651Smckusic 	else
6284651Smckusic 		start = cgp->cg_frotor / NBBY;
6294651Smckusic 	len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start;
6304651Smckusic 	loc = scanc(len, &cgp->cg_free[start], fragtbl, 1 << (allocsiz - 1));
6314651Smckusic 	if (loc == 0) {
6324651Smckusic 		len = start - 1;
6334651Smckusic 		start = (cgdmin(cgp->cg_cgx, fs) -
6344651Smckusic 			 cgbase(cgp->cg_cgx, fs)) / NBBY;
6354651Smckusic 		loc = scanc(len, &cgp->cg_free[start], fragtbl,
6364651Smckusic 			1 << (allocsiz - 1));
6374651Smckusic 		if (loc == 0) {
6384651Smckusic 			panic("alloccg: map corrupted");
6394651Smckusic 			return (0);
6404651Smckusic 		}
6414651Smckusic 	}
6424651Smckusic 	bno = (start + len - loc) * NBBY;
6434651Smckusic 	cgp->cg_frotor = bno;
6444651Smckusic 	/*
6454651Smckusic 	 * found the byte in the map
6464651Smckusic 	 * sift through the bits to find the selected frag
6474651Smckusic 	 */
6484651Smckusic 	for (i = 0; i < NBBY; i += FRAG) {
6494651Smckusic 		blk = (cgp->cg_free[bno / NBBY] >> i) & (0xff >> NBBY - FRAG);
6504651Smckusic 		blk <<= 1;
6514651Smckusic 		field = around[allocsiz];
6524651Smckusic 		subfield = inside[allocsiz];
6534651Smckusic 		for (pos = 0; pos <= FRAG - allocsiz; pos++) {
6544651Smckusic 			if ((blk & field) == subfield) {
6554651Smckusic 				return (bno + i + pos);
6564651Smckusic 			}
6574651Smckusic 			field <<= 1;
6584651Smckusic 			subfield <<= 1;
6594651Smckusic 		}
6604651Smckusic 	}
6614651Smckusic 	panic("alloccg: block not in map");
6624651Smckusic 	return (0);
6634651Smckusic }
6644651Smckusic 
6654651Smckusic /*
6664463Smckusic  * update the frsum fields to reflect addition or deletion
6674463Smckusic  * of some frags
6684463Smckusic  */
6694463Smckusic fragacct(fragmap, fraglist, cnt)
6704472Smckusic 	int fragmap;
6714792Smckusic 	long fraglist[];
6724463Smckusic 	int cnt;
6734463Smckusic {
6744463Smckusic 	int inblk;
6754463Smckusic 	register int field, subfield;
6764463Smckusic 	register int siz, pos;
6774463Smckusic 
6784472Smckusic 	inblk = (int)(fragtbl[fragmap]) << 1;
6794463Smckusic 	fragmap <<= 1;
6804463Smckusic 	for (siz = 1; siz < FRAG; siz++) {
6814463Smckusic 		if (((1 << siz) & inblk) == 0)
6824463Smckusic 			continue;
6834463Smckusic 		field = around[siz];
6844463Smckusic 		subfield = inside[siz];
6854463Smckusic 		for (pos = siz; pos <= FRAG; pos++) {
6864463Smckusic 			if ((fragmap & field) == subfield) {
6874463Smckusic 				fraglist[siz] += cnt;
6884463Smckusic 				pos += siz;
6894463Smckusic 				field <<= siz;
6904463Smckusic 				subfield <<= siz;
6914463Smckusic 			}
6924463Smckusic 			field <<= 1;
6934463Smckusic 			subfield <<= 1;
6944463Smckusic 		}
6954463Smckusic 	}
6964463Smckusic }
6974463Smckusic 
6984359Smckusick badblock(fs, bn)
6994359Smckusick 	register struct fs *fs;
7004359Smckusick 	daddr_t bn;
7014359Smckusick {
7024359Smckusick 
7034359Smckusick 	if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) {
7044359Smckusick 		fserr(fs, "bad block");
7054359Smckusick 		return (1);
7064359Smckusick 	}
7074359Smckusick 	return (0);
7084359Smckusick }
7094359Smckusick 
7104359Smckusick /*
7114359Smckusick  * getfs maps a device number into
7124359Smckusick  * a pointer to the incore super
7134359Smckusick  * block.  The algorithm is a linear
7144359Smckusick  * search through the mount table.
7154359Smckusick  * A consistency check of the
7164359Smckusick  * in core free-block and i-node
7174359Smckusick  * counts is performed.
7184359Smckusick  *
7194359Smckusick  * panic: no fs -- the device is not mounted.
7204359Smckusick  *	this "cannot happen"
7214359Smckusick  */
7224359Smckusick struct fs *
7234359Smckusick getfs(dev)
7244359Smckusick 	dev_t dev;
7254359Smckusick {
7264359Smckusick 	register struct mount *mp;
7274359Smckusick 	register struct fs *fs;
7284359Smckusick 
7294359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
7304359Smckusick 		if (mp->m_bufp != NULL && mp->m_dev == dev) {
7314359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
7324359Smckusick 			if (fs->fs_magic != FS_MAGIC)
7334359Smckusick 				panic("getfs: bad magic");
7344359Smckusick 			return (fs);
7354359Smckusick 		}
7364359Smckusick 	panic("getfs: no fs");
7374359Smckusick 	return (NULL);
7384359Smckusick }
7394359Smckusick 
7404359Smckusick /*
7414359Smckusick  * Fserr prints the name of a file system
7424359Smckusick  * with an error diagnostic, in the form
7434359Smckusick  *	fs: error message
7444359Smckusick  */
7454359Smckusick fserr(fs, cp)
7464359Smckusick 	struct fs *fs;
7474359Smckusick 	char *cp;
7484359Smckusick {
7494359Smckusick 
7504359Smckusick 	printf("%s: %s\n", fs->fs_fsmnt, cp);
7514359Smckusick }
7524359Smckusick 
7534359Smckusick /*
7544359Smckusick  * Getfsx returns the index in the file system
7554359Smckusick  * table of the specified device.  The swap device
7564359Smckusick  * is also assigned a pseudo-index.  The index may
7574359Smckusick  * be used as a compressed indication of the location
7584359Smckusick  * of a block, recording
7594359Smckusick  *	<getfsx(dev),blkno>
7604359Smckusick  * rather than
7614359Smckusick  *	<dev, blkno>
7624359Smckusick  * provided the information need remain valid only
7634359Smckusick  * as long as the file system is mounted.
7644359Smckusick  */
7654359Smckusick getfsx(dev)
7664359Smckusick 	dev_t dev;
7674359Smckusick {
7684359Smckusick 	register struct mount *mp;
7694359Smckusick 
7704359Smckusick 	if (dev == swapdev)
7714359Smckusick 		return (MSWAPX);
7724359Smckusick 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
7734359Smckusick 		if (mp->m_dev == dev)
7744359Smckusick 			return (mp - &mount[0]);
7754359Smckusick 	return (-1);
7764359Smckusick }
7774359Smckusick 
7784359Smckusick /*
7794359Smckusick  * Update is the internal name of 'sync'.  It goes through the disk
7804359Smckusick  * queues to initiate sandbagged IO; goes through the inodes to write
7814359Smckusick  * modified nodes; and it goes through the mount table to initiate modified
7824359Smckusick  * super blocks.
7834359Smckusick  */
7844359Smckusick update()
7854359Smckusick {
7864359Smckusick 	register struct inode *ip;
7874359Smckusick 	register struct mount *mp;
7884359Smckusick 	register struct buf *bp;
7894359Smckusick 	struct fs *fs;
7904359Smckusick 	time_t tim;
7914651Smckusic 	int i, blks;
7924359Smckusick 
7934359Smckusick 	if (updlock)
7944359Smckusick 		return;
7954359Smckusick 	updlock++;
7964359Smckusick 	/*
7974359Smckusick 	 * Write back modified superblocks.
7984359Smckusick 	 * Consistency check that the superblock
7994359Smckusick 	 * of each file system is still in the buffer cache.
8004359Smckusick 	 */
8014359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
8024359Smckusick 		if (mp->m_bufp != NULL) {
8034359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
8044359Smckusick 			if (fs->fs_fmod == 0)
8054359Smckusick 				continue;
8064359Smckusick 			if (fs->fs_ronly != 0)
8074359Smckusick 				panic("update: rofs mod");
8084426Smckusic 			bp = getblk(mp->m_dev, SBLOCK, BSIZE);
8094359Smckusick 			fs->fs_fmod = 0;
8104359Smckusick 			fs->fs_time = TIME;
8114359Smckusick 			if (bp->b_un.b_fs != fs)
8124359Smckusick 				panic("update: bad b_fs");
8134359Smckusick 			bwrite(bp);
8144651Smckusic 			blks = howmany(cssize(fs), BSIZE);
8154651Smckusic 			for (i = 0; i < blks; i++) {
8164651Smckusic 				bp = getblk(mp->m_dev, csaddr(fs) + (i * FRAG),
8174426Smckusic 					BSIZE);
8184359Smckusick 				bwrite(bp);
8194359Smckusick 			}
8204359Smckusick 		}
8214359Smckusick 	/*
8224359Smckusick 	 * Write back each (modified) inode.
8234359Smckusick 	 */
8244359Smckusick 	for (ip = inode; ip < inodeNINODE; ip++)
8254359Smckusick 		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
8264359Smckusick 			ip->i_flag |= ILOCK;
8274359Smckusick 			ip->i_count++;
8284359Smckusick 			tim = TIME;
8294359Smckusick 			iupdat(ip, &tim, &tim, 0);
8304359Smckusick 			iput(ip);
8314359Smckusick 		}
8324359Smckusick 	updlock = 0;
8334359Smckusick 	/*
8344359Smckusick 	 * Force stale buffer cache information to be flushed,
8354359Smckusick 	 * for all devices.
8364359Smckusick 	 */
8374359Smckusick 	bflush(NODEV);
8384359Smckusick }
839