Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
a94023e0 | 6 | * @(#)ffs_subr.c 7.7 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
764e2379 BJ |
8 | |
9 | #ifdef KERNEL | |
94368568 JB |
10 | #include "param.h" |
11 | #include "systm.h" | |
12 | #include "mount.h" | |
13 | #include "fs.h" | |
94368568 JB |
14 | #include "buf.h" |
15 | #include "inode.h" | |
16 | #include "dir.h" | |
17 | #include "user.h" | |
18 | #include "quota.h" | |
19 | #include "kernel.h" | |
764e2379 BJ |
20 | #else |
21 | #include <sys/param.h> | |
4f083fd7 SL |
22 | #include <sys/systm.h> |
23 | #include <sys/mount.h> | |
764e2379 | 24 | #include <sys/fs.h> |
4f083fd7 SL |
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> | |
4f083fd7 SL |
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++) { | |
3649dfe2 | 58 | if (mp->m_fs == NULL || mp->m_fs == (struct fs *)1) /* XXX */ |
4f083fd7 | 59 | continue; |
e4f5c903 | 60 | fs = mp->m_fs; |
4f083fd7 SL |
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++) { | |
d2c01817 | 75 | if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 || |
38601d83 | 76 | (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) |
4f083fd7 SL |
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. | |
9a5e5086 KM |
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. | |
4f083fd7 SL |
105 | */ |
106 | syncip(ip) | |
107 | register struct inode *ip; | |
108 | { | |
109 | register struct fs *fs; | |
9a5e5086 KM |
110 | register struct buf *bp; |
111 | struct buf *lastbufp; | |
a5e62f37 MK |
112 | long lbn, lastlbn; |
113 | int s; | |
4f083fd7 SL |
114 | daddr_t blkno; |
115 | ||
116 | fs = ip->i_fs; | |
117 | lastlbn = howmany(ip->i_size, fs->fs_bsize); | |
9a5e5086 | 118 | if (lastlbn < nbuf / 2) { |
ec67a3ce MK |
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 | |
9a5e5086 KM |
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 | } | |
ec67a3ce | 134 | #endif SECSIZE |
9a5e5086 KM |
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; | |
a5e62f37 | 141 | s = splbio(); |
9a5e5086 KM |
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 | } | |
4f083fd7 | 153 | } |
5b973eee | 154 | iupdat(ip, &time, &time, 1); |
4f083fd7 | 155 | } |
764e2379 BJ |
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 | ||
cae611dc | 226 | switch ((int)fs->fs_frag) { |
764e2379 BJ |
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; | |
39d536e6 | 249 | u_char *cp; |
764e2379 BJ |
250 | daddr_t h; |
251 | { | |
252 | ||
cae611dc | 253 | switch ((int)fs->fs_frag) { |
764e2379 BJ |
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 | ||
cae611dc | 280 | switch ((int)fs->fs_frag) { |
764e2379 BJ |
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 | } | |
4f083fd7 SL |
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. | |
3649dfe2 | 305 | * Filesystems still working on a mount are skipped. |
4f083fd7 SL |
306 | * |
307 | * panic: no fs -- the device is not mounted. | |
308 | * this "cannot happen" | |
309 | */ | |
310 | struct fs * | |
311 | getfs(dev) | |
312 | dev_t dev; | |
313 | { | |
314 | register struct mount *mp; | |
315 | register struct fs *fs; | |
316 | ||
317 | for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { | |
3649dfe2 MK |
318 | if (mp->m_dev != dev || mp->m_fs == NULL || |
319 | mp->m_fs == (struct fs *)1) /* XXX */ | |
4f083fd7 | 320 | continue; |
e4f5c903 | 321 | fs = mp->m_fs; |
4f083fd7 SL |
322 | if (fs->fs_magic != FS_MAGIC) { |
323 | printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); | |
324 | panic("getfs: bad magic"); | |
325 | } | |
326 | return (fs); | |
327 | } | |
328 | printf("dev = 0x%x\n", dev); | |
329 | panic("getfs: no fs"); | |
330 | return (NULL); | |
331 | } | |
332 | ||
333 | /* | |
334 | * Getfsx returns the index in the file system | |
335 | * table of the specified device. The swap device | |
336 | * is also assigned a pseudo-index. The index may | |
337 | * be used as a compressed indication of the location | |
338 | * of a block, recording | |
339 | * <getfsx(dev),blkno> | |
340 | * rather than | |
341 | * <dev, blkno> | |
342 | * provided the information need remain valid only | |
343 | * as long as the file system is mounted. | |
344 | */ | |
345 | getfsx(dev) | |
346 | dev_t dev; | |
347 | { | |
348 | register struct mount *mp; | |
349 | ||
350 | if (dev == swapdev) | |
351 | return (MSWAPX); | |
352 | for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) | |
353 | if (mp->m_dev == dev) | |
354 | return (mp - &mount[0]); | |
355 | return (-1); | |
356 | } | |
357 | ||
358 | /* | |
359 | * Print out statistics on the current allocation of the buffer pool. | |
360 | * Can be enabled to print out on every ``sync'' by setting "syncprt" | |
361 | * above. | |
362 | */ | |
363 | bufstats() | |
364 | { | |
365 | int s, i, j, count; | |
366 | register struct buf *bp, *dp; | |
367 | int counts[MAXBSIZE/CLBYTES+1]; | |
368 | static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; | |
369 | ||
370 | for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { | |
371 | count = 0; | |
372 | for (j = 0; j <= MAXBSIZE/CLBYTES; j++) | |
373 | counts[j] = 0; | |
a5e62f37 | 374 | s = splbio(); |
4f083fd7 SL |
375 | for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { |
376 | counts[dp->b_bufsize/CLBYTES]++; | |
377 | count++; | |
378 | } | |
379 | splx(s); | |
380 | printf("%s: total-%d", bname[i], count); | |
381 | for (j = 0; j <= MAXBSIZE/CLBYTES; j++) | |
382 | if (counts[j] != 0) | |
383 | printf(", %d-%d", j * CLBYTES, counts[j]); | |
384 | printf("\n"); | |
385 | } | |
386 | } | |
387 | #endif | |
8570887c | 388 | |
a94023e0 | 389 | #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650) |
8570887c | 390 | /* |
fb1db32c MK |
391 | * C definitions of special instructions. |
392 | * Normally expanded with inline. | |
8570887c KM |
393 | */ |
394 | scanc(size, cp, table, mask) | |
395 | u_int size; | |
396 | register u_char *cp, table[]; | |
397 | register u_char mask; | |
398 | { | |
399 | register u_char *end = &cp[size]; | |
400 | ||
401 | while (cp < end && (table[*cp] & mask) == 0) | |
402 | cp++; | |
403 | return (end - cp); | |
404 | } | |
ac3e1f5c | 405 | #endif |
ac3e1f5c | 406 | |
fb1db32c | 407 | #if !defined(vax) && !defined(tahoe) |
8570887c KM |
408 | skpc(mask, size, cp) |
409 | register u_char mask; | |
410 | u_int size; | |
411 | register u_char *cp; | |
412 | { | |
413 | register u_char *end = &cp[size]; | |
414 | ||
415 | while (cp < end && *cp == mask) | |
416 | cp++; | |
417 | return (end - cp); | |
418 | } | |
419 | ||
420 | locc(mask, size, cp) | |
421 | register u_char mask; | |
422 | u_int size; | |
423 | register u_char *cp; | |
424 | { | |
425 | register u_char *end = &cp[size]; | |
426 | ||
427 | while (cp < end && *cp != mask) | |
428 | cp++; | |
429 | return (end - cp); | |
430 | } | |
fb1db32c | 431 | #endif |