xref: /csrg-svn/sys/ufs/ffs/ffs_subr.c (revision 30749)
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.3.1.1 (Berkeley) 04/02/87
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 #ifdef SECSIZE
120 		lastlbn--;
121 		s = fsbtodb(fs, fs->fs_frag);
122 		for (lbn = 0; lbn < lastlbn; lbn++) {
123 			blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
124 			blkflush(ip->i_dev, blkno, s);
125 		}
126 		if (lastlbn >= 0)
127 			blkflush(ip->i_dev, blkno, (int)fsbtodb(fs,
128 			    blksize(fs, ip, lbn) / fs->fs_fsize));
129 #else SECSIZE
130 		for (lbn = 0; lbn < lastlbn; lbn++) {
131 			blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
132 			blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
133 		}
134 #endif SECSIZE
135 	} else {
136 		lastbufp = &buf[nbuf];
137 		for (bp = buf; bp < lastbufp; bp++) {
138 			if (bp->b_dev != ip->i_dev ||
139 			    (bp->b_flags & B_DELWRI) == 0)
140 				continue;
141 			s = splbio();
142 			if (bp->b_flags & B_BUSY) {
143 				bp->b_flags |= B_WANTED;
144 				sleep((caddr_t)bp, PRIBIO+1);
145 				splx(s);
146 				bp--;
147 				continue;
148 			}
149 			splx(s);
150 			notavail(bp);
151 			bwrite(bp);
152 		}
153 	}
154 	iupdat(ip, &time, &time, 1);
155 }
156 #endif
157 
158 extern	int around[9];
159 extern	int inside[9];
160 extern	u_char *fragtbl[];
161 
162 /*
163  * Update the frsum fields to reflect addition or deletion
164  * of some frags.
165  */
166 fragacct(fs, fragmap, fraglist, cnt)
167 	struct fs *fs;
168 	int fragmap;
169 	long fraglist[];
170 	int cnt;
171 {
172 	int inblk;
173 	register int field, subfield;
174 	register int siz, pos;
175 
176 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
177 	fragmap <<= 1;
178 	for (siz = 1; siz < fs->fs_frag; siz++) {
179 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
180 			continue;
181 		field = around[siz];
182 		subfield = inside[siz];
183 		for (pos = siz; pos <= fs->fs_frag; pos++) {
184 			if ((fragmap & field) == subfield) {
185 				fraglist[siz] += cnt;
186 				pos += siz;
187 				field <<= siz;
188 				subfield <<= siz;
189 			}
190 			field <<= 1;
191 			subfield <<= 1;
192 		}
193 	}
194 }
195 
196 #ifdef KERNEL
197 /*
198  * Check that a specified block number is in range.
199  */
200 badblock(fs, bn)
201 	register struct fs *fs;
202 	daddr_t bn;
203 {
204 
205 	if ((unsigned)bn >= fs->fs_size) {
206 		printf("bad block %d, ", bn);
207 		fserr(fs, "bad block");
208 		return (1);
209 	}
210 	return (0);
211 }
212 #endif
213 
214 /*
215  * block operations
216  *
217  * check if a block is available
218  */
219 isblock(fs, cp, h)
220 	struct fs *fs;
221 	unsigned char *cp;
222 	daddr_t h;
223 {
224 	unsigned char mask;
225 
226 	switch ((int)fs->fs_frag) {
227 	case 8:
228 		return (cp[h] == 0xff);
229 	case 4:
230 		mask = 0x0f << ((h & 0x1) << 2);
231 		return ((cp[h >> 1] & mask) == mask);
232 	case 2:
233 		mask = 0x03 << ((h & 0x3) << 1);
234 		return ((cp[h >> 2] & mask) == mask);
235 	case 1:
236 		mask = 0x01 << (h & 0x7);
237 		return ((cp[h >> 3] & mask) == mask);
238 	default:
239 		panic("isblock");
240 		return (NULL);
241 	}
242 }
243 
244 /*
245  * take a block out of the map
246  */
247 clrblock(fs, cp, h)
248 	struct fs *fs;
249 	u_char *cp;
250 	daddr_t h;
251 {
252 
253 	switch ((int)fs->fs_frag) {
254 	case 8:
255 		cp[h] = 0;
256 		return;
257 	case 4:
258 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
259 		return;
260 	case 2:
261 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
262 		return;
263 	case 1:
264 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
265 		return;
266 	default:
267 		panic("clrblock");
268 	}
269 }
270 
271 /*
272  * put a block into the map
273  */
274 setblock(fs, cp, h)
275 	struct fs *fs;
276 	unsigned char *cp;
277 	daddr_t h;
278 {
279 
280 	switch ((int)fs->fs_frag) {
281 
282 	case 8:
283 		cp[h] = 0xff;
284 		return;
285 	case 4:
286 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
287 		return;
288 	case 2:
289 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
290 		return;
291 	case 1:
292 		cp[h >> 3] |= (0x01 << (h & 0x7));
293 		return;
294 	default:
295 		panic("setblock");
296 	}
297 }
298 
299 #ifdef KERNEL
300 /*
301  * Getfs maps a device number into a pointer to the incore super block.
302  *
303  * The algorithm is a linear search through the mount table. A
304  * consistency check of the super block magic number is performed.
305  *
306  * panic: no fs -- the device is not mounted.
307  *	this "cannot happen"
308  */
309 struct fs *
310 getfs(dev)
311 	dev_t dev;
312 {
313 	register struct mount *mp;
314 	register struct fs *fs;
315 
316 	for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
317 		if (mp->m_bufp == NULL || mp->m_dev != dev)
318 			continue;
319 		fs = mp->m_bufp->b_un.b_fs;
320 		if (fs->fs_magic != FS_MAGIC) {
321 			printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
322 			panic("getfs: bad magic");
323 		}
324 		return (fs);
325 	}
326 	printf("dev = 0x%x\n", dev);
327 	panic("getfs: no fs");
328 	return (NULL);
329 }
330 
331 /*
332  * Getfsx returns the index in the file system
333  * table of the specified device.  The swap device
334  * is also assigned a pseudo-index.  The index may
335  * be used as a compressed indication of the location
336  * of a block, recording
337  *	<getfsx(dev),blkno>
338  * rather than
339  *	<dev, blkno>
340  * provided the information need remain valid only
341  * as long as the file system is mounted.
342  */
343 getfsx(dev)
344 	dev_t dev;
345 {
346 	register struct mount *mp;
347 
348 	if (dev == swapdev)
349 		return (MSWAPX);
350 	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
351 		if (mp->m_dev == dev)
352 			return (mp - &mount[0]);
353 	return (-1);
354 }
355 
356 /*
357  * Print out statistics on the current allocation of the buffer pool.
358  * Can be enabled to print out on every ``sync'' by setting "syncprt"
359  * above.
360  */
361 bufstats()
362 {
363 	int s, i, j, count;
364 	register struct buf *bp, *dp;
365 	int counts[MAXBSIZE/CLBYTES+1];
366 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
367 
368 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
369 		count = 0;
370 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
371 			counts[j] = 0;
372 		s = splbio();
373 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
374 			counts[dp->b_bufsize/CLBYTES]++;
375 			count++;
376 		}
377 		splx(s);
378 		printf("%s: total-%d", bname[i], count);
379 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
380 			if (counts[j] != 0)
381 				printf(", %d-%d", j * CLBYTES, counts[j]);
382 		printf("\n");
383 	}
384 }
385 #endif
386 
387 #if (!defined(vax) && !defined(tahoe)) || defined(VAX630)
388 /*
389  * C definitions of special instructions.
390  * Normally expanded with inline.
391  */
392 scanc(size, cp, table, mask)
393 	u_int size;
394 	register u_char *cp, table[];
395 	register u_char mask;
396 {
397 	register u_char *end = &cp[size];
398 
399 	while (cp < end && (table[*cp] & mask) == 0)
400 		cp++;
401 	return (end - cp);
402 }
403 #endif
404 
405 #if !defined(vax) && !defined(tahoe)
406 skpc(mask, size, cp)
407 	register u_char mask;
408 	u_int size;
409 	register u_char *cp;
410 {
411 	register u_char *end = &cp[size];
412 
413 	while (cp < end && *cp == mask)
414 		cp++;
415 	return (end - cp);
416 }
417 
418 locc(mask, size, cp)
419 	register u_char mask;
420 	u_int size;
421 	register u_char *cp;
422 {
423 	register u_char *end = &cp[size];
424 
425 	while (cp < end && *cp != mask)
426 		cp++;
427 	return (end - cp);
428 }
429 #endif
430