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