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