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