xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 16708)
1*16708Smckusick /*	ffs_subr.c	6.3	84/07/10	*/
28719Sroot 
38719Sroot #ifdef KERNEL
48719Sroot #include "../h/param.h"
59167Ssam #include "../h/systm.h"
69167Ssam #include "../h/mount.h"
78719Sroot #include "../h/fs.h"
89167Ssam #include "../h/conf.h"
99167Ssam #include "../h/buf.h"
109167Ssam #include "../h/inode.h"
119167Ssam #include "../h/dir.h"
129167Ssam #include "../h/user.h"
139167Ssam #include "../h/quota.h"
149167Ssam #include "../h/kernel.h"
158719Sroot #else
168719Sroot #include <sys/param.h>
179167Ssam #include <sys/systm.h>
189167Ssam #include <sys/mount.h>
198719Sroot #include <sys/fs.h>
209167Ssam #include <sys/conf.h>
219167Ssam #include <sys/buf.h>
229167Ssam #include <sys/inode.h>
239167Ssam #include <sys/dir.h>
249167Ssam #include <sys/user.h>
259167Ssam #include <sys/quota.h>
268719Sroot #endif
278719Sroot 
289167Ssam #ifdef KERNEL
299167Ssam int	syncprt = 0;
309167Ssam 
319167Ssam /*
329167Ssam  * Update is the internal name of 'sync'.  It goes through the disk
339167Ssam  * queues to initiate sandbagged IO; goes through the inodes to write
349167Ssam  * modified nodes; and it goes through the mount table to initiate
359167Ssam  * the writing of the modified super blocks.
369167Ssam  */
379167Ssam update()
389167Ssam {
399167Ssam 	register struct inode *ip;
409167Ssam 	register struct mount *mp;
419167Ssam 	struct fs *fs;
429167Ssam 
439167Ssam 	if (syncprt)
449167Ssam 		bufstats();
459167Ssam 	if (updlock)
469167Ssam 		return;
479167Ssam 	updlock++;
489167Ssam 	/*
499167Ssam 	 * Write back modified superblocks.
509167Ssam 	 * Consistency check that the superblock
519167Ssam 	 * of each file system is still in the buffer cache.
529167Ssam 	 */
539167Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
549764Ssam 		if (mp->m_bufp == NULL || mp->m_dev == NODEV)
559167Ssam 			continue;
569167Ssam 		fs = mp->m_bufp->b_un.b_fs;
579167Ssam 		if (fs->fs_fmod == 0)
589167Ssam 			continue;
599167Ssam 		if (fs->fs_ronly != 0) {		/* XXX */
609167Ssam 			printf("fs = %s\n", fs->fs_fsmnt);
619167Ssam 			panic("update: rofs mod");
629167Ssam 		}
639167Ssam 		fs->fs_fmod = 0;
649167Ssam 		fs->fs_time = time.tv_sec;
659167Ssam 		sbupdate(mp);
669167Ssam 	}
679167Ssam 	/*
689167Ssam 	 * Write back each (modified) inode.
699167Ssam 	 */
709167Ssam 	for (ip = inode; ip < inodeNINODE; ip++) {
7115957Skarels 		if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 ||
72*16708Smckusick 		    (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
739167Ssam 			continue;
749167Ssam 		ip->i_flag |= ILOCKED;
759167Ssam 		ip->i_count++;
769167Ssam 		iupdat(ip, &time, &time, 0);
779167Ssam 		iput(ip);
789167Ssam 	}
799167Ssam 	updlock = 0;
809167Ssam 	/*
819167Ssam 	 * Force stale buffer cache information to be flushed,
829167Ssam 	 * for all devices.
839167Ssam 	 */
849167Ssam 	bflush(NODEV);
859167Ssam }
869167Ssam 
879167Ssam /*
889167Ssam  * Flush all the blocks associated with an inode.
899167Ssam  * Note that we make a more stringent check of
909167Ssam  * writing out any block in the buffer pool that may
919167Ssam  * overlap the inode. This brings the inode up to
929167Ssam  * date with recent mods to the cooked device.
939167Ssam  */
949167Ssam syncip(ip)
959167Ssam 	register struct inode *ip;
969167Ssam {
979167Ssam 	register struct fs *fs;
989167Ssam 	long lbn, lastlbn;
999167Ssam 	daddr_t blkno;
1009167Ssam 
1019167Ssam 	fs = ip->i_fs;
1029167Ssam 	lastlbn = howmany(ip->i_size, fs->fs_bsize);
1039167Ssam 	for (lbn = 0; lbn < lastlbn; lbn++) {
1049167Ssam 		blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
1059167Ssam 		blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
1069167Ssam 	}
10711637Ssam 	ip->i_flag |= ICHG;
10811637Ssam 	iupdat(ip, &time, &time, 1);
1099167Ssam }
1109167Ssam #endif
1119167Ssam 
1128719Sroot extern	int around[9];
1138719Sroot extern	int inside[9];
1148719Sroot extern	u_char *fragtbl[];
1158719Sroot 
1168719Sroot /*
1178719Sroot  * Update the frsum fields to reflect addition or deletion
1188719Sroot  * of some frags.
1198719Sroot  */
1208719Sroot fragacct(fs, fragmap, fraglist, cnt)
1218719Sroot 	struct fs *fs;
1228719Sroot 	int fragmap;
1238719Sroot 	long fraglist[];
1248719Sroot 	int cnt;
1258719Sroot {
1268719Sroot 	int inblk;
1278719Sroot 	register int field, subfield;
1288719Sroot 	register int siz, pos;
1298719Sroot 
1308719Sroot 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
1318719Sroot 	fragmap <<= 1;
1328719Sroot 	for (siz = 1; siz < fs->fs_frag; siz++) {
1338719Sroot 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
1348719Sroot 			continue;
1358719Sroot 		field = around[siz];
1368719Sroot 		subfield = inside[siz];
1378719Sroot 		for (pos = siz; pos <= fs->fs_frag; pos++) {
1388719Sroot 			if ((fragmap & field) == subfield) {
1398719Sroot 				fraglist[siz] += cnt;
1408719Sroot 				pos += siz;
1418719Sroot 				field <<= siz;
1428719Sroot 				subfield <<= siz;
1438719Sroot 			}
1448719Sroot 			field <<= 1;
1458719Sroot 			subfield <<= 1;
1468719Sroot 		}
1478719Sroot 	}
1488719Sroot }
1498719Sroot 
1508719Sroot #ifdef KERNEL
1518719Sroot /*
1528719Sroot  * Check that a specified block number is in range.
1538719Sroot  */
1548719Sroot badblock(fs, bn)
1558719Sroot 	register struct fs *fs;
1568719Sroot 	daddr_t bn;
1578719Sroot {
1588719Sroot 
1598719Sroot 	if ((unsigned)bn >= fs->fs_size) {
1608719Sroot 		printf("bad block %d, ", bn);
1618719Sroot 		fserr(fs, "bad block");
1628719Sroot 		return (1);
1638719Sroot 	}
1648719Sroot 	return (0);
1658719Sroot }
1668719Sroot #endif
1678719Sroot 
1688719Sroot /*
1698719Sroot  * block operations
1708719Sroot  *
1718719Sroot  * check if a block is available
1728719Sroot  */
1738719Sroot isblock(fs, cp, h)
1748719Sroot 	struct fs *fs;
1758719Sroot 	unsigned char *cp;
1768719Sroot 	daddr_t h;
1778719Sroot {
1788719Sroot 	unsigned char mask;
1798719Sroot 
1808719Sroot 	switch (fs->fs_frag) {
1818719Sroot 	case 8:
1828719Sroot 		return (cp[h] == 0xff);
1838719Sroot 	case 4:
1848719Sroot 		mask = 0x0f << ((h & 0x1) << 2);
1858719Sroot 		return ((cp[h >> 1] & mask) == mask);
1868719Sroot 	case 2:
1878719Sroot 		mask = 0x03 << ((h & 0x3) << 1);
1888719Sroot 		return ((cp[h >> 2] & mask) == mask);
1898719Sroot 	case 1:
1908719Sroot 		mask = 0x01 << (h & 0x7);
1918719Sroot 		return ((cp[h >> 3] & mask) == mask);
1928719Sroot 	default:
1938719Sroot 		panic("isblock");
1948719Sroot 		return (NULL);
1958719Sroot 	}
1968719Sroot }
1978719Sroot 
1988719Sroot /*
1998719Sroot  * take a block out of the map
2008719Sroot  */
2018719Sroot clrblock(fs, cp, h)
2028719Sroot 	struct fs *fs;
2038770Sroot 	u_char *cp;
2048719Sroot 	daddr_t h;
2058719Sroot {
2068719Sroot 
2078719Sroot 	switch ((fs)->fs_frag) {
2088719Sroot 	case 8:
2098719Sroot 		cp[h] = 0;
2108719Sroot 		return;
2118719Sroot 	case 4:
2128719Sroot 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
2138719Sroot 		return;
2148719Sroot 	case 2:
2158719Sroot 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
2168719Sroot 		return;
2178719Sroot 	case 1:
2188719Sroot 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
2198719Sroot 		return;
2208719Sroot 	default:
2218719Sroot 		panic("clrblock");
2228719Sroot 	}
2238719Sroot }
2248719Sroot 
2258719Sroot /*
2268719Sroot  * put a block into the map
2278719Sroot  */
2288719Sroot setblock(fs, cp, h)
2298719Sroot 	struct fs *fs;
2308719Sroot 	unsigned char *cp;
2318719Sroot 	daddr_t h;
2328719Sroot {
2338719Sroot 
2348719Sroot 	switch (fs->fs_frag) {
2358719Sroot 
2368719Sroot 	case 8:
2378719Sroot 		cp[h] = 0xff;
2388719Sroot 		return;
2398719Sroot 	case 4:
2408719Sroot 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
2418719Sroot 		return;
2428719Sroot 	case 2:
2438719Sroot 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
2448719Sroot 		return;
2458719Sroot 	case 1:
2468719Sroot 		cp[h >> 3] |= (0x01 << (h & 0x7));
2478719Sroot 		return;
2488719Sroot 	default:
2498719Sroot 		panic("setblock");
2508719Sroot 	}
2518719Sroot }
2529167Ssam 
2539167Ssam #ifdef KERNEL
2549167Ssam /*
2559167Ssam  * Getfs maps a device number into a pointer to the incore super block.
2569167Ssam  *
2579167Ssam  * The algorithm is a linear search through the mount table. A
2589167Ssam  * consistency check of the super block magic number is performed.
2599167Ssam  *
2609167Ssam  * panic: no fs -- the device is not mounted.
2619167Ssam  *	this "cannot happen"
2629167Ssam  */
2639167Ssam struct fs *
2649167Ssam getfs(dev)
2659167Ssam 	dev_t dev;
2669167Ssam {
2679167Ssam 	register struct mount *mp;
2689167Ssam 	register struct fs *fs;
2699167Ssam 
2709167Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
2719167Ssam 		if (mp->m_bufp == NULL || mp->m_dev != dev)
2729167Ssam 			continue;
2739167Ssam 		fs = mp->m_bufp->b_un.b_fs;
2749167Ssam 		if (fs->fs_magic != FS_MAGIC) {
2759167Ssam 			printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
2769167Ssam 			panic("getfs: bad magic");
2779167Ssam 		}
2789167Ssam 		return (fs);
2799167Ssam 	}
2809167Ssam 	printf("dev = 0x%x\n", dev);
2819167Ssam 	panic("getfs: no fs");
2829167Ssam 	return (NULL);
2839167Ssam }
2849167Ssam 
2859167Ssam /*
2869167Ssam  * Getfsx returns the index in the file system
2879167Ssam  * table of the specified device.  The swap device
2889167Ssam  * is also assigned a pseudo-index.  The index may
2899167Ssam  * be used as a compressed indication of the location
2909167Ssam  * of a block, recording
2919167Ssam  *	<getfsx(dev),blkno>
2929167Ssam  * rather than
2939167Ssam  *	<dev, blkno>
2949167Ssam  * provided the information need remain valid only
2959167Ssam  * as long as the file system is mounted.
2969167Ssam  */
2979167Ssam getfsx(dev)
2989167Ssam 	dev_t dev;
2999167Ssam {
3009167Ssam 	register struct mount *mp;
3019167Ssam 
3029167Ssam 	if (dev == swapdev)
3039167Ssam 		return (MSWAPX);
3049167Ssam 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
3059167Ssam 		if (mp->m_dev == dev)
3069167Ssam 			return (mp - &mount[0]);
3079167Ssam 	return (-1);
3089167Ssam }
3099167Ssam 
3109167Ssam /*
3119167Ssam  * Print out statistics on the current allocation of the buffer pool.
3129167Ssam  * Can be enabled to print out on every ``sync'' by setting "syncprt"
3139167Ssam  * above.
3149167Ssam  */
3159167Ssam bufstats()
3169167Ssam {
3179167Ssam 	int s, i, j, count;
3189167Ssam 	register struct buf *bp, *dp;
3199167Ssam 	int counts[MAXBSIZE/CLBYTES+1];
3209167Ssam 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
3219167Ssam 
3229167Ssam 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
3239167Ssam 		count = 0;
3249167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3259167Ssam 			counts[j] = 0;
3269167Ssam 		s = spl6();
3279167Ssam 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
3289167Ssam 			counts[dp->b_bufsize/CLBYTES]++;
3299167Ssam 			count++;
3309167Ssam 		}
3319167Ssam 		splx(s);
3329167Ssam 		printf("%s: total-%d", bname[i], count);
3339167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3349167Ssam 			if (counts[j] != 0)
3359167Ssam 				printf(", %d-%d", j * CLBYTES, counts[j]);
3369167Ssam 		printf("\n");
3379167Ssam 	}
3389167Ssam }
3399167Ssam #endif
340