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