xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 9167)
1 /*	ffs_subr.c	4.3	82/11/13	*/
2 
3 #ifdef KERNEL
4 #include "../h/param.h"
5 #include "../h/systm.h"
6 #include "../h/mount.h"
7 #include "../h/fs.h"
8 #include "../h/conf.h"
9 #include "../h/buf.h"
10 #include "../h/inode.h"
11 #include "../h/dir.h"
12 #include "../h/user.h"
13 #include "../h/quota.h"
14 #include "../h/kernel.h"
15 #else
16 #include <sys/param.h>
17 #include <sys/systm.h>
18 #include <sys/mount.h>
19 #include <sys/fs.h>
20 #include <sys/conf.h>
21 #include <sys/buf.h>
22 #include <sys/inode.h>
23 #include <sys/dir.h>
24 #include <sys/user.h>
25 #include <sys/quota.h>
26 #include <sys/kernel.h>
27 #endif
28 
29 #ifdef KERNEL
30 int	syncprt = 0;
31 
32 /*
33  * Update is the internal name of 'sync'.  It goes through the disk
34  * queues to initiate sandbagged IO; goes through the inodes to write
35  * modified nodes; and it goes through the mount table to initiate
36  * the writing of the modified super blocks.
37  */
38 update()
39 {
40 	register struct inode *ip;
41 	register struct mount *mp;
42 	struct fs *fs;
43 
44 	if (syncprt)
45 		bufstats();
46 	if (updlock)
47 		return;
48 	updlock++;
49 	/*
50 	 * Write back modified superblocks.
51 	 * Consistency check that the superblock
52 	 * of each file system is still in the buffer cache.
53 	 */
54 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
55 		if (mp->m_bufp == NULL)
56 			continue;
57 		fs = mp->m_bufp->b_un.b_fs;
58 		if (fs->fs_fmod == 0)
59 			continue;
60 		if (fs->fs_ronly != 0) {		/* XXX */
61 			printf("fs = %s\n", fs->fs_fsmnt);
62 			panic("update: rofs mod");
63 		}
64 		fs->fs_fmod = 0;
65 		fs->fs_time = time.tv_sec;
66 		sbupdate(mp);
67 	}
68 	/*
69 	 * Write back each (modified) inode.
70 	 */
71 	for (ip = inode; ip < inodeNINODE; ip++) {
72 		if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0)
73 			continue;
74 		ip->i_flag |= ILOCKED;
75 		ip->i_count++;
76 		iupdat(ip, &time, &time, 0);
77 		iput(ip);
78 	}
79 	updlock = 0;
80 	/*
81 	 * Force stale buffer cache information to be flushed,
82 	 * for all devices.
83 	 */
84 	bflush(NODEV);
85 }
86 
87 /*
88  * Flush all the blocks associated with an inode.
89  * Note that we make a more stringent check of
90  * writing out any block in the buffer pool that may
91  * overlap the inode. This brings the inode up to
92  * date with recent mods to the cooked device.
93  */
94 syncip(ip)
95 	register struct inode *ip;
96 {
97 	register struct fs *fs;
98 	long lbn, lastlbn;
99 	daddr_t blkno;
100 
101 	fs = ip->i_fs;
102 	lastlbn = howmany(ip->i_size, fs->fs_bsize);
103 	for (lbn = 0; lbn < lastlbn; lbn++) {
104 		blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
105 		blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
106 	}
107 }
108 #endif
109 
110 extern	int around[9];
111 extern	int inside[9];
112 extern	u_char *fragtbl[];
113 
114 /*
115  * Update the frsum fields to reflect addition or deletion
116  * of some frags.
117  */
118 fragacct(fs, fragmap, fraglist, cnt)
119 	struct fs *fs;
120 	int fragmap;
121 	long fraglist[];
122 	int cnt;
123 {
124 	int inblk;
125 	register int field, subfield;
126 	register int siz, pos;
127 
128 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
129 	fragmap <<= 1;
130 	for (siz = 1; siz < fs->fs_frag; siz++) {
131 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
132 			continue;
133 		field = around[siz];
134 		subfield = inside[siz];
135 		for (pos = siz; pos <= fs->fs_frag; pos++) {
136 			if ((fragmap & field) == subfield) {
137 				fraglist[siz] += cnt;
138 				pos += siz;
139 				field <<= siz;
140 				subfield <<= siz;
141 			}
142 			field <<= 1;
143 			subfield <<= 1;
144 		}
145 	}
146 }
147 
148 #ifdef KERNEL
149 /*
150  * Check that a specified block number is in range.
151  */
152 badblock(fs, bn)
153 	register struct fs *fs;
154 	daddr_t bn;
155 {
156 
157 	if ((unsigned)bn >= fs->fs_size) {
158 		printf("bad block %d, ", bn);
159 		fserr(fs, "bad block");
160 		return (1);
161 	}
162 	return (0);
163 }
164 #endif
165 
166 /*
167  * block operations
168  *
169  * check if a block is available
170  */
171 isblock(fs, cp, h)
172 	struct fs *fs;
173 	unsigned char *cp;
174 	daddr_t h;
175 {
176 	unsigned char mask;
177 
178 	switch (fs->fs_frag) {
179 	case 8:
180 		return (cp[h] == 0xff);
181 	case 4:
182 		mask = 0x0f << ((h & 0x1) << 2);
183 		return ((cp[h >> 1] & mask) == mask);
184 	case 2:
185 		mask = 0x03 << ((h & 0x3) << 1);
186 		return ((cp[h >> 2] & mask) == mask);
187 	case 1:
188 		mask = 0x01 << (h & 0x7);
189 		return ((cp[h >> 3] & mask) == mask);
190 	default:
191 		panic("isblock");
192 		return (NULL);
193 	}
194 }
195 
196 /*
197  * take a block out of the map
198  */
199 clrblock(fs, cp, h)
200 	struct fs *fs;
201 	u_char *cp;
202 	daddr_t h;
203 {
204 
205 	switch ((fs)->fs_frag) {
206 	case 8:
207 		cp[h] = 0;
208 		return;
209 	case 4:
210 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
211 		return;
212 	case 2:
213 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
214 		return;
215 	case 1:
216 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
217 		return;
218 	default:
219 		panic("clrblock");
220 	}
221 }
222 
223 /*
224  * put a block into the map
225  */
226 setblock(fs, cp, h)
227 	struct fs *fs;
228 	unsigned char *cp;
229 	daddr_t h;
230 {
231 
232 	switch (fs->fs_frag) {
233 
234 	case 8:
235 		cp[h] = 0xff;
236 		return;
237 	case 4:
238 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
239 		return;
240 	case 2:
241 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
242 		return;
243 	case 1:
244 		cp[h >> 3] |= (0x01 << (h & 0x7));
245 		return;
246 	default:
247 		panic("setblock");
248 	}
249 }
250 
251 #ifdef KERNEL
252 /*
253  * Getfs maps a device number into a pointer to the incore super block.
254  *
255  * The algorithm is a linear search through the mount table. A
256  * consistency check of the super block magic number is performed.
257  *
258  * panic: no fs -- the device is not mounted.
259  *	this "cannot happen"
260  */
261 struct fs *
262 getfs(dev)
263 	dev_t dev;
264 {
265 	register struct mount *mp;
266 	register struct fs *fs;
267 
268 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
269 		if (mp->m_bufp == NULL || mp->m_dev != dev)
270 			continue;
271 		fs = mp->m_bufp->b_un.b_fs;
272 		if (fs->fs_magic != FS_MAGIC) {
273 			printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
274 			panic("getfs: bad magic");
275 		}
276 		return (fs);
277 	}
278 	printf("dev = 0x%x\n", dev);
279 	panic("getfs: no fs");
280 	return (NULL);
281 }
282 
283 /*
284  * Getfsx returns the index in the file system
285  * table of the specified device.  The swap device
286  * is also assigned a pseudo-index.  The index may
287  * be used as a compressed indication of the location
288  * of a block, recording
289  *	<getfsx(dev),blkno>
290  * rather than
291  *	<dev, blkno>
292  * provided the information need remain valid only
293  * as long as the file system is mounted.
294  */
295 getfsx(dev)
296 	dev_t dev;
297 {
298 	register struct mount *mp;
299 
300 	if (dev == swapdev)
301 		return (MSWAPX);
302 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
303 		if (mp->m_dev == dev)
304 			return (mp - &mount[0]);
305 	return (-1);
306 }
307 
308 /*
309  * Print out statistics on the current allocation of the buffer pool.
310  * Can be enabled to print out on every ``sync'' by setting "syncprt"
311  * above.
312  */
313 bufstats()
314 {
315 	int s, i, j, count;
316 	register struct buf *bp, *dp;
317 	int counts[MAXBSIZE/CLBYTES+1];
318 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
319 
320 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
321 		count = 0;
322 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
323 			counts[j] = 0;
324 		s = spl6();
325 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
326 			counts[dp->b_bufsize/CLBYTES]++;
327 			count++;
328 		}
329 		splx(s);
330 		printf("%s: total-%d", bname[i], count);
331 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
332 			if (counts[j] != 0)
333 				printf(", %d-%d", j * CLBYTES, counts[j]);
334 		printf("\n");
335 	}
336 }
337 #endif
338