xref: /csrg-svn/sys/ufs/lfs/lfs_alloc.c (revision 4463)
14359Smckusick /* Copyright (c) 1981 Regents of the University of California */
24359Smckusick 
3*4463Smckusic static char vers[] = "@(#)lfs_alloc.c 1.4 10/05/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 
174359Smckusick long	hashalloc();
184359Smckusick long	alloccg();
194359Smckusick long	ialloccg();
204359Smckusick 
214359Smckusick struct buf *
224359Smckusick alloc(dev, ip, bpref, size)
234359Smckusick 	dev_t dev;
24*4463Smckusic 	register struct inode *ip;
254359Smckusick 	daddr_t bpref;
264359Smckusick 	int size;
274359Smckusick {
284359Smckusick 	daddr_t bno;
294359Smckusick 	register struct fs *fs;
30*4463Smckusic 	register struct buf *bp;
314359Smckusick 	int cg;
324359Smckusick 
33*4463Smckusic 	if ((unsigned)size > BSIZE || size % FSIZE != 0)
34*4463Smckusic 		panic("alloc: bad size");
354359Smckusick 	fs = getfs(dev);
364359Smckusick 	if (fs->fs_nbfree == 0 && size == BSIZE)
374359Smckusick 		goto nospace;
384359Smckusick 	if (bpref == 0)
394359Smckusick 		cg = itog(ip->i_number, fs);
404359Smckusick 	else
414359Smckusick 		cg = dtog(bpref, fs);
424359Smckusick 	bno = hashalloc(dev, fs, cg, (long)bpref, size, alloccg);
434359Smckusick 	if (bno == 0)
444359Smckusick 		goto nospace;
454426Smckusic 	bp = getblk(dev, bno, size);
464359Smckusick 	clrbuf(bp);
474359Smckusick 	return (bp);
484359Smckusick nospace:
494359Smckusick 	fserr(fs, "file system full");
504359Smckusick 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
514359Smckusick 	u.u_error = ENOSPC;
524359Smckusick 	return (NULL);
534359Smckusick }
544359Smckusick 
554426Smckusic struct buf *
56*4463Smckusic realloccg(dev, ip, bprev, osize, nsize)
574426Smckusic 	dev_t dev;
58*4463Smckusic 	register struct inode *ip;
59*4463Smckusic 	daddr_t bprev;
604426Smckusic 	int osize, nsize;
614426Smckusic {
624426Smckusic 	daddr_t bno;
634426Smckusic 	register struct fs *fs;
64*4463Smckusic 	register struct buf *bp, *obp;
65*4463Smckusic 	caddr_t cp;
664426Smckusic 	int cg;
674426Smckusic 
68*4463Smckusic 	if ((unsigned)osize > BSIZE || osize % FSIZE != 0 ||
69*4463Smckusic 	    (unsigned)nsize > BSIZE || nsize % FSIZE != 0)
70*4463Smckusic 		panic("realloccg: bad size");
714426Smckusic 	fs = getfs(dev);
72*4463Smckusic 	if (bprev == 0)
73*4463Smckusic 		panic("realloccg: bad bprev");
744426Smckusic 	else
75*4463Smckusic 		cg = dtog(bprev, fs);
76*4463Smckusic 	bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize);
77*4463Smckusic 	if (bno != 0) {
78*4463Smckusic 		bp = bread(dev, bno, osize);
79*4463Smckusic 		bp->b_bcount = nsize;
80*4463Smckusic 		blkclr(bp->b_un.b_addr + osize, nsize - osize);
81*4463Smckusic 		return (bp);
82*4463Smckusic 	}
83*4463Smckusic 	bno = hashalloc(dev, fs, cg, (long)bprev, nsize, alloccg);
84*4463Smckusic 	if (bno != 0) {
85*4463Smckusic 		/*
86*4463Smckusic 		 * make a new copy
87*4463Smckusic 		 */
88*4463Smckusic 		obp = bread(dev, bprev, osize);
89*4463Smckusic 		bp = getblk(dev, bno, nsize);
90*4463Smckusic 		cp = bp->b_un.b_addr;
91*4463Smckusic 		bp->b_un.b_addr = obp->b_un.b_addr;
92*4463Smckusic 		obp->b_un.b_addr = cp;
93*4463Smckusic 		obp->b_flags |= B_INVAL;
94*4463Smckusic 		brelse(obp);
95*4463Smckusic 		fre(dev, bprev, osize);
96*4463Smckusic 		blkclr(bp->b_un.b_addr + osize, nsize - osize);
97*4463Smckusic 		return(bp);
98*4463Smckusic 	}
99*4463Smckusic 	/*
100*4463Smckusic 	 * no space available
101*4463Smckusic 	 */
1024426Smckusic 	fserr(fs, "file system full");
1034426Smckusic 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
1044426Smckusic 	u.u_error = ENOSPC;
1054426Smckusic 	return (NULL);
1064426Smckusic }
1074426Smckusic 
1084359Smckusick struct inode *
1094359Smckusick ialloc(dev, ipref, mode)
1104359Smckusick 	dev_t dev;
1114359Smckusick 	ino_t ipref;
1124359Smckusick 	int mode;
1134359Smckusick {
1144359Smckusick 	daddr_t ino;
1154359Smckusick 	register struct fs *fs;
1164359Smckusick 	register struct inode *ip;
1174359Smckusick 	int cg;
1184359Smckusick 
1194359Smckusick 	fs = getfs(dev);
1204359Smckusick 	if (fs->fs_nifree == 0)
1214359Smckusick 		goto noinodes;
1224359Smckusick 	cg = itog(ipref, fs);
1234359Smckusick 	ino = hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg);
1244359Smckusick 	if (ino == 0)
1254359Smckusick 		goto noinodes;
1264359Smckusick 	ip = iget(dev, ino);
1274359Smckusick 	if (ip == NULL) {
1284359Smckusick 		ifree(dev, ino);
1294359Smckusick 		return (NULL);
1304359Smckusick 	}
1314359Smckusick 	if (ip->i_mode)
1324359Smckusick 		panic("ialloc: dup alloc");
1334359Smckusick 	return (ip);
1344359Smckusick noinodes:
1354359Smckusick 	fserr(fs, "out of inodes");
1364359Smckusick 	uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt);
1374359Smckusick 	u.u_error = ENOSPC;
1384359Smckusick 	return (NULL);
1394359Smckusick }
1404359Smckusick 
1414359Smckusick dipref(dev)
1424359Smckusick 	dev_t dev;
1434359Smckusick {
1444359Smckusick 	register struct fs *fs;
1454359Smckusick 	int cg, minndir, mincg;
1464359Smckusick 
1474359Smckusick 	fs = getfs(dev);
1484359Smckusick 	minndir = fs->fs_cs[0].cs_ndir;
1494359Smckusick 	mincg = 0;
1504359Smckusick 	for (cg = 1; cg < fs->fs_ncg; cg++)
1514359Smckusick 		if (fs->fs_cs[cg].cs_ndir < minndir) {
1524359Smckusick 			mincg = cg;
1534359Smckusick 			minndir = fs->fs_cs[cg].cs_ndir;
1544359Smckusick 			if (minndir == 0)
1554359Smckusick 				break;
1564359Smckusick 		}
1574359Smckusick 	return (fs->fs_ipg * mincg);
1584359Smckusick }
1594359Smckusick 
1604359Smckusick long
1614359Smckusick hashalloc(dev, fs, cg, pref, size, allocator)
1624359Smckusick 	dev_t dev;
1634359Smckusick 	register struct fs *fs;
1644359Smckusick 	int cg;
1654359Smckusick 	long pref;
1664359Smckusick 	int size;	/* size for data blocks, mode for inodes */
1674359Smckusick 	long (*allocator)();
1684359Smckusick {
1694359Smckusick 	long result;
1704359Smckusick 	int i, icg = cg;
1714359Smckusick 
1724359Smckusick 	/*
1734359Smckusick 	 * 1: preferred cylinder group
1744359Smckusick 	 */
1754359Smckusick 	result = (*allocator)(dev, fs, cg, pref, size);
1764359Smckusick 	if (result)
1774359Smckusick 		return (result);
1784359Smckusick 	/*
1794359Smckusick 	 * 2: quadratic rehash
1804359Smckusick 	 */
1814359Smckusick 	for (i = 1; i < fs->fs_ncg; i *= 2) {
1824359Smckusick 		cg += i;
1834359Smckusick 		if (cg >= fs->fs_ncg)
1844359Smckusick 			cg -= fs->fs_ncg;
1854359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
1864359Smckusick 		if (result)
1874359Smckusick 			return (result);
1884359Smckusick 	}
1894359Smckusick 	/*
1904359Smckusick 	 * 3: brute force search
1914359Smckusick 	 */
1924359Smckusick 	cg = icg;
1934359Smckusick 	for (i = 0; i < fs->fs_ncg; i++) {
1944359Smckusick 		result = (*allocator)(dev, fs, cg, 0, size);
1954359Smckusick 		if (result)
1964359Smckusick 			return (result);
1974359Smckusick 		cg++;
1984359Smckusick 		if (cg == fs->fs_ncg)
1994359Smckusick 			cg = 0;
2004359Smckusick 	}
2014359Smckusick 	return (0);
2024359Smckusick }
2034359Smckusick 
2044359Smckusick daddr_t
205*4463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize)
2064426Smckusic 	dev_t dev;
2074426Smckusic 	register struct fs *fs;
2084426Smckusic 	int cg;
209*4463Smckusic 	long bprev;
2104426Smckusic 	int osize, nsize;
2114426Smckusic {
212*4463Smckusic 	register struct buf *bp;
213*4463Smckusic 	register struct cg *cgp;
214*4463Smckusic 	long bno;
215*4463Smckusic 	int frags, bbase;
2164426Smckusic 	int i;
2174426Smckusic 
218*4463Smckusic 	frags = nsize / FSIZE;
219*4463Smckusic 	bbase = bprev % FRAG;
220*4463Smckusic 	if (bbase > (bprev + frags - 1) % FRAG) {
221*4463Smckusic 		/* cannot extend across a block boundry */
222*4463Smckusic 		return (0);
223*4463Smckusic 	}
2244426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
2254426Smckusic 	if (bp->b_flags & B_ERROR)
2264426Smckusic 		return (0);
2274426Smckusic 	cgp = bp->b_un.b_cg;
228*4463Smckusic 	bno = bprev % fs->fs_fpg;
229*4463Smckusic 	for (i = osize / FSIZE; i < frags; i++) {
230*4463Smckusic 		if (isclr(cgp->cg_free, bno + i))
231*4463Smckusic 			break;
232*4463Smckusic 	}
233*4463Smckusic 	if (i == frags) {
234*4463Smckusic 		/*
235*4463Smckusic 		 * the current fragment can be extended
236*4463Smckusic 		 * deduct the count on fragment being extended into
237*4463Smckusic 		 * increase the count on the remaining fragment (if any)
238*4463Smckusic 		 * allocate the extended piece
239*4463Smckusic 		 */
240*4463Smckusic 		for (i = frags; i < FRAG - bbase; i++)
241*4463Smckusic 			if (isclr(cgp->cg_free, bno + i))
2424426Smckusic 				break;
243*4463Smckusic 		cgp->cg_frsum[i - osize / FSIZE]--;
244*4463Smckusic 		if (i != frags)
245*4463Smckusic 			cgp->cg_frsum[i - frags]++;
246*4463Smckusic 		for (i = osize / FSIZE; i < frags; i++) {
247*4463Smckusic 			clrbit(cgp->cg_free, bno + i);
248*4463Smckusic 			cgp->cg_nffree--;
249*4463Smckusic 			fs->fs_nffree--;
2504426Smckusic 		}
251*4463Smckusic 		fs->fs_fmod++;
252*4463Smckusic 		bdwrite(bp);
253*4463Smckusic 		return (bprev);
2544426Smckusic 	}
2554426Smckusic 	brelse(bp);
2564426Smckusic 	return (0);
2574426Smckusic }
2584426Smckusic 
2594426Smckusic daddr_t
2604359Smckusick alloccg(dev, fs, cg, bpref, size)
2614359Smckusick 	dev_t dev;
262*4463Smckusic 	register struct fs *fs;
2634359Smckusick 	int cg;
2644359Smckusick 	daddr_t bpref;
2654359Smckusick 	int size;
2664359Smckusick {
267*4463Smckusic 	register struct buf *bp;
268*4463Smckusic 	register struct cg *cgp;
269*4463Smckusic 	int bno, frags;
270*4463Smckusic 	int allocsiz;
271*4463Smckusic 	int start, len, loc;
272*4463Smckusic 	int blk, field, subfield, pos;
273*4463Smckusic 	register int i;
2744359Smckusick 
2754426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
2764359Smckusick 	if (bp->b_flags & B_ERROR)
2774359Smckusick 		return (0);
2784359Smckusick 	cgp = bp->b_un.b_cg;
279*4463Smckusic 	if (size == BSIZE) {
280*4463Smckusic 		if (cgp->cg_nbfree == 0) {
281*4463Smckusic 			brelse(bp);
282*4463Smckusic 			return (0);
283*4463Smckusic 		}
284*4463Smckusic 		bno = alloccgblk(dev, fs, cgp, bpref);
285*4463Smckusic 		bdwrite(bp);
286*4463Smckusic 		return (bno);
287*4463Smckusic 	}
288*4463Smckusic 	/*
289*4463Smckusic 	 * check to see if any fragments are already available
290*4463Smckusic 	 * allocsiz is the size which will be allocated, hacking
291*4463Smckusic 	 * it down to a smaller size if necessary
292*4463Smckusic 	 */
293*4463Smckusic 	frags = size / FSIZE;
294*4463Smckusic 	for (allocsiz = frags; allocsiz < FRAG; allocsiz++)
295*4463Smckusic 		if (cgp->cg_frsum[allocsiz] != 0)
296*4463Smckusic 			break;
297*4463Smckusic 	if (allocsiz == FRAG) {
298*4463Smckusic 		/*
299*4463Smckusic 		 * no fragments were available, so a block will be
300*4463Smckusic 		 * allocated, and hacked up
301*4463Smckusic 		 */
302*4463Smckusic 		if (cgp->cg_nbfree == 0) {
303*4463Smckusic 			brelse(bp);
304*4463Smckusic 			return (0);
305*4463Smckusic 		}
306*4463Smckusic 		bno = alloccgblk(dev, fs, cgp, bpref);
307*4463Smckusic 		bpref = bno % fs->fs_fpg;
308*4463Smckusic 		for (i = frags; i < FRAG; i++)
309*4463Smckusic 			setbit(cgp->cg_free, bpref + i);
310*4463Smckusic 		i = FRAG - frags;
311*4463Smckusic 		cgp->cg_nffree += i;
312*4463Smckusic 		fs->fs_nffree += i;
313*4463Smckusic 		cgp->cg_frsum[i]++;
314*4463Smckusic 		bdwrite(bp);
315*4463Smckusic 		return (bno);
316*4463Smckusic 	}
317*4463Smckusic 	/*
318*4463Smckusic 	 * find the fragment by searching through the free block
319*4463Smckusic 	 * map for an appropriate bit pattern
320*4463Smckusic 	 */
321*4463Smckusic 	if (bpref)
322*4463Smckusic 		start = bpref % fs->fs_fpg / NBBY;
323*4463Smckusic 	else
324*4463Smckusic 		start = cgp->cg_frotor / NBBY;
325*4463Smckusic 	len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start;
326*4463Smckusic 	loc = scanc(len, &cgp->cg_free[start], fragtbl, 1 << (allocsiz - 1));
327*4463Smckusic 	if (loc == 0) {
328*4463Smckusic 		len = start - 1;
329*4463Smckusic 		start = (cgdmin(cg, fs) - cgbase(cg, fs)) / NBBY;
330*4463Smckusic 		loc = scanc(len, &cgp->cg_free[start], fragtbl,
331*4463Smckusic 			1 << (allocsiz - 1));
332*4463Smckusic 		if (loc == 0)
333*4463Smckusic 			panic("alloccg: can't find frag");
334*4463Smckusic 	}
335*4463Smckusic 	bno = (start + len - loc) * NBBY;
336*4463Smckusic 	cgp->cg_frotor = bno;
337*4463Smckusic 	/*
338*4463Smckusic 	 * found the byte in the map
339*4463Smckusic 	 * sift through the bits to find the selected frag
340*4463Smckusic 	 */
341*4463Smckusic 	for (i = 0; i < NBBY; i += FRAG) {
342*4463Smckusic 		blk = (cgp->cg_free[bno / NBBY] >> i) & (0xff >> NBBY - FRAG);
343*4463Smckusic 		blk <<= 1;
344*4463Smckusic 		field = around[allocsiz];
345*4463Smckusic 		subfield = inside[allocsiz];
346*4463Smckusic 		for (pos = 0; pos <= FRAG - allocsiz; pos++) {
347*4463Smckusic 			if ((blk & field) == subfield) {
348*4463Smckusic 				bno += i + pos;
349*4463Smckusic 				goto gotit;
350*4463Smckusic 			}
351*4463Smckusic 			field <<= 1;
352*4463Smckusic 			subfield <<= 1;
353*4463Smckusic 		}
354*4463Smckusic 	}
355*4463Smckusic 	panic("alloccg: frag not in block");
356*4463Smckusic gotit:
357*4463Smckusic 	for (i = 0; i < frags; i++)
358*4463Smckusic 		clrbit(cgp->cg_free, bno + i);
359*4463Smckusic 	cgp->cg_nffree -= frags;
360*4463Smckusic 	fs->fs_nffree -= frags;
361*4463Smckusic 	cgp->cg_frsum[allocsiz]--;
362*4463Smckusic 	if (frags != allocsiz)
363*4463Smckusic 		cgp->cg_frsum[allocsiz - frags]++;
364*4463Smckusic 	bdwrite(bp);
365*4463Smckusic 	return (cg * fs->fs_fpg + bno);
366*4463Smckusic }
367*4463Smckusic 
368*4463Smckusic daddr_t
369*4463Smckusic alloccgblk(dev, fs, cgp, bpref)
370*4463Smckusic 	dev_t dev;
371*4463Smckusic 	struct fs *fs;
372*4463Smckusic 	register struct cg *cgp;
373*4463Smckusic 	daddr_t bpref;
374*4463Smckusic {
375*4463Smckusic 	register int i;
376*4463Smckusic 
3774359Smckusick 	if (bpref) {
378*4463Smckusic 		bpref &= ~(FRAG - 1);
3794359Smckusick 		bpref %= fs->fs_fpg;
3804359Smckusick 		if (isblock(cgp->cg_free, bpref/FRAG))
3814359Smckusick 			goto gotit;
3824359Smckusick 	} else
3834359Smckusick 		bpref = cgp->cg_rotor;
3844359Smckusick 	for (i = 0; i < cgp->cg_ndblk; i += FRAG) {
3854359Smckusick 		bpref += FRAG;
3864359Smckusick 		if (bpref >= cgp->cg_ndblk)
3874359Smckusick 			bpref = 0;
3884359Smckusick 		if (isblock(cgp->cg_free, bpref/FRAG)) {
3894359Smckusick 			cgp->cg_rotor = bpref;
3904359Smckusick 			goto gotit;
3914359Smckusick 		}
3924359Smckusick 	}
393*4463Smckusic 	panic("alloccgblk: can't find a blk");
3944359Smckusick 	return (0);
3954359Smckusick gotit:
396*4463Smckusic 	clrblock(cgp->cg_free, bpref/FRAG);
397*4463Smckusic 	cgp->cg_nbfree--;
398*4463Smckusic 	fs->fs_nbfree--;
399*4463Smckusic 	fs->fs_cs[cgp->cg_cgx].cs_nbfree--;
400*4463Smckusic 	i = bpref * NSPF;
401*4463Smckusic 	cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--;
4024359Smckusick 	fs->fs_fmod++;
403*4463Smckusic 	return (cgp->cg_cgx * fs->fs_fpg + bpref);
4044359Smckusick }
4054359Smckusick 
4064359Smckusick long
4074359Smckusick ialloccg(dev, fs, cg, ipref, mode)
4084359Smckusick 	dev_t dev;
409*4463Smckusic 	register struct fs *fs;
4104359Smckusick 	int cg;
4114359Smckusick 	daddr_t ipref;
4124359Smckusick 	int mode;
4134359Smckusick {
414*4463Smckusic 	register struct buf *bp;
415*4463Smckusic 	register struct cg *cgp;
4164359Smckusick 	int i;
4174359Smckusick 
4184426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
4194359Smckusick 	if (bp->b_flags & B_ERROR)
4204359Smckusick 		return (0);
4214359Smckusick 	cgp = bp->b_un.b_cg;
4224359Smckusick 	if (cgp->cg_nifree == 0) {
4234359Smckusick 		brelse(bp);
4244359Smckusick 		return (0);
4254359Smckusick 	}
4264359Smckusick 	if (ipref) {
4274359Smckusick 		ipref %= fs->fs_ipg;
4284359Smckusick 		if (isclr(cgp->cg_iused, ipref))
4294359Smckusick 			goto gotit;
4304359Smckusick 	} else
4314359Smckusick 		ipref = cgp->cg_irotor;
4324359Smckusick 	for (i = 0; i < fs->fs_ipg; i++) {
4334359Smckusick 		ipref++;
4344359Smckusick 		if (ipref >= fs->fs_ipg)
4354359Smckusick 			ipref = 0;
4364359Smckusick 		if (isclr(cgp->cg_iused, ipref)) {
4374359Smckusick 			cgp->cg_irotor = ipref;
4384359Smckusick 			goto gotit;
4394359Smckusick 		}
4404359Smckusick 	}
4414359Smckusick 	brelse(bp);
4424359Smckusick 	return (0);
4434359Smckusick gotit:
4444359Smckusick 	setbit(cgp->cg_iused, ipref);
4454359Smckusick 	cgp->cg_nifree--;
4464359Smckusick 	fs->fs_nifree--;
4474359Smckusick 	fs->fs_cs[cg].cs_nifree--;
4484359Smckusick 	fs->fs_fmod++;
4494359Smckusick 	if ((mode & IFMT) == IFDIR) {
4504359Smckusick 		cgp->cg_ndir++;
4514359Smckusick 		fs->fs_cs[cg].cs_ndir++;
4524359Smckusick 	}
4534359Smckusick 	bdwrite(bp);
4544359Smckusick 	return (cg * fs->fs_ipg + ipref);
4554359Smckusick }
4564359Smckusick 
4574359Smckusick fre(dev, bno, size)
4584359Smckusick 	dev_t dev;
4594359Smckusick 	daddr_t bno;
4604359Smckusick 	int size;
4614359Smckusick {
4624359Smckusick 	register struct fs *fs;
4634359Smckusick 	register struct cg *cgp;
4644359Smckusick 	register struct buf *bp;
465*4463Smckusic 	int cg, blk, frags, bbase;
466*4463Smckusic 	register int i;
4674359Smckusick 
4684426Smckusic 	if ((unsigned)size > BSIZE || size % FSIZE != 0)
4694426Smckusic 		panic("free: bad size");
4704359Smckusick 	fs = getfs(dev);
4714359Smckusick 	cg = dtog(bno, fs);
4724359Smckusick 	if (badblock(fs, bno))
4734359Smckusick 		return;
4744426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
4754359Smckusick 	if (bp->b_flags & B_ERROR)
4764359Smckusick 		return;
4774359Smckusick 	cgp = bp->b_un.b_cg;
4784359Smckusick 	bno %= fs->fs_fpg;
4794426Smckusic 	if (size == BSIZE) {
4804426Smckusic 		if (isblock(cgp->cg_free, bno/FRAG))
4814426Smckusic 			panic("free: freeing free block");
4824426Smckusic 		setblock(cgp->cg_free, bno/FRAG);
4834426Smckusic 		cgp->cg_nbfree++;
4844426Smckusic 		fs->fs_nbfree++;
4854426Smckusic 		fs->fs_cs[cg].cs_nbfree++;
4864426Smckusic 		i = bno * NSPF;
4874426Smckusic 		cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++;
4884426Smckusic 	} else {
489*4463Smckusic 		bbase = bno - (bno % FRAG);
490*4463Smckusic 		/*
491*4463Smckusic 		 * decrement the counts associated with the old frags
492*4463Smckusic 		 */
493*4463Smckusic 		blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) &
494*4463Smckusic 		       (0xff >> (NBBY - FRAG)));
495*4463Smckusic 		fragacct(blk, cgp->cg_frsum, -1);
496*4463Smckusic 		/*
497*4463Smckusic 		 * deallocate the fragment
498*4463Smckusic 		 */
499*4463Smckusic 		frags = size / FSIZE;
500*4463Smckusic 		for (i = 0; i < frags; i++) {
5014426Smckusic 			if (isset(cgp->cg_free, bno + i))
5024426Smckusic 				panic("free: freeing free frag");
5034426Smckusic 			setbit(cgp->cg_free, bno + i);
5044426Smckusic 			cgp->cg_nffree++;
5054426Smckusic 			fs->fs_nffree++;
5064426Smckusic 		}
507*4463Smckusic 		/*
508*4463Smckusic 		 * add back in counts associated with the new frags
509*4463Smckusic 		 */
510*4463Smckusic 		blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) &
511*4463Smckusic 		       (0xff >> (NBBY - FRAG)));
512*4463Smckusic 		fragacct(blk, cgp->cg_frsum, 1);
513*4463Smckusic 		/*
514*4463Smckusic 		 * if a complete block has been reassembled, account for it
515*4463Smckusic 		 */
516*4463Smckusic 		if (isblock(cgp->cg_free, bbase / FRAG)) {
5174426Smckusic 			cgp->cg_nffree -= FRAG;
5184426Smckusic 			fs->fs_nffree -= FRAG;
5194426Smckusic 			cgp->cg_nbfree++;
5204426Smckusic 			fs->fs_nbfree++;
5214426Smckusic 			fs->fs_cs[cg].cs_nbfree++;
522*4463Smckusic 			i = bbase * NSPF;
5234426Smckusic 			cgp->cg_b[i / fs->fs_spc]
5244426Smckusic 				 [i % fs->fs_nsect * NRPOS / fs->fs_nsect]++;
5254426Smckusic 		}
5264426Smckusic 	}
5274359Smckusick 	fs->fs_fmod++;
5284359Smckusick 	bdwrite(bp);
5294359Smckusick }
5304359Smckusick 
5314359Smckusick ifree(dev, ino, mode)
5324359Smckusick 	dev_t dev;
5334359Smckusick 	ino_t ino;
5344359Smckusick 	int mode;
5354359Smckusick {
5364359Smckusick 	register struct fs *fs;
5374359Smckusick 	register struct cg *cgp;
5384359Smckusick 	register struct buf *bp;
5394359Smckusick 	int i;
5404359Smckusick 	int cg;
5414359Smckusick 
5424359Smckusick 	fs = getfs(dev);
5434359Smckusick 	if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
5444359Smckusick 		panic("ifree: range");
5454359Smckusick 	cg = itog(ino, fs);
5464426Smckusic 	bp = bread(dev, cgtod(cg, fs), BSIZE);
5474359Smckusick 	if (bp->b_flags & B_ERROR)
5484359Smckusick 		return;
5494359Smckusick 	cgp = bp->b_un.b_cg;
5504359Smckusick 	ino %= fs->fs_ipg;
5514359Smckusick 	if (isclr(cgp->cg_iused, ino))
5524359Smckusick 		panic("ifree: freeing free inode");
5534359Smckusick 	clrbit(cgp->cg_iused, ino);
5544359Smckusick 	cgp->cg_nifree++;
5554359Smckusick 	fs->fs_nifree++;
5564359Smckusick 	fs->fs_cs[cg].cs_nifree++;
5574359Smckusick 	if ((mode & IFMT) == IFDIR) {
5584359Smckusick 		cgp->cg_ndir--;
5594359Smckusick 		fs->fs_cs[cg].cs_ndir--;
5604359Smckusick 	}
5614359Smckusick 	fs->fs_fmod++;
5624359Smckusick 	bdwrite(bp);
5634359Smckusick }
5644359Smckusick 
565*4463Smckusic /*
566*4463Smckusic  * update the frsum fields to reflect addition or deletion
567*4463Smckusic  * of some frags
568*4463Smckusic  */
569*4463Smckusic fragacct(fragmap, fraglist, cnt)
570*4463Smckusic 	char fragmap;
571*4463Smckusic 	short fraglist[];
572*4463Smckusic 	int cnt;
573*4463Smckusic {
574*4463Smckusic 	int inblk;
575*4463Smckusic 	register int field, subfield;
576*4463Smckusic 	register int siz, pos;
577*4463Smckusic 
578*4463Smckusic 	inblk = (int)(fragtbl[fragmap] << 1);
579*4463Smckusic 	fragmap <<= 1;
580*4463Smckusic 	for (siz = 1; siz < FRAG; siz++) {
581*4463Smckusic 		if (((1 << siz) & inblk) == 0)
582*4463Smckusic 			continue;
583*4463Smckusic 		field = around[siz];
584*4463Smckusic 		subfield = inside[siz];
585*4463Smckusic 		for (pos = siz; pos <= FRAG; pos++) {
586*4463Smckusic 			if ((fragmap & field) == subfield) {
587*4463Smckusic 				fraglist[siz] += cnt;
588*4463Smckusic 				pos += siz;
589*4463Smckusic 				field <<= siz;
590*4463Smckusic 				subfield <<= siz;
591*4463Smckusic 			}
592*4463Smckusic 			field <<= 1;
593*4463Smckusic 			subfield <<= 1;
594*4463Smckusic 		}
595*4463Smckusic 	}
596*4463Smckusic }
597*4463Smckusic 
5984359Smckusick badblock(fs, bn)
5994359Smckusick 	register struct fs *fs;
6004359Smckusick 	daddr_t bn;
6014359Smckusick {
6024359Smckusick 
6034359Smckusick 	if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) {
6044359Smckusick 		fserr(fs, "bad block");
6054359Smckusick 		return (1);
6064359Smckusick 	}
6074359Smckusick 	return (0);
6084359Smckusick }
6094359Smckusick 
6104359Smckusick /*
6114359Smckusick  * getfs maps a device number into
6124359Smckusick  * a pointer to the incore super
6134359Smckusick  * block.  The algorithm is a linear
6144359Smckusick  * search through the mount table.
6154359Smckusick  * A consistency check of the
6164359Smckusick  * in core free-block and i-node
6174359Smckusick  * counts is performed.
6184359Smckusick  *
6194359Smckusick  * panic: no fs -- the device is not mounted.
6204359Smckusick  *	this "cannot happen"
6214359Smckusick  */
6224359Smckusick struct fs *
6234359Smckusick getfs(dev)
6244359Smckusick 	dev_t dev;
6254359Smckusick {
6264359Smckusick 	register struct mount *mp;
6274359Smckusick 	register struct fs *fs;
6284359Smckusick 
6294359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
6304359Smckusick 		if (mp->m_bufp != NULL && mp->m_dev == dev) {
6314359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
6324359Smckusick 			if (fs->fs_magic != FS_MAGIC)
6334359Smckusick 				panic("getfs: bad magic");
6344359Smckusick 			return (fs);
6354359Smckusick 		}
6364359Smckusick 	panic("getfs: no fs");
6374359Smckusick 	return (NULL);
6384359Smckusick }
6394359Smckusick 
6404359Smckusick /*
6414359Smckusick  * Fserr prints the name of a file system
6424359Smckusick  * with an error diagnostic, in the form
6434359Smckusick  *	fs: error message
6444359Smckusick  */
6454359Smckusick fserr(fs, cp)
6464359Smckusick 	struct fs *fs;
6474359Smckusick 	char *cp;
6484359Smckusick {
6494359Smckusick 
6504359Smckusick 	printf("%s: %s\n", fs->fs_fsmnt, cp);
6514359Smckusick }
6524359Smckusick 
6534359Smckusick /*
6544359Smckusick  * Getfsx returns the index in the file system
6554359Smckusick  * table of the specified device.  The swap device
6564359Smckusick  * is also assigned a pseudo-index.  The index may
6574359Smckusick  * be used as a compressed indication of the location
6584359Smckusick  * of a block, recording
6594359Smckusick  *	<getfsx(dev),blkno>
6604359Smckusick  * rather than
6614359Smckusick  *	<dev, blkno>
6624359Smckusick  * provided the information need remain valid only
6634359Smckusick  * as long as the file system is mounted.
6644359Smckusick  */
6654359Smckusick getfsx(dev)
6664359Smckusick 	dev_t dev;
6674359Smckusick {
6684359Smckusick 	register struct mount *mp;
6694359Smckusick 
6704359Smckusick 	if (dev == swapdev)
6714359Smckusick 		return (MSWAPX);
6724359Smckusick 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
6734359Smckusick 		if (mp->m_dev == dev)
6744359Smckusick 			return (mp - &mount[0]);
6754359Smckusick 	return (-1);
6764359Smckusick }
6774359Smckusick 
6784359Smckusick /*
6794359Smckusick  * Update is the internal name of 'sync'.  It goes through the disk
6804359Smckusick  * queues to initiate sandbagged IO; goes through the inodes to write
6814359Smckusick  * modified nodes; and it goes through the mount table to initiate modified
6824359Smckusick  * super blocks.
6834359Smckusick  */
6844359Smckusick update()
6854359Smckusick {
6864359Smckusick 	register struct inode *ip;
6874359Smckusick 	register struct mount *mp;
6884359Smckusick 	register struct buf *bp;
6894359Smckusick 	struct fs *fs;
6904359Smckusick 	time_t tim;
6914359Smckusick 	int i;
6924359Smckusick 
6934359Smckusick 	if (updlock)
6944359Smckusick 		return;
6954359Smckusick 	updlock++;
6964359Smckusick 	/*
6974359Smckusick 	 * Write back modified superblocks.
6984359Smckusick 	 * Consistency check that the superblock
6994359Smckusick 	 * of each file system is still in the buffer cache.
7004359Smckusick 	 */
7014359Smckusick 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
7024359Smckusick 		if (mp->m_bufp != NULL) {
7034359Smckusick 			fs = mp->m_bufp->b_un.b_fs;
7044359Smckusick 			if (fs->fs_fmod == 0)
7054359Smckusick 				continue;
7064359Smckusick 			if (fs->fs_ronly != 0)
7074359Smckusick 				panic("update: rofs mod");
7084426Smckusic 			bp = getblk(mp->m_dev, SBLOCK, BSIZE);
7094359Smckusick 			fs->fs_fmod = 0;
7104359Smckusick 			fs->fs_time = TIME;
7114359Smckusick 			if (bp->b_un.b_fs != fs)
7124359Smckusick 				panic("update: bad b_fs");
7134359Smckusick 			bwrite(bp);
7144359Smckusick 			for (i = 0; i < cssize(fs); i += BSIZE) {
7154426Smckusic 				bp = getblk(mp->m_dev, csaddr(fs) + i / FSIZE,
7164426Smckusic 					BSIZE);
7174359Smckusick 				bcopy(fs->fs_cs + i, bp->b_un.b_addr, BSIZE);
7184359Smckusick 				bwrite(bp);
7194359Smckusick 			}
7204359Smckusick 		}
7214359Smckusick 	/*
7224359Smckusick 	 * Write back each (modified) inode.
7234359Smckusick 	 */
7244359Smckusick 	for (ip = inode; ip < inodeNINODE; ip++)
7254359Smckusick 		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
7264359Smckusick 			ip->i_flag |= ILOCK;
7274359Smckusick 			ip->i_count++;
7284359Smckusick 			tim = TIME;
7294359Smckusick 			iupdat(ip, &tim, &tim, 0);
7304359Smckusick 			iput(ip);
7314359Smckusick 		}
7324359Smckusick 	updlock = 0;
7334359Smckusick 	/*
7344359Smckusick 	 * Force stale buffer cache information to be flushed,
7354359Smckusick 	 * for all devices.
7364359Smckusick 	 */
7374359Smckusick 	bflush(NODEV);
7384359Smckusick }
739