1*16708Smckusick /* ffs_subr.c 6.3 84/07/10 */ 28719Sroot 38719Sroot #ifdef KERNEL 48719Sroot #include "../h/param.h" 59167Ssam #include "../h/systm.h" 69167Ssam #include "../h/mount.h" 78719Sroot #include "../h/fs.h" 89167Ssam #include "../h/conf.h" 99167Ssam #include "../h/buf.h" 109167Ssam #include "../h/inode.h" 119167Ssam #include "../h/dir.h" 129167Ssam #include "../h/user.h" 139167Ssam #include "../h/quota.h" 149167Ssam #include "../h/kernel.h" 158719Sroot #else 168719Sroot #include <sys/param.h> 179167Ssam #include <sys/systm.h> 189167Ssam #include <sys/mount.h> 198719Sroot #include <sys/fs.h> 209167Ssam #include <sys/conf.h> 219167Ssam #include <sys/buf.h> 229167Ssam #include <sys/inode.h> 239167Ssam #include <sys/dir.h> 249167Ssam #include <sys/user.h> 259167Ssam #include <sys/quota.h> 268719Sroot #endif 278719Sroot 289167Ssam #ifdef KERNEL 299167Ssam int syncprt = 0; 309167Ssam 319167Ssam /* 329167Ssam * Update is the internal name of 'sync'. It goes through the disk 339167Ssam * queues to initiate sandbagged IO; goes through the inodes to write 349167Ssam * modified nodes; and it goes through the mount table to initiate 359167Ssam * the writing of the modified super blocks. 369167Ssam */ 379167Ssam update() 389167Ssam { 399167Ssam register struct inode *ip; 409167Ssam register struct mount *mp; 419167Ssam struct fs *fs; 429167Ssam 439167Ssam if (syncprt) 449167Ssam bufstats(); 459167Ssam if (updlock) 469167Ssam return; 479167Ssam updlock++; 489167Ssam /* 499167Ssam * Write back modified superblocks. 509167Ssam * Consistency check that the superblock 519167Ssam * of each file system is still in the buffer cache. 529167Ssam */ 539167Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 549764Ssam if (mp->m_bufp == NULL || mp->m_dev == NODEV) 559167Ssam continue; 569167Ssam fs = mp->m_bufp->b_un.b_fs; 579167Ssam if (fs->fs_fmod == 0) 589167Ssam continue; 599167Ssam if (fs->fs_ronly != 0) { /* XXX */ 609167Ssam printf("fs = %s\n", fs->fs_fsmnt); 619167Ssam panic("update: rofs mod"); 629167Ssam } 639167Ssam fs->fs_fmod = 0; 649167Ssam fs->fs_time = time.tv_sec; 659167Ssam sbupdate(mp); 669167Ssam } 679167Ssam /* 689167Ssam * Write back each (modified) inode. 699167Ssam */ 709167Ssam for (ip = inode; ip < inodeNINODE; ip++) { 7115957Skarels if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 || 72*16708Smckusick (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) 739167Ssam continue; 749167Ssam ip->i_flag |= ILOCKED; 759167Ssam ip->i_count++; 769167Ssam iupdat(ip, &time, &time, 0); 779167Ssam iput(ip); 789167Ssam } 799167Ssam updlock = 0; 809167Ssam /* 819167Ssam * Force stale buffer cache information to be flushed, 829167Ssam * for all devices. 839167Ssam */ 849167Ssam bflush(NODEV); 859167Ssam } 869167Ssam 879167Ssam /* 889167Ssam * Flush all the blocks associated with an inode. 899167Ssam * Note that we make a more stringent check of 909167Ssam * writing out any block in the buffer pool that may 919167Ssam * overlap the inode. This brings the inode up to 929167Ssam * date with recent mods to the cooked device. 939167Ssam */ 949167Ssam syncip(ip) 959167Ssam register struct inode *ip; 969167Ssam { 979167Ssam register struct fs *fs; 989167Ssam long lbn, lastlbn; 999167Ssam daddr_t blkno; 1009167Ssam 1019167Ssam fs = ip->i_fs; 1029167Ssam lastlbn = howmany(ip->i_size, fs->fs_bsize); 1039167Ssam for (lbn = 0; lbn < lastlbn; lbn++) { 1049167Ssam blkno = fsbtodb(fs, bmap(ip, lbn, B_READ)); 1059167Ssam blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn)); 1069167Ssam } 10711637Ssam ip->i_flag |= ICHG; 10811637Ssam iupdat(ip, &time, &time, 1); 1099167Ssam } 1109167Ssam #endif 1119167Ssam 1128719Sroot extern int around[9]; 1138719Sroot extern int inside[9]; 1148719Sroot extern u_char *fragtbl[]; 1158719Sroot 1168719Sroot /* 1178719Sroot * Update the frsum fields to reflect addition or deletion 1188719Sroot * of some frags. 1198719Sroot */ 1208719Sroot fragacct(fs, fragmap, fraglist, cnt) 1218719Sroot struct fs *fs; 1228719Sroot int fragmap; 1238719Sroot long fraglist[]; 1248719Sroot int cnt; 1258719Sroot { 1268719Sroot int inblk; 1278719Sroot register int field, subfield; 1288719Sroot register int siz, pos; 1298719Sroot 1308719Sroot inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 1318719Sroot fragmap <<= 1; 1328719Sroot for (siz = 1; siz < fs->fs_frag; siz++) { 1338719Sroot if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 1348719Sroot continue; 1358719Sroot field = around[siz]; 1368719Sroot subfield = inside[siz]; 1378719Sroot for (pos = siz; pos <= fs->fs_frag; pos++) { 1388719Sroot if ((fragmap & field) == subfield) { 1398719Sroot fraglist[siz] += cnt; 1408719Sroot pos += siz; 1418719Sroot field <<= siz; 1428719Sroot subfield <<= siz; 1438719Sroot } 1448719Sroot field <<= 1; 1458719Sroot subfield <<= 1; 1468719Sroot } 1478719Sroot } 1488719Sroot } 1498719Sroot 1508719Sroot #ifdef KERNEL 1518719Sroot /* 1528719Sroot * Check that a specified block number is in range. 1538719Sroot */ 1548719Sroot badblock(fs, bn) 1558719Sroot register struct fs *fs; 1568719Sroot daddr_t bn; 1578719Sroot { 1588719Sroot 1598719Sroot if ((unsigned)bn >= fs->fs_size) { 1608719Sroot printf("bad block %d, ", bn); 1618719Sroot fserr(fs, "bad block"); 1628719Sroot return (1); 1638719Sroot } 1648719Sroot return (0); 1658719Sroot } 1668719Sroot #endif 1678719Sroot 1688719Sroot /* 1698719Sroot * block operations 1708719Sroot * 1718719Sroot * check if a block is available 1728719Sroot */ 1738719Sroot isblock(fs, cp, h) 1748719Sroot struct fs *fs; 1758719Sroot unsigned char *cp; 1768719Sroot daddr_t h; 1778719Sroot { 1788719Sroot unsigned char mask; 1798719Sroot 1808719Sroot switch (fs->fs_frag) { 1818719Sroot case 8: 1828719Sroot return (cp[h] == 0xff); 1838719Sroot case 4: 1848719Sroot mask = 0x0f << ((h & 0x1) << 2); 1858719Sroot return ((cp[h >> 1] & mask) == mask); 1868719Sroot case 2: 1878719Sroot mask = 0x03 << ((h & 0x3) << 1); 1888719Sroot return ((cp[h >> 2] & mask) == mask); 1898719Sroot case 1: 1908719Sroot mask = 0x01 << (h & 0x7); 1918719Sroot return ((cp[h >> 3] & mask) == mask); 1928719Sroot default: 1938719Sroot panic("isblock"); 1948719Sroot return (NULL); 1958719Sroot } 1968719Sroot } 1978719Sroot 1988719Sroot /* 1998719Sroot * take a block out of the map 2008719Sroot */ 2018719Sroot clrblock(fs, cp, h) 2028719Sroot struct fs *fs; 2038770Sroot u_char *cp; 2048719Sroot daddr_t h; 2058719Sroot { 2068719Sroot 2078719Sroot switch ((fs)->fs_frag) { 2088719Sroot case 8: 2098719Sroot cp[h] = 0; 2108719Sroot return; 2118719Sroot case 4: 2128719Sroot cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 2138719Sroot return; 2148719Sroot case 2: 2158719Sroot cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 2168719Sroot return; 2178719Sroot case 1: 2188719Sroot cp[h >> 3] &= ~(0x01 << (h & 0x7)); 2198719Sroot return; 2208719Sroot default: 2218719Sroot panic("clrblock"); 2228719Sroot } 2238719Sroot } 2248719Sroot 2258719Sroot /* 2268719Sroot * put a block into the map 2278719Sroot */ 2288719Sroot setblock(fs, cp, h) 2298719Sroot struct fs *fs; 2308719Sroot unsigned char *cp; 2318719Sroot daddr_t h; 2328719Sroot { 2338719Sroot 2348719Sroot switch (fs->fs_frag) { 2358719Sroot 2368719Sroot case 8: 2378719Sroot cp[h] = 0xff; 2388719Sroot return; 2398719Sroot case 4: 2408719Sroot cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 2418719Sroot return; 2428719Sroot case 2: 2438719Sroot cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 2448719Sroot return; 2458719Sroot case 1: 2468719Sroot cp[h >> 3] |= (0x01 << (h & 0x7)); 2478719Sroot return; 2488719Sroot default: 2498719Sroot panic("setblock"); 2508719Sroot } 2518719Sroot } 2529167Ssam 2539167Ssam #ifdef KERNEL 2549167Ssam /* 2559167Ssam * Getfs maps a device number into a pointer to the incore super block. 2569167Ssam * 2579167Ssam * The algorithm is a linear search through the mount table. A 2589167Ssam * consistency check of the super block magic number is performed. 2599167Ssam * 2609167Ssam * panic: no fs -- the device is not mounted. 2619167Ssam * this "cannot happen" 2629167Ssam */ 2639167Ssam struct fs * 2649167Ssam getfs(dev) 2659167Ssam dev_t dev; 2669167Ssam { 2679167Ssam register struct mount *mp; 2689167Ssam register struct fs *fs; 2699167Ssam 2709167Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 2719167Ssam if (mp->m_bufp == NULL || mp->m_dev != dev) 2729167Ssam continue; 2739167Ssam fs = mp->m_bufp->b_un.b_fs; 2749167Ssam if (fs->fs_magic != FS_MAGIC) { 2759167Ssam printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); 2769167Ssam panic("getfs: bad magic"); 2779167Ssam } 2789167Ssam return (fs); 2799167Ssam } 2809167Ssam printf("dev = 0x%x\n", dev); 2819167Ssam panic("getfs: no fs"); 2829167Ssam return (NULL); 2839167Ssam } 2849167Ssam 2859167Ssam /* 2869167Ssam * Getfsx returns the index in the file system 2879167Ssam * table of the specified device. The swap device 2889167Ssam * is also assigned a pseudo-index. The index may 2899167Ssam * be used as a compressed indication of the location 2909167Ssam * of a block, recording 2919167Ssam * <getfsx(dev),blkno> 2929167Ssam * rather than 2939167Ssam * <dev, blkno> 2949167Ssam * provided the information need remain valid only 2959167Ssam * as long as the file system is mounted. 2969167Ssam */ 2979167Ssam getfsx(dev) 2989167Ssam dev_t dev; 2999167Ssam { 3009167Ssam register struct mount *mp; 3019167Ssam 3029167Ssam if (dev == swapdev) 3039167Ssam return (MSWAPX); 3049167Ssam for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 3059167Ssam if (mp->m_dev == dev) 3069167Ssam return (mp - &mount[0]); 3079167Ssam return (-1); 3089167Ssam } 3099167Ssam 3109167Ssam /* 3119167Ssam * Print out statistics on the current allocation of the buffer pool. 3129167Ssam * Can be enabled to print out on every ``sync'' by setting "syncprt" 3139167Ssam * above. 3149167Ssam */ 3159167Ssam bufstats() 3169167Ssam { 3179167Ssam int s, i, j, count; 3189167Ssam register struct buf *bp, *dp; 3199167Ssam int counts[MAXBSIZE/CLBYTES+1]; 3209167Ssam static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 3219167Ssam 3229167Ssam for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 3239167Ssam count = 0; 3249167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3259167Ssam counts[j] = 0; 3269167Ssam s = spl6(); 3279167Ssam for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 3289167Ssam counts[dp->b_bufsize/CLBYTES]++; 3299167Ssam count++; 3309167Ssam } 3319167Ssam splx(s); 3329167Ssam printf("%s: total-%d", bname[i], count); 3339167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3349167Ssam if (counts[j] != 0) 3359167Ssam printf(", %d-%d", j * CLBYTES, counts[j]); 3369167Ssam printf("\n"); 3379167Ssam } 3389167Ssam } 3399167Ssam #endif 340