xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 34356)
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*34356Skarels  *	@(#)ffs_subr.c	7.6 (Berkeley) 05/19/88
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++) {
58*34356Skarels 		if (mp->m_fs == NULL || mp->m_fs == (struct fs *)1)   /* XXX */
599167Ssam 			continue;
6031659Smckusick 		fs = mp->m_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 	iupdat(ip, &time, &time, 1);
1439167Ssam }
1449167Ssam #endif
1459167Ssam 
1468719Sroot extern	int around[9];
1478719Sroot extern	int inside[9];
1488719Sroot extern	u_char *fragtbl[];
1498719Sroot 
1508719Sroot /*
1518719Sroot  * Update the frsum fields to reflect addition or deletion
1528719Sroot  * of some frags.
1538719Sroot  */
1548719Sroot fragacct(fs, fragmap, fraglist, cnt)
1558719Sroot 	struct fs *fs;
1568719Sroot 	int fragmap;
1578719Sroot 	long fraglist[];
1588719Sroot 	int cnt;
1598719Sroot {
1608719Sroot 	int inblk;
1618719Sroot 	register int field, subfield;
1628719Sroot 	register int siz, pos;
1638719Sroot 
1648719Sroot 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
1658719Sroot 	fragmap <<= 1;
1668719Sroot 	for (siz = 1; siz < fs->fs_frag; siz++) {
1678719Sroot 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
1688719Sroot 			continue;
1698719Sroot 		field = around[siz];
1708719Sroot 		subfield = inside[siz];
1718719Sroot 		for (pos = siz; pos <= fs->fs_frag; pos++) {
1728719Sroot 			if ((fragmap & field) == subfield) {
1738719Sroot 				fraglist[siz] += cnt;
1748719Sroot 				pos += siz;
1758719Sroot 				field <<= siz;
1768719Sroot 				subfield <<= siz;
1778719Sroot 			}
1788719Sroot 			field <<= 1;
1798719Sroot 			subfield <<= 1;
1808719Sroot 		}
1818719Sroot 	}
1828719Sroot }
1838719Sroot 
1848719Sroot #ifdef KERNEL
1858719Sroot /*
1868719Sroot  * Check that a specified block number is in range.
1878719Sroot  */
1888719Sroot badblock(fs, bn)
1898719Sroot 	register struct fs *fs;
1908719Sroot 	daddr_t bn;
1918719Sroot {
1928719Sroot 
1938719Sroot 	if ((unsigned)bn >= fs->fs_size) {
1948719Sroot 		printf("bad block %d, ", bn);
1958719Sroot 		fserr(fs, "bad block");
1968719Sroot 		return (1);
1978719Sroot 	}
1988719Sroot 	return (0);
1998719Sroot }
2008719Sroot #endif
2018719Sroot 
2028719Sroot /*
2038719Sroot  * block operations
2048719Sroot  *
2058719Sroot  * check if a block is available
2068719Sroot  */
2078719Sroot isblock(fs, cp, h)
2088719Sroot 	struct fs *fs;
2098719Sroot 	unsigned char *cp;
2108719Sroot 	daddr_t h;
2118719Sroot {
2128719Sroot 	unsigned char mask;
2138719Sroot 
21426309Skarels 	switch ((int)fs->fs_frag) {
2158719Sroot 	case 8:
2168719Sroot 		return (cp[h] == 0xff);
2178719Sroot 	case 4:
2188719Sroot 		mask = 0x0f << ((h & 0x1) << 2);
2198719Sroot 		return ((cp[h >> 1] & mask) == mask);
2208719Sroot 	case 2:
2218719Sroot 		mask = 0x03 << ((h & 0x3) << 1);
2228719Sroot 		return ((cp[h >> 2] & mask) == mask);
2238719Sroot 	case 1:
2248719Sroot 		mask = 0x01 << (h & 0x7);
2258719Sroot 		return ((cp[h >> 3] & mask) == mask);
2268719Sroot 	default:
2278719Sroot 		panic("isblock");
2288719Sroot 		return (NULL);
2298719Sroot 	}
2308719Sroot }
2318719Sroot 
2328719Sroot /*
2338719Sroot  * take a block out of the map
2348719Sroot  */
2358719Sroot clrblock(fs, cp, h)
2368719Sroot 	struct fs *fs;
2378770Sroot 	u_char *cp;
2388719Sroot 	daddr_t h;
2398719Sroot {
2408719Sroot 
24126309Skarels 	switch ((int)fs->fs_frag) {
2428719Sroot 	case 8:
2438719Sroot 		cp[h] = 0;
2448719Sroot 		return;
2458719Sroot 	case 4:
2468719Sroot 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
2478719Sroot 		return;
2488719Sroot 	case 2:
2498719Sroot 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
2508719Sroot 		return;
2518719Sroot 	case 1:
2528719Sroot 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
2538719Sroot 		return;
2548719Sroot 	default:
2558719Sroot 		panic("clrblock");
2568719Sroot 	}
2578719Sroot }
2588719Sroot 
2598719Sroot /*
2608719Sroot  * put a block into the map
2618719Sroot  */
2628719Sroot setblock(fs, cp, h)
2638719Sroot 	struct fs *fs;
2648719Sroot 	unsigned char *cp;
2658719Sroot 	daddr_t h;
2668719Sroot {
2678719Sroot 
26826309Skarels 	switch ((int)fs->fs_frag) {
2698719Sroot 
2708719Sroot 	case 8:
2718719Sroot 		cp[h] = 0xff;
2728719Sroot 		return;
2738719Sroot 	case 4:
2748719Sroot 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
2758719Sroot 		return;
2768719Sroot 	case 2:
2778719Sroot 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
2788719Sroot 		return;
2798719Sroot 	case 1:
2808719Sroot 		cp[h >> 3] |= (0x01 << (h & 0x7));
2818719Sroot 		return;
2828719Sroot 	default:
2838719Sroot 		panic("setblock");
2848719Sroot 	}
2858719Sroot }
2869167Ssam 
2879167Ssam #ifdef KERNEL
2889167Ssam /*
2899167Ssam  * Getfs maps a device number into a pointer to the incore super block.
2909167Ssam  *
2919167Ssam  * The algorithm is a linear search through the mount table. A
2929167Ssam  * consistency check of the super block magic number is performed.
293*34356Skarels  * Filesystems still working on a mount are skipped.
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++) {
306*34356Skarels 		if (mp->m_dev != dev || mp->m_fs == NULL ||
307*34356Skarels 		    mp->m_fs == (struct fs *)1)			/* XXX */
3089167Ssam 			continue;
30931659Smckusick 		fs = mp->m_fs;
3109167Ssam 		if (fs->fs_magic != FS_MAGIC) {
3119167Ssam 			printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
3129167Ssam 			panic("getfs: bad magic");
3139167Ssam 		}
3149167Ssam 		return (fs);
3159167Ssam 	}
3169167Ssam 	printf("dev = 0x%x\n", dev);
3179167Ssam 	panic("getfs: no fs");
3189167Ssam 	return (NULL);
3199167Ssam }
3209167Ssam 
3219167Ssam /*
3229167Ssam  * Getfsx returns the index in the file system
3239167Ssam  * table of the specified device.  The swap device
3249167Ssam  * is also assigned a pseudo-index.  The index may
3259167Ssam  * be used as a compressed indication of the location
3269167Ssam  * of a block, recording
3279167Ssam  *	<getfsx(dev),blkno>
3289167Ssam  * rather than
3299167Ssam  *	<dev, blkno>
3309167Ssam  * provided the information need remain valid only
3319167Ssam  * as long as the file system is mounted.
3329167Ssam  */
3339167Ssam getfsx(dev)
3349167Ssam 	dev_t dev;
3359167Ssam {
3369167Ssam 	register struct mount *mp;
3379167Ssam 
3389167Ssam 	if (dev == swapdev)
3399167Ssam 		return (MSWAPX);
3409167Ssam 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
3419167Ssam 		if (mp->m_dev == dev)
3429167Ssam 			return (mp - &mount[0]);
3439167Ssam 	return (-1);
3449167Ssam }
3459167Ssam 
3469167Ssam /*
3479167Ssam  * Print out statistics on the current allocation of the buffer pool.
3489167Ssam  * Can be enabled to print out on every ``sync'' by setting "syncprt"
3499167Ssam  * above.
3509167Ssam  */
3519167Ssam bufstats()
3529167Ssam {
3539167Ssam 	int s, i, j, count;
3549167Ssam 	register struct buf *bp, *dp;
3559167Ssam 	int counts[MAXBSIZE/CLBYTES+1];
3569167Ssam 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
3579167Ssam 
3589167Ssam 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
3599167Ssam 		count = 0;
3609167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3619167Ssam 			counts[j] = 0;
36226274Skarels 		s = splbio();
3639167Ssam 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
3649167Ssam 			counts[dp->b_bufsize/CLBYTES]++;
3659167Ssam 			count++;
3669167Ssam 		}
3679167Ssam 		splx(s);
3689167Ssam 		printf("%s: total-%d", bname[i], count);
3699167Ssam 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
3709167Ssam 			if (counts[j] != 0)
3719167Ssam 				printf(", %d-%d", j * CLBYTES, counts[j]);
3729167Ssam 		printf("\n");
3739167Ssam 	}
3749167Ssam }
3759167Ssam #endif
37621090Smckusick 
37729947Skarels #if (!defined(vax) && !defined(tahoe)) || defined(VAX630)
37821090Smckusick /*
37929947Skarels  * C definitions of special instructions.
38029947Skarels  * Normally expanded with inline.
38121090Smckusick  */
38221090Smckusick scanc(size, cp, table, mask)
38321090Smckusick 	u_int size;
38421090Smckusick 	register u_char *cp, table[];
38521090Smckusick 	register u_char mask;
38621090Smckusick {
38721090Smckusick 	register u_char *end = &cp[size];
38821090Smckusick 
38921090Smckusick 	while (cp < end && (table[*cp] & mask) == 0)
39021090Smckusick 		cp++;
39121090Smckusick 	return (end - cp);
39221090Smckusick }
39327476Skridle #endif
39427476Skridle 
39529947Skarels #if !defined(vax) && !defined(tahoe)
39621090Smckusick skpc(mask, size, cp)
39721090Smckusick 	register u_char mask;
39821090Smckusick 	u_int size;
39921090Smckusick 	register u_char *cp;
40021090Smckusick {
40121090Smckusick 	register u_char *end = &cp[size];
40221090Smckusick 
40321090Smckusick 	while (cp < end && *cp == mask)
40421090Smckusick 		cp++;
40521090Smckusick 	return (end - cp);
40621090Smckusick }
40721090Smckusick 
40821090Smckusick locc(mask, size, cp)
40921090Smckusick 	register u_char mask;
41021090Smckusick 	u_int size;
41121090Smckusick 	register u_char *cp;
41221090Smckusick {
41321090Smckusick 	register u_char *end = &cp[size];
41421090Smckusick 
41521090Smckusick 	while (cp < end && *cp != mask)
41621090Smckusick 		cp++;
41721090Smckusick 	return (end - cp);
41821090Smckusick }
41929947Skarels #endif
420