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