xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 29947)
123402Smckusick /*
229120Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323402Smckusick  * All rights reserved.  The Berkeley software License Agreement
423402Smckusick  * specifies the terms and conditions for redistribution.
523402Smckusick  *
6*29947Skarels  *	@(#)ffs_subr.c	7.2 (Berkeley) 11/03/86
723402Smckusick  */
88719Sroot 
98719Sroot #ifdef KERNEL
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1217101Sbloom #include "mount.h"
1317101Sbloom #include "fs.h"
1417101Sbloom #include "buf.h"
1517101Sbloom #include "inode.h"
1617101Sbloom #include "dir.h"
1717101Sbloom #include "user.h"
1817101Sbloom #include "quota.h"
1917101Sbloom #include "kernel.h"
208719Sroot #else
218719Sroot #include <sys/param.h>
229167Ssam #include <sys/systm.h>
239167Ssam #include <sys/mount.h>
248719Sroot #include <sys/fs.h>
259167Ssam #include <sys/buf.h>
269167Ssam #include <sys/inode.h>
279167Ssam #include <sys/dir.h>
289167Ssam #include <sys/user.h>
299167Ssam #include <sys/quota.h>
308719Sroot #endif
318719Sroot 
329167Ssam #ifdef KERNEL
339167Ssam int	syncprt = 0;
349167Ssam 
359167Ssam /*
369167Ssam  * Update is the internal name of 'sync'.  It goes through the disk
379167Ssam  * queues to initiate sandbagged IO; goes through the inodes to write
389167Ssam  * modified nodes; and it goes through the mount table to initiate
399167Ssam  * the writing of the modified super blocks.
409167Ssam  */
419167Ssam update()
429167Ssam {
439167Ssam 	register struct inode *ip;
449167Ssam 	register struct mount *mp;
459167Ssam 	struct fs *fs;
469167Ssam 
479167Ssam 	if (syncprt)
489167Ssam 		bufstats();
499167Ssam 	if (updlock)
509167Ssam 		return;
519167Ssam 	updlock++;
529167Ssam 	/*
539167Ssam 	 * Write back modified superblocks.
549167Ssam 	 * Consistency check that the superblock
559167Ssam 	 * of each file system is still in the buffer cache.
569167Ssam 	 */
579167Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
589764Ssam 		if (mp->m_bufp == NULL || mp->m_dev == NODEV)
599167Ssam 			continue;
609167Ssam 		fs = mp->m_bufp->b_un.b_fs;
619167Ssam 		if (fs->fs_fmod == 0)
629167Ssam 			continue;
639167Ssam 		if (fs->fs_ronly != 0) {		/* XXX */
649167Ssam 			printf("fs = %s\n", fs->fs_fsmnt);
659167Ssam 			panic("update: rofs mod");
669167Ssam 		}
679167Ssam 		fs->fs_fmod = 0;
689167Ssam 		fs->fs_time = time.tv_sec;
699167Ssam 		sbupdate(mp);
709167Ssam 	}
719167Ssam 	/*
729167Ssam 	 * Write back each (modified) inode.
739167Ssam 	 */
749167Ssam 	for (ip = inode; ip < inodeNINODE; ip++) {
7515957Skarels 		if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 ||
7616708Smckusick 		    (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
779167Ssam 			continue;
789167Ssam 		ip->i_flag |= ILOCKED;
799167Ssam 		ip->i_count++;
809167Ssam 		iupdat(ip, &time, &time, 0);
819167Ssam 		iput(ip);
829167Ssam 	}
839167Ssam 	updlock = 0;
849167Ssam 	/*
859167Ssam 	 * Force stale buffer cache information to be flushed,
869167Ssam 	 * for all devices.
879167Ssam 	 */
889167Ssam 	bflush(NODEV);
899167Ssam }
909167Ssam 
919167Ssam /*
929167Ssam  * Flush all the blocks associated with an inode.
9316861Smckusick  * There are two strategies based on the size of the file;
9416861Smckusick  * large files are those with more than (nbuf / 2) blocks.
9516861Smckusick  * Large files
9616861Smckusick  * 	Walk through the buffer pool and push any dirty pages
9716861Smckusick  *	associated with the device on which the file resides.
9816861Smckusick  * Small files
9916861Smckusick  *	Look up each block in the file to see if it is in the
10016861Smckusick  *	buffer pool writing any that are found to disk.
10116861Smckusick  *	Note that we make a more stringent check of
10216861Smckusick  *	writing out any block in the buffer pool that may
10316861Smckusick  *	overlap the inode. This brings the inode up to
10416861Smckusick  *	date with recent mods to the cooked device.
1059167Ssam  */
1069167Ssam syncip(ip)
1079167Ssam 	register struct inode *ip;
1089167Ssam {
1099167Ssam 	register struct fs *fs;
11016861Smckusick 	register struct buf *bp;
11116861Smckusick 	struct buf *lastbufp;
11226274Skarels 	long lbn, lastlbn;
11326274Skarels 	int s;
1149167Ssam 	daddr_t blkno;
1159167Ssam 
1169167Ssam 	fs = ip->i_fs;
1179167Ssam 	lastlbn = howmany(ip->i_size, fs->fs_bsize);
11816861Smckusick 	if (lastlbn < nbuf / 2) {
11916861Smckusick 		for (lbn = 0; lbn < lastlbn; lbn++) {
12016861Smckusick 			blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
12116861Smckusick 			blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
12216861Smckusick 		}
12316861Smckusick 	} else {
12416861Smckusick 		lastbufp = &buf[nbuf];
12516861Smckusick 		for (bp = buf; bp < lastbufp; bp++) {
12616861Smckusick 			if (bp->b_dev != ip->i_dev ||
12716861Smckusick 			    (bp->b_flags & B_DELWRI) == 0)
12816861Smckusick 				continue;
12926274Skarels 			s = splbio();
13016861Smckusick 			if (bp->b_flags & B_BUSY) {
13116861Smckusick 				bp->b_flags |= B_WANTED;
13216861Smckusick 				sleep((caddr_t)bp, PRIBIO+1);
13316861Smckusick 				splx(s);
13416861Smckusick 				bp--;
13516861Smckusick 				continue;
13616861Smckusick 			}
13716861Smckusick 			splx(s);
13816861Smckusick 			notavail(bp);
13916861Smckusick 			bwrite(bp);
14016861Smckusick 		}
1419167Ssam 	}
14211637Ssam 	ip->i_flag |= ICHG;
14311637Ssam 	iupdat(ip, &time, &time, 1);
1449167Ssam }
1459167Ssam #endif
1469167Ssam 
1478719Sroot extern	int around[9];
1488719Sroot extern	int inside[9];
1498719Sroot extern	u_char *fragtbl[];
1508719Sroot 
1518719Sroot /*
1528719Sroot  * Update the frsum fields to reflect addition or deletion
1538719Sroot  * of some frags.
1548719Sroot  */
1558719Sroot fragacct(fs, fragmap, fraglist, cnt)
1568719Sroot 	struct fs *fs;
1578719Sroot 	int fragmap;
1588719Sroot 	long fraglist[];
1598719Sroot 	int cnt;
1608719Sroot {
1618719Sroot 	int inblk;
1628719Sroot 	register int field, subfield;
1638719Sroot 	register int siz, pos;
1648719Sroot 
1658719Sroot 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
1668719Sroot 	fragmap <<= 1;
1678719Sroot 	for (siz = 1; siz < fs->fs_frag; siz++) {
1688719Sroot 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
1698719Sroot 			continue;
1708719Sroot 		field = around[siz];
1718719Sroot 		subfield = inside[siz];
1728719Sroot 		for (pos = siz; pos <= fs->fs_frag; pos++) {
1738719Sroot 			if ((fragmap & field) == subfield) {
1748719Sroot 				fraglist[siz] += cnt;
1758719Sroot 				pos += siz;
1768719Sroot 				field <<= siz;
1778719Sroot 				subfield <<= siz;
1788719Sroot 			}
1798719Sroot 			field <<= 1;
1808719Sroot 			subfield <<= 1;
1818719Sroot 		}
1828719Sroot 	}
1838719Sroot }
1848719Sroot 
1858719Sroot #ifdef KERNEL
1868719Sroot /*
1878719Sroot  * Check that a specified block number is in range.
1888719Sroot  */
1898719Sroot badblock(fs, bn)
1908719Sroot 	register struct fs *fs;
1918719Sroot 	daddr_t bn;
1928719Sroot {
1938719Sroot 
1948719Sroot 	if ((unsigned)bn >= fs->fs_size) {
1958719Sroot 		printf("bad block %d, ", bn);
1968719Sroot 		fserr(fs, "bad block");
1978719Sroot 		return (1);
1988719Sroot 	}
1998719Sroot 	return (0);
2008719Sroot }
2018719Sroot #endif
2028719Sroot 
2038719Sroot /*
2048719Sroot  * block operations
2058719Sroot  *
2068719Sroot  * check if a block is available
2078719Sroot  */
2088719Sroot isblock(fs, cp, h)
2098719Sroot 	struct fs *fs;
2108719Sroot 	unsigned char *cp;
2118719Sroot 	daddr_t h;
2128719Sroot {
2138719Sroot 	unsigned char mask;
2148719Sroot 
21526309Skarels 	switch ((int)fs->fs_frag) {
2168719Sroot 	case 8:
2178719Sroot 		return (cp[h] == 0xff);
2188719Sroot 	case 4:
2198719Sroot 		mask = 0x0f << ((h & 0x1) << 2);
2208719Sroot 		return ((cp[h >> 1] & mask) == mask);
2218719Sroot 	case 2:
2228719Sroot 		mask = 0x03 << ((h & 0x3) << 1);
2238719Sroot 		return ((cp[h >> 2] & mask) == mask);
2248719Sroot 	case 1:
2258719Sroot 		mask = 0x01 << (h & 0x7);
2268719Sroot 		return ((cp[h >> 3] & mask) == mask);
2278719Sroot 	default:
2288719Sroot 		panic("isblock");
2298719Sroot 		return (NULL);
2308719Sroot 	}
2318719Sroot }
2328719Sroot 
2338719Sroot /*
2348719Sroot  * take a block out of the map
2358719Sroot  */
2368719Sroot clrblock(fs, cp, h)
2378719Sroot 	struct fs *fs;
2388770Sroot 	u_char *cp;
2398719Sroot 	daddr_t h;
2408719Sroot {
2418719Sroot 
24226309Skarels 	switch ((int)fs->fs_frag) {
2438719Sroot 	case 8:
2448719Sroot 		cp[h] = 0;
2458719Sroot 		return;
2468719Sroot 	case 4:
2478719Sroot 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
2488719Sroot 		return;
2498719Sroot 	case 2:
2508719Sroot 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
2518719Sroot 		return;
2528719Sroot 	case 1:
2538719Sroot 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
2548719Sroot 		return;
2558719Sroot 	default:
2568719Sroot 		panic("clrblock");
2578719Sroot 	}
2588719Sroot }
2598719Sroot 
2608719Sroot /*
2618719Sroot  * put a block into the map
2628719Sroot  */
2638719Sroot setblock(fs, cp, h)
2648719Sroot 	struct fs *fs;
2658719Sroot 	unsigned char *cp;
2668719Sroot 	daddr_t h;
2678719Sroot {
2688719Sroot 
26926309Skarels 	switch ((int)fs->fs_frag) {
2708719Sroot 
2718719Sroot 	case 8:
2728719Sroot 		cp[h] = 0xff;
2738719Sroot 		return;
2748719Sroot 	case 4:
2758719Sroot 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
2768719Sroot 		return;
2778719Sroot 	case 2:
2788719Sroot 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
2798719Sroot 		return;
2808719Sroot 	case 1:
2818719Sroot 		cp[h >> 3] |= (0x01 << (h & 0x7));
2828719Sroot 		return;
2838719Sroot 	default:
2848719Sroot 		panic("setblock");
2858719Sroot 	}
2868719Sroot }
2879167Ssam 
2889167Ssam #ifdef KERNEL
2899167Ssam /*
2909167Ssam  * Getfs maps a device number into a pointer to the incore super block.
2919167Ssam  *
2929167Ssam  * The algorithm is a linear search through the mount table. A
2939167Ssam  * consistency check of the super block magic number is performed.
2949167Ssam  *
2959167Ssam  * panic: no fs -- the device is not mounted.
2969167Ssam  *	this "cannot happen"
2979167Ssam  */
2989167Ssam struct fs *
2999167Ssam getfs(dev)
3009167Ssam 	dev_t dev;
3019167Ssam {
3029167Ssam 	register struct mount *mp;
3039167Ssam 	register struct fs *fs;
3049167Ssam 
3059167Ssam 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
3069167Ssam 		if (mp->m_bufp == NULL || mp->m_dev != dev)
3079167Ssam 			continue;
3089167Ssam 		fs = mp->m_bufp->b_un.b_fs;
3099167Ssam 		if (fs->fs_magic != FS_MAGIC) {
3109167Ssam 			printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
3119167Ssam 			panic("getfs: bad magic");
3129167Ssam 		}
3139167Ssam 		return (fs);
3149167Ssam 	}
3159167Ssam 	printf("dev = 0x%x\n", dev);
3169167Ssam 	panic("getfs: no fs");
3179167Ssam 	return (NULL);
3189167Ssam }
3199167Ssam 
3209167Ssam /*
3219167Ssam  * Getfsx returns the index in the file system
3229167Ssam  * table of the specified device.  The swap device
3239167Ssam  * is also assigned a pseudo-index.  The index may
3249167Ssam  * be used as a compressed indication of the location
3259167Ssam  * of a block, recording
3269167Ssam  *	<getfsx(dev),blkno>
3279167Ssam  * rather than
3289167Ssam  *	<dev, blkno>
3299167Ssam  * provided the information need remain valid only
3309167Ssam  * as long as the file system is mounted.
3319167Ssam  */
3329167Ssam getfsx(dev)
3339167Ssam 	dev_t dev;
3349167Ssam {
3359167Ssam 	register struct mount *mp;
3369167Ssam 
3379167Ssam 	if (dev == swapdev)
3389167Ssam 		return (MSWAPX);
3399167Ssam 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
3409167Ssam 		if (mp->m_dev == dev)
3419167Ssam 			return (mp - &mount[0]);
3429167Ssam 	return (-1);
3439167Ssam }
3449167Ssam 
3459167Ssam /*
3469167Ssam  * Print out statistics on the current allocation of the buffer pool.
3479167Ssam  * Can be enabled to print out on every ``sync'' by setting "syncprt"
3489167Ssam  * above.
3499167Ssam  */
3509167Ssam bufstats()
3519167Ssam {
3529167Ssam 	int s, i, j, count;
3539167Ssam 	register struct buf *bp, *dp;
3549167Ssam 	int counts[MAXBSIZE/CLBYTES+1];
3559167Ssam 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
3569167Ssam 
3579167Ssam 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
3589167Ssam 		count = 0;
3599167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3609167Ssam 			counts[j] = 0;
36126274Skarels 		s = splbio();
3629167Ssam 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
3639167Ssam 			counts[dp->b_bufsize/CLBYTES]++;
3649167Ssam 			count++;
3659167Ssam 		}
3669167Ssam 		splx(s);
3679167Ssam 		printf("%s: total-%d", bname[i], count);
3689167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3699167Ssam 			if (counts[j] != 0)
3709167Ssam 				printf(", %d-%d", j * CLBYTES, counts[j]);
3719167Ssam 		printf("\n");
3729167Ssam 	}
3739167Ssam }
3749167Ssam #endif
37521090Smckusick 
376*29947Skarels #if (!defined(vax) && !defined(tahoe)) || defined(VAX630)
37721090Smckusick /*
378*29947Skarels  * C definitions of special instructions.
379*29947Skarels  * Normally expanded with inline.
38021090Smckusick  */
38121090Smckusick scanc(size, cp, table, mask)
38221090Smckusick 	u_int size;
38321090Smckusick 	register u_char *cp, table[];
38421090Smckusick 	register u_char mask;
38521090Smckusick {
38621090Smckusick 	register u_char *end = &cp[size];
38721090Smckusick 
38821090Smckusick 	while (cp < end && (table[*cp] & mask) == 0)
38921090Smckusick 		cp++;
39021090Smckusick 	return (end - cp);
39121090Smckusick }
39227476Skridle #endif
39327476Skridle 
394*29947Skarels #if !defined(vax) && !defined(tahoe)
39521090Smckusick skpc(mask, size, cp)
39621090Smckusick 	register u_char mask;
39721090Smckusick 	u_int size;
39821090Smckusick 	register u_char *cp;
39921090Smckusick {
40021090Smckusick 	register u_char *end = &cp[size];
40121090Smckusick 
40221090Smckusick 	while (cp < end && *cp == mask)
40321090Smckusick 		cp++;
40421090Smckusick 	return (end - cp);
40521090Smckusick }
40621090Smckusick 
40721090Smckusick locc(mask, size, cp)
40821090Smckusick 	register u_char mask;
40921090Smckusick 	u_int size;
41021090Smckusick 	register u_char *cp;
41121090Smckusick {
41221090Smckusick 	register u_char *end = &cp[size];
41321090Smckusick 
41421090Smckusick 	while (cp < end && *cp != mask)
41521090Smckusick 		cp++;
41621090Smckusick 	return (end - cp);
41721090Smckusick }
418*29947Skarels #endif
419