xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 37737)
123402Smckusick /*
2*37737Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*37737Smckusick  * All rights reserved.
423402Smckusick  *
5*37737Smckusick  * Redistribution and use in source and binary forms are permitted
6*37737Smckusick  * provided that the above copyright notice and this paragraph are
7*37737Smckusick  * duplicated in all such forms and that any documentation,
8*37737Smckusick  * advertising materials, and other materials related to such
9*37737Smckusick  * distribution and use acknowledge that the software was developed
10*37737Smckusick  * by the University of California, Berkeley.  The name of the
11*37737Smckusick  * University may not be used to endorse or promote products derived
12*37737Smckusick  * from this software without specific prior written permission.
13*37737Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37737Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37737Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37737Smckusick  *
17*37737Smckusick  *	@(#)ffs_subr.c	7.8 (Berkeley) 05/09/89
1823402Smckusick  */
198719Sroot 
208719Sroot #ifdef KERNEL
2117101Sbloom #include "param.h"
2217101Sbloom #include "systm.h"
2317101Sbloom #include "buf.h"
24*37737Smckusick #include "time.h"
2517101Sbloom #include "kernel.h"
26*37737Smckusick #include "file.h"
27*37737Smckusick #include "mount.h"
28*37737Smckusick #include "vnode.h"
29*37737Smckusick #include "../ufs/inode.h"
30*37737Smckusick #include "../ufs/ufsmount.h"
31*37737Smckusick #include "../ufs/fs.h"
32*37737Smckusick #include "../ufs/quota.h"
338719Sroot #else
348719Sroot #include <sys/param.h>
359167Ssam #include <sys/systm.h>
36*37737Smckusick #include <sys/buf.h>
37*37737Smckusick #include <sys/time.h>
38*37737Smckusick #include <sys/file.h>
399167Ssam #include <sys/mount.h>
40*37737Smckusick #include <sys/vnode.h>
41*37737Smckusick #include <ufs/inode.h>
42*37737Smckusick #include <ufs/ufsmount.h>
43*37737Smckusick #include <ufs/fs.h>
44*37737Smckusick #include <ufs/quota.h>
458719Sroot #endif
468719Sroot 
479167Ssam #ifdef KERNEL
489167Ssam /*
499167Ssam  * Flush all the blocks associated with an inode.
5016861Smckusick  * There are two strategies based on the size of the file;
5116861Smckusick  * large files are those with more than (nbuf / 2) blocks.
5216861Smckusick  * Large files
5316861Smckusick  * 	Walk through the buffer pool and push any dirty pages
5416861Smckusick  *	associated with the device on which the file resides.
5516861Smckusick  * Small files
5616861Smckusick  *	Look up each block in the file to see if it is in the
5716861Smckusick  *	buffer pool writing any that are found to disk.
5816861Smckusick  *	Note that we make a more stringent check of
5916861Smckusick  *	writing out any block in the buffer pool that may
6016861Smckusick  *	overlap the inode. This brings the inode up to
6116861Smckusick  *	date with recent mods to the cooked device.
629167Ssam  */
639167Ssam syncip(ip)
649167Ssam 	register struct inode *ip;
659167Ssam {
669167Ssam 	register struct fs *fs;
6716861Smckusick 	register struct buf *bp;
6816861Smckusick 	struct buf *lastbufp;
6926274Skarels 	long lbn, lastlbn;
70*37737Smckusick 	int s, error, allerror = 0;
719167Ssam 	daddr_t blkno;
729167Ssam 
739167Ssam 	fs = ip->i_fs;
749167Ssam 	lastlbn = howmany(ip->i_size, fs->fs_bsize);
7516861Smckusick 	if (lastlbn < nbuf / 2) {
7616861Smckusick 		for (lbn = 0; lbn < lastlbn; lbn++) {
77*37737Smckusick 			error = bmap(ip, lbn, &blkno, (daddr_t *)0, (int *)0);
78*37737Smckusick 			if (error)
79*37737Smckusick 				allerror = error;
80*37737Smckusick 			if (error = blkflush(ip->i_devvp, blkno,
81*37737Smckusick 			    blksize(fs, ip, lbn)))
82*37737Smckusick 				allerror = error;
8316861Smckusick 		}
8416861Smckusick 	} else {
8516861Smckusick 		lastbufp = &buf[nbuf];
8616861Smckusick 		for (bp = buf; bp < lastbufp; bp++) {
8716861Smckusick 			if (bp->b_dev != ip->i_dev ||
8816861Smckusick 			    (bp->b_flags & B_DELWRI) == 0)
8916861Smckusick 				continue;
9026274Skarels 			s = splbio();
9116861Smckusick 			if (bp->b_flags & B_BUSY) {
9216861Smckusick 				bp->b_flags |= B_WANTED;
9316861Smckusick 				sleep((caddr_t)bp, PRIBIO+1);
9416861Smckusick 				splx(s);
9516861Smckusick 				bp--;
9616861Smckusick 				continue;
9716861Smckusick 			}
9816861Smckusick 			splx(s);
9916861Smckusick 			notavail(bp);
100*37737Smckusick 			if (error = bwrite(bp))
101*37737Smckusick 				allerror = error;
10216861Smckusick 		}
1039167Ssam 	}
104*37737Smckusick 	if (error = iupdat(ip, &time, &time, 1))
105*37737Smckusick 		allerror = error;
106*37737Smckusick 	return (allerror);
1079167Ssam }
108*37737Smckusick #endif KERNEL
1099167Ssam 
1108719Sroot extern	int around[9];
1118719Sroot extern	int inside[9];
1128719Sroot extern	u_char *fragtbl[];
1138719Sroot 
1148719Sroot /*
1158719Sroot  * Update the frsum fields to reflect addition or deletion
1168719Sroot  * of some frags.
1178719Sroot  */
1188719Sroot fragacct(fs, fragmap, fraglist, cnt)
1198719Sroot 	struct fs *fs;
1208719Sroot 	int fragmap;
1218719Sroot 	long fraglist[];
1228719Sroot 	int cnt;
1238719Sroot {
1248719Sroot 	int inblk;
1258719Sroot 	register int field, subfield;
1268719Sroot 	register int siz, pos;
1278719Sroot 
1288719Sroot 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
1298719Sroot 	fragmap <<= 1;
1308719Sroot 	for (siz = 1; siz < fs->fs_frag; siz++) {
1318719Sroot 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
1328719Sroot 			continue;
1338719Sroot 		field = around[siz];
1348719Sroot 		subfield = inside[siz];
1358719Sroot 		for (pos = siz; pos <= fs->fs_frag; pos++) {
1368719Sroot 			if ((fragmap & field) == subfield) {
1378719Sroot 				fraglist[siz] += cnt;
1388719Sroot 				pos += siz;
1398719Sroot 				field <<= siz;
1408719Sroot 				subfield <<= siz;
1418719Sroot 			}
1428719Sroot 			field <<= 1;
1438719Sroot 			subfield <<= 1;
1448719Sroot 		}
1458719Sroot 	}
1468719Sroot }
1478719Sroot 
1488719Sroot #ifdef KERNEL
1498719Sroot /*
1508719Sroot  * Check that a specified block number is in range.
1518719Sroot  */
1528719Sroot badblock(fs, bn)
1538719Sroot 	register struct fs *fs;
1548719Sroot 	daddr_t bn;
1558719Sroot {
1568719Sroot 
1578719Sroot 	if ((unsigned)bn >= fs->fs_size) {
1588719Sroot 		printf("bad block %d, ", bn);
1598719Sroot 		fserr(fs, "bad block");
1608719Sroot 		return (1);
1618719Sroot 	}
1628719Sroot 	return (0);
1638719Sroot }
1648719Sroot #endif
1658719Sroot 
1668719Sroot /*
1678719Sroot  * block operations
1688719Sroot  *
1698719Sroot  * check if a block is available
1708719Sroot  */
1718719Sroot isblock(fs, cp, h)
1728719Sroot 	struct fs *fs;
1738719Sroot 	unsigned char *cp;
1748719Sroot 	daddr_t h;
1758719Sroot {
1768719Sroot 	unsigned char mask;
1778719Sroot 
17826309Skarels 	switch ((int)fs->fs_frag) {
1798719Sroot 	case 8:
1808719Sroot 		return (cp[h] == 0xff);
1818719Sroot 	case 4:
1828719Sroot 		mask = 0x0f << ((h & 0x1) << 2);
1838719Sroot 		return ((cp[h >> 1] & mask) == mask);
1848719Sroot 	case 2:
1858719Sroot 		mask = 0x03 << ((h & 0x3) << 1);
1868719Sroot 		return ((cp[h >> 2] & mask) == mask);
1878719Sroot 	case 1:
1888719Sroot 		mask = 0x01 << (h & 0x7);
1898719Sroot 		return ((cp[h >> 3] & mask) == mask);
1908719Sroot 	default:
1918719Sroot 		panic("isblock");
1928719Sroot 		return (NULL);
1938719Sroot 	}
1948719Sroot }
1958719Sroot 
1968719Sroot /*
1978719Sroot  * take a block out of the map
1988719Sroot  */
1998719Sroot clrblock(fs, cp, h)
2008719Sroot 	struct fs *fs;
2018770Sroot 	u_char *cp;
2028719Sroot 	daddr_t h;
2038719Sroot {
2048719Sroot 
20526309Skarels 	switch ((int)fs->fs_frag) {
2068719Sroot 	case 8:
2078719Sroot 		cp[h] = 0;
2088719Sroot 		return;
2098719Sroot 	case 4:
2108719Sroot 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
2118719Sroot 		return;
2128719Sroot 	case 2:
2138719Sroot 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
2148719Sroot 		return;
2158719Sroot 	case 1:
2168719Sroot 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
2178719Sroot 		return;
2188719Sroot 	default:
2198719Sroot 		panic("clrblock");
2208719Sroot 	}
2218719Sroot }
2228719Sroot 
2238719Sroot /*
2248719Sroot  * put a block into the map
2258719Sroot  */
2268719Sroot setblock(fs, cp, h)
2278719Sroot 	struct fs *fs;
2288719Sroot 	unsigned char *cp;
2298719Sroot 	daddr_t h;
2308719Sroot {
2318719Sroot 
23226309Skarels 	switch ((int)fs->fs_frag) {
2338719Sroot 
2348719Sroot 	case 8:
2358719Sroot 		cp[h] = 0xff;
2368719Sroot 		return;
2378719Sroot 	case 4:
2388719Sroot 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
2398719Sroot 		return;
2408719Sroot 	case 2:
2418719Sroot 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
2428719Sroot 		return;
2438719Sroot 	case 1:
2448719Sroot 		cp[h >> 3] |= (0x01 << (h & 0x7));
2458719Sroot 		return;
2468719Sroot 	default:
2478719Sroot 		panic("setblock");
2488719Sroot 	}
2498719Sroot }
2509167Ssam 
2519167Ssam #ifdef KERNEL
2529167Ssam /*
2539167Ssam  * Getfs maps a device number into a pointer to the incore super block.
2549167Ssam  *
2559167Ssam  * The algorithm is a linear search through the mount table. A
2569167Ssam  * consistency check of the super block magic number is performed.
25734356Skarels  * Filesystems still working on a mount are skipped.
2589167Ssam  *
2599167Ssam  * panic: no fs -- the device is not mounted.
2609167Ssam  *	this "cannot happen"
2619167Ssam  */
2629167Ssam struct fs *
2639167Ssam getfs(dev)
2649167Ssam 	dev_t dev;
2659167Ssam {
266*37737Smckusick 	register struct ufsmount *mp;
2679167Ssam 	register struct fs *fs;
2689167Ssam 
269*37737Smckusick 	for (mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) {
270*37737Smckusick 		if (mp->um_fs == NULL || mp->um_dev != dev ||
271*37737Smckusick 		    mp->um_fs == (struct fs *)1)		/* XXX */
2729167Ssam 			continue;
273*37737Smckusick 		fs = mp->um_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 {
300*37737Smckusick 	register struct ufsmount *mp;
3019167Ssam 
3029167Ssam 	if (dev == swapdev)
3039167Ssam 		return (MSWAPX);
304*37737Smckusick 	for(mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++)
305*37737Smckusick 		if (mp->um_dev == dev)
306*37737Smckusick 			return (mp - &mounttab[0]);
3079167Ssam 	return (-1);
3089167Ssam }
3099167Ssam #endif
31021090Smckusick 
31137574Sbostic #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650)
31221090Smckusick /*
31329947Skarels  * C definitions of special instructions.
31429947Skarels  * Normally expanded with inline.
31521090Smckusick  */
31621090Smckusick scanc(size, cp, table, mask)
31721090Smckusick 	u_int size;
31821090Smckusick 	register u_char *cp, table[];
31921090Smckusick 	register u_char mask;
32021090Smckusick {
32121090Smckusick 	register u_char *end = &cp[size];
32221090Smckusick 
32321090Smckusick 	while (cp < end && (table[*cp] & mask) == 0)
32421090Smckusick 		cp++;
32521090Smckusick 	return (end - cp);
32621090Smckusick }
32727476Skridle #endif
32827476Skridle 
32929947Skarels #if !defined(vax) && !defined(tahoe)
33021090Smckusick skpc(mask, size, cp)
33121090Smckusick 	register u_char mask;
33221090Smckusick 	u_int size;
33321090Smckusick 	register u_char *cp;
33421090Smckusick {
33521090Smckusick 	register u_char *end = &cp[size];
33621090Smckusick 
33721090Smckusick 	while (cp < end && *cp == mask)
33821090Smckusick 		cp++;
33921090Smckusick 	return (end - cp);
34021090Smckusick }
34121090Smckusick 
34221090Smckusick locc(mask, size, cp)
34321090Smckusick 	register u_char mask;
34421090Smckusick 	u_int size;
34521090Smckusick 	register u_char *cp;
34621090Smckusick {
34721090Smckusick 	register u_char *end = &cp[size];
34821090Smckusick 
34921090Smckusick 	while (cp < end && *cp != mask)
35021090Smckusick 		cp++;
35121090Smckusick 	return (end - cp);
35221090Smckusick }
35329947Skarels #endif
354