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