1*16861Smckusick /* ffs_subr.c 6.4 84/08/09 */ 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 || 7216708Smckusick (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. 89*16861Smckusick * There are two strategies based on the size of the file; 90*16861Smckusick * large files are those with more than (nbuf / 2) blocks. 91*16861Smckusick * Large files 92*16861Smckusick * Walk through the buffer pool and push any dirty pages 93*16861Smckusick * associated with the device on which the file resides. 94*16861Smckusick * Small files 95*16861Smckusick * Look up each block in the file to see if it is in the 96*16861Smckusick * buffer pool writing any that are found to disk. 97*16861Smckusick * Note that we make a more stringent check of 98*16861Smckusick * writing out any block in the buffer pool that may 99*16861Smckusick * overlap the inode. This brings the inode up to 100*16861Smckusick * date with recent mods to the cooked device. 1019167Ssam */ 1029167Ssam syncip(ip) 1039167Ssam register struct inode *ip; 1049167Ssam { 1059167Ssam register struct fs *fs; 106*16861Smckusick register struct buf *bp; 107*16861Smckusick struct buf *lastbufp; 108*16861Smckusick long lbn, lastlbn, s; 1099167Ssam daddr_t blkno; 1109167Ssam 1119167Ssam fs = ip->i_fs; 1129167Ssam lastlbn = howmany(ip->i_size, fs->fs_bsize); 113*16861Smckusick if (lastlbn < nbuf / 2) { 114*16861Smckusick for (lbn = 0; lbn < lastlbn; lbn++) { 115*16861Smckusick blkno = fsbtodb(fs, bmap(ip, lbn, B_READ)); 116*16861Smckusick blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn)); 117*16861Smckusick } 118*16861Smckusick } else { 119*16861Smckusick lastbufp = &buf[nbuf]; 120*16861Smckusick for (bp = buf; bp < lastbufp; bp++) { 121*16861Smckusick if (bp->b_dev != ip->i_dev || 122*16861Smckusick (bp->b_flags & B_DELWRI) == 0) 123*16861Smckusick continue; 124*16861Smckusick s = spl6(); 125*16861Smckusick if (bp->b_flags & B_BUSY) { 126*16861Smckusick bp->b_flags |= B_WANTED; 127*16861Smckusick sleep((caddr_t)bp, PRIBIO+1); 128*16861Smckusick splx(s); 129*16861Smckusick bp--; 130*16861Smckusick continue; 131*16861Smckusick } 132*16861Smckusick splx(s); 133*16861Smckusick notavail(bp); 134*16861Smckusick bwrite(bp); 135*16861Smckusick } 1369167Ssam } 13711637Ssam ip->i_flag |= ICHG; 13811637Ssam iupdat(ip, &time, &time, 1); 1399167Ssam } 1409167Ssam #endif 1419167Ssam 1428719Sroot extern int around[9]; 1438719Sroot extern int inside[9]; 1448719Sroot extern u_char *fragtbl[]; 1458719Sroot 1468719Sroot /* 1478719Sroot * Update the frsum fields to reflect addition or deletion 1488719Sroot * of some frags. 1498719Sroot */ 1508719Sroot fragacct(fs, fragmap, fraglist, cnt) 1518719Sroot struct fs *fs; 1528719Sroot int fragmap; 1538719Sroot long fraglist[]; 1548719Sroot int cnt; 1558719Sroot { 1568719Sroot int inblk; 1578719Sroot register int field, subfield; 1588719Sroot register int siz, pos; 1598719Sroot 1608719Sroot inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 1618719Sroot fragmap <<= 1; 1628719Sroot for (siz = 1; siz < fs->fs_frag; siz++) { 1638719Sroot if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 1648719Sroot continue; 1658719Sroot field = around[siz]; 1668719Sroot subfield = inside[siz]; 1678719Sroot for (pos = siz; pos <= fs->fs_frag; pos++) { 1688719Sroot if ((fragmap & field) == subfield) { 1698719Sroot fraglist[siz] += cnt; 1708719Sroot pos += siz; 1718719Sroot field <<= siz; 1728719Sroot subfield <<= siz; 1738719Sroot } 1748719Sroot field <<= 1; 1758719Sroot subfield <<= 1; 1768719Sroot } 1778719Sroot } 1788719Sroot } 1798719Sroot 1808719Sroot #ifdef KERNEL 1818719Sroot /* 1828719Sroot * Check that a specified block number is in range. 1838719Sroot */ 1848719Sroot badblock(fs, bn) 1858719Sroot register struct fs *fs; 1868719Sroot daddr_t bn; 1878719Sroot { 1888719Sroot 1898719Sroot if ((unsigned)bn >= fs->fs_size) { 1908719Sroot printf("bad block %d, ", bn); 1918719Sroot fserr(fs, "bad block"); 1928719Sroot return (1); 1938719Sroot } 1948719Sroot return (0); 1958719Sroot } 1968719Sroot #endif 1978719Sroot 1988719Sroot /* 1998719Sroot * block operations 2008719Sroot * 2018719Sroot * check if a block is available 2028719Sroot */ 2038719Sroot isblock(fs, cp, h) 2048719Sroot struct fs *fs; 2058719Sroot unsigned char *cp; 2068719Sroot daddr_t h; 2078719Sroot { 2088719Sroot unsigned char mask; 2098719Sroot 2108719Sroot switch (fs->fs_frag) { 2118719Sroot case 8: 2128719Sroot return (cp[h] == 0xff); 2138719Sroot case 4: 2148719Sroot mask = 0x0f << ((h & 0x1) << 2); 2158719Sroot return ((cp[h >> 1] & mask) == mask); 2168719Sroot case 2: 2178719Sroot mask = 0x03 << ((h & 0x3) << 1); 2188719Sroot return ((cp[h >> 2] & mask) == mask); 2198719Sroot case 1: 2208719Sroot mask = 0x01 << (h & 0x7); 2218719Sroot return ((cp[h >> 3] & mask) == mask); 2228719Sroot default: 2238719Sroot panic("isblock"); 2248719Sroot return (NULL); 2258719Sroot } 2268719Sroot } 2278719Sroot 2288719Sroot /* 2298719Sroot * take a block out of the map 2308719Sroot */ 2318719Sroot clrblock(fs, cp, h) 2328719Sroot struct fs *fs; 2338770Sroot u_char *cp; 2348719Sroot daddr_t h; 2358719Sroot { 2368719Sroot 2378719Sroot switch ((fs)->fs_frag) { 2388719Sroot case 8: 2398719Sroot cp[h] = 0; 2408719Sroot return; 2418719Sroot case 4: 2428719Sroot cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 2438719Sroot return; 2448719Sroot case 2: 2458719Sroot cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 2468719Sroot return; 2478719Sroot case 1: 2488719Sroot cp[h >> 3] &= ~(0x01 << (h & 0x7)); 2498719Sroot return; 2508719Sroot default: 2518719Sroot panic("clrblock"); 2528719Sroot } 2538719Sroot } 2548719Sroot 2558719Sroot /* 2568719Sroot * put a block into the map 2578719Sroot */ 2588719Sroot setblock(fs, cp, h) 2598719Sroot struct fs *fs; 2608719Sroot unsigned char *cp; 2618719Sroot daddr_t h; 2628719Sroot { 2638719Sroot 2648719Sroot switch (fs->fs_frag) { 2658719Sroot 2668719Sroot case 8: 2678719Sroot cp[h] = 0xff; 2688719Sroot return; 2698719Sroot case 4: 2708719Sroot cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 2718719Sroot return; 2728719Sroot case 2: 2738719Sroot cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 2748719Sroot return; 2758719Sroot case 1: 2768719Sroot cp[h >> 3] |= (0x01 << (h & 0x7)); 2778719Sroot return; 2788719Sroot default: 2798719Sroot panic("setblock"); 2808719Sroot } 2818719Sroot } 2829167Ssam 2839167Ssam #ifdef KERNEL 2849167Ssam /* 2859167Ssam * Getfs maps a device number into a pointer to the incore super block. 2869167Ssam * 2879167Ssam * The algorithm is a linear search through the mount table. A 2889167Ssam * consistency check of the super block magic number is performed. 2899167Ssam * 2909167Ssam * panic: no fs -- the device is not mounted. 2919167Ssam * this "cannot happen" 2929167Ssam */ 2939167Ssam struct fs * 2949167Ssam getfs(dev) 2959167Ssam dev_t dev; 2969167Ssam { 2979167Ssam register struct mount *mp; 2989167Ssam register struct fs *fs; 2999167Ssam 3009167Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 3019167Ssam if (mp->m_bufp == NULL || mp->m_dev != dev) 3029167Ssam continue; 3039167Ssam fs = mp->m_bufp->b_un.b_fs; 3049167Ssam if (fs->fs_magic != FS_MAGIC) { 3059167Ssam printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); 3069167Ssam panic("getfs: bad magic"); 3079167Ssam } 3089167Ssam return (fs); 3099167Ssam } 3109167Ssam printf("dev = 0x%x\n", dev); 3119167Ssam panic("getfs: no fs"); 3129167Ssam return (NULL); 3139167Ssam } 3149167Ssam 3159167Ssam /* 3169167Ssam * Getfsx returns the index in the file system 3179167Ssam * table of the specified device. The swap device 3189167Ssam * is also assigned a pseudo-index. The index may 3199167Ssam * be used as a compressed indication of the location 3209167Ssam * of a block, recording 3219167Ssam * <getfsx(dev),blkno> 3229167Ssam * rather than 3239167Ssam * <dev, blkno> 3249167Ssam * provided the information need remain valid only 3259167Ssam * as long as the file system is mounted. 3269167Ssam */ 3279167Ssam getfsx(dev) 3289167Ssam dev_t dev; 3299167Ssam { 3309167Ssam register struct mount *mp; 3319167Ssam 3329167Ssam if (dev == swapdev) 3339167Ssam return (MSWAPX); 3349167Ssam for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 3359167Ssam if (mp->m_dev == dev) 3369167Ssam return (mp - &mount[0]); 3379167Ssam return (-1); 3389167Ssam } 3399167Ssam 3409167Ssam /* 3419167Ssam * Print out statistics on the current allocation of the buffer pool. 3429167Ssam * Can be enabled to print out on every ``sync'' by setting "syncprt" 3439167Ssam * above. 3449167Ssam */ 3459167Ssam bufstats() 3469167Ssam { 3479167Ssam int s, i, j, count; 3489167Ssam register struct buf *bp, *dp; 3499167Ssam int counts[MAXBSIZE/CLBYTES+1]; 3509167Ssam static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 3519167Ssam 3529167Ssam for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 3539167Ssam count = 0; 3549167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3559167Ssam counts[j] = 0; 3569167Ssam s = spl6(); 3579167Ssam for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 3589167Ssam counts[dp->b_bufsize/CLBYTES]++; 3599167Ssam count++; 3609167Ssam } 3619167Ssam splx(s); 3629167Ssam printf("%s: total-%d", bname[i], count); 3639167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3649167Ssam if (counts[j] != 0) 3659167Ssam printf(", %d-%d", j * CLBYTES, counts[j]); 3669167Ssam printf("\n"); 3679167Ssam } 3689167Ssam } 3699167Ssam #endif 370