123402Smckusick /* 229120Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323402Smckusick * All rights reserved. The Berkeley software License Agreement 423402Smckusick * specifies the terms and conditions for redistribution. 523402Smckusick * 6*29947Skarels * @(#)ffs_subr.c 7.2 (Berkeley) 11/03/86 723402Smckusick */ 88719Sroot 98719Sroot #ifdef KERNEL 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1217101Sbloom #include "mount.h" 1317101Sbloom #include "fs.h" 1417101Sbloom #include "buf.h" 1517101Sbloom #include "inode.h" 1617101Sbloom #include "dir.h" 1717101Sbloom #include "user.h" 1817101Sbloom #include "quota.h" 1917101Sbloom #include "kernel.h" 208719Sroot #else 218719Sroot #include <sys/param.h> 229167Ssam #include <sys/systm.h> 239167Ssam #include <sys/mount.h> 248719Sroot #include <sys/fs.h> 259167Ssam #include <sys/buf.h> 269167Ssam #include <sys/inode.h> 279167Ssam #include <sys/dir.h> 289167Ssam #include <sys/user.h> 299167Ssam #include <sys/quota.h> 308719Sroot #endif 318719Sroot 329167Ssam #ifdef KERNEL 339167Ssam int syncprt = 0; 349167Ssam 359167Ssam /* 369167Ssam * Update is the internal name of 'sync'. It goes through the disk 379167Ssam * queues to initiate sandbagged IO; goes through the inodes to write 389167Ssam * modified nodes; and it goes through the mount table to initiate 399167Ssam * the writing of the modified super blocks. 409167Ssam */ 419167Ssam update() 429167Ssam { 439167Ssam register struct inode *ip; 449167Ssam register struct mount *mp; 459167Ssam struct fs *fs; 469167Ssam 479167Ssam if (syncprt) 489167Ssam bufstats(); 499167Ssam if (updlock) 509167Ssam return; 519167Ssam updlock++; 529167Ssam /* 539167Ssam * Write back modified superblocks. 549167Ssam * Consistency check that the superblock 559167Ssam * of each file system is still in the buffer cache. 569167Ssam */ 579167Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 589764Ssam if (mp->m_bufp == NULL || mp->m_dev == NODEV) 599167Ssam continue; 609167Ssam fs = mp->m_bufp->b_un.b_fs; 619167Ssam if (fs->fs_fmod == 0) 629167Ssam continue; 639167Ssam if (fs->fs_ronly != 0) { /* XXX */ 649167Ssam printf("fs = %s\n", fs->fs_fsmnt); 659167Ssam panic("update: rofs mod"); 669167Ssam } 679167Ssam fs->fs_fmod = 0; 689167Ssam fs->fs_time = time.tv_sec; 699167Ssam sbupdate(mp); 709167Ssam } 719167Ssam /* 729167Ssam * Write back each (modified) inode. 739167Ssam */ 749167Ssam for (ip = inode; ip < inodeNINODE; ip++) { 7515957Skarels if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 || 7616708Smckusick (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) 779167Ssam continue; 789167Ssam ip->i_flag |= ILOCKED; 799167Ssam ip->i_count++; 809167Ssam iupdat(ip, &time, &time, 0); 819167Ssam iput(ip); 829167Ssam } 839167Ssam updlock = 0; 849167Ssam /* 859167Ssam * Force stale buffer cache information to be flushed, 869167Ssam * for all devices. 879167Ssam */ 889167Ssam bflush(NODEV); 899167Ssam } 909167Ssam 919167Ssam /* 929167Ssam * Flush all the blocks associated with an inode. 9316861Smckusick * There are two strategies based on the size of the file; 9416861Smckusick * large files are those with more than (nbuf / 2) blocks. 9516861Smckusick * Large files 9616861Smckusick * Walk through the buffer pool and push any dirty pages 9716861Smckusick * associated with the device on which the file resides. 9816861Smckusick * Small files 9916861Smckusick * Look up each block in the file to see if it is in the 10016861Smckusick * buffer pool writing any that are found to disk. 10116861Smckusick * Note that we make a more stringent check of 10216861Smckusick * writing out any block in the buffer pool that may 10316861Smckusick * overlap the inode. This brings the inode up to 10416861Smckusick * date with recent mods to the cooked device. 1059167Ssam */ 1069167Ssam syncip(ip) 1079167Ssam register struct inode *ip; 1089167Ssam { 1099167Ssam register struct fs *fs; 11016861Smckusick register struct buf *bp; 11116861Smckusick struct buf *lastbufp; 11226274Skarels long lbn, lastlbn; 11326274Skarels int s; 1149167Ssam daddr_t blkno; 1159167Ssam 1169167Ssam fs = ip->i_fs; 1179167Ssam lastlbn = howmany(ip->i_size, fs->fs_bsize); 11816861Smckusick if (lastlbn < nbuf / 2) { 11916861Smckusick for (lbn = 0; lbn < lastlbn; lbn++) { 12016861Smckusick blkno = fsbtodb(fs, bmap(ip, lbn, B_READ)); 12116861Smckusick blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn)); 12216861Smckusick } 12316861Smckusick } else { 12416861Smckusick lastbufp = &buf[nbuf]; 12516861Smckusick for (bp = buf; bp < lastbufp; bp++) { 12616861Smckusick if (bp->b_dev != ip->i_dev || 12716861Smckusick (bp->b_flags & B_DELWRI) == 0) 12816861Smckusick continue; 12926274Skarels s = splbio(); 13016861Smckusick if (bp->b_flags & B_BUSY) { 13116861Smckusick bp->b_flags |= B_WANTED; 13216861Smckusick sleep((caddr_t)bp, PRIBIO+1); 13316861Smckusick splx(s); 13416861Smckusick bp--; 13516861Smckusick continue; 13616861Smckusick } 13716861Smckusick splx(s); 13816861Smckusick notavail(bp); 13916861Smckusick bwrite(bp); 14016861Smckusick } 1419167Ssam } 14211637Ssam ip->i_flag |= ICHG; 14311637Ssam iupdat(ip, &time, &time, 1); 1449167Ssam } 1459167Ssam #endif 1469167Ssam 1478719Sroot extern int around[9]; 1488719Sroot extern int inside[9]; 1498719Sroot extern u_char *fragtbl[]; 1508719Sroot 1518719Sroot /* 1528719Sroot * Update the frsum fields to reflect addition or deletion 1538719Sroot * of some frags. 1548719Sroot */ 1558719Sroot fragacct(fs, fragmap, fraglist, cnt) 1568719Sroot struct fs *fs; 1578719Sroot int fragmap; 1588719Sroot long fraglist[]; 1598719Sroot int cnt; 1608719Sroot { 1618719Sroot int inblk; 1628719Sroot register int field, subfield; 1638719Sroot register int siz, pos; 1648719Sroot 1658719Sroot inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 1668719Sroot fragmap <<= 1; 1678719Sroot for (siz = 1; siz < fs->fs_frag; siz++) { 1688719Sroot if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 1698719Sroot continue; 1708719Sroot field = around[siz]; 1718719Sroot subfield = inside[siz]; 1728719Sroot for (pos = siz; pos <= fs->fs_frag; pos++) { 1738719Sroot if ((fragmap & field) == subfield) { 1748719Sroot fraglist[siz] += cnt; 1758719Sroot pos += siz; 1768719Sroot field <<= siz; 1778719Sroot subfield <<= siz; 1788719Sroot } 1798719Sroot field <<= 1; 1808719Sroot subfield <<= 1; 1818719Sroot } 1828719Sroot } 1838719Sroot } 1848719Sroot 1858719Sroot #ifdef KERNEL 1868719Sroot /* 1878719Sroot * Check that a specified block number is in range. 1888719Sroot */ 1898719Sroot badblock(fs, bn) 1908719Sroot register struct fs *fs; 1918719Sroot daddr_t bn; 1928719Sroot { 1938719Sroot 1948719Sroot if ((unsigned)bn >= fs->fs_size) { 1958719Sroot printf("bad block %d, ", bn); 1968719Sroot fserr(fs, "bad block"); 1978719Sroot return (1); 1988719Sroot } 1998719Sroot return (0); 2008719Sroot } 2018719Sroot #endif 2028719Sroot 2038719Sroot /* 2048719Sroot * block operations 2058719Sroot * 2068719Sroot * check if a block is available 2078719Sroot */ 2088719Sroot isblock(fs, cp, h) 2098719Sroot struct fs *fs; 2108719Sroot unsigned char *cp; 2118719Sroot daddr_t h; 2128719Sroot { 2138719Sroot unsigned char mask; 2148719Sroot 21526309Skarels switch ((int)fs->fs_frag) { 2168719Sroot case 8: 2178719Sroot return (cp[h] == 0xff); 2188719Sroot case 4: 2198719Sroot mask = 0x0f << ((h & 0x1) << 2); 2208719Sroot return ((cp[h >> 1] & mask) == mask); 2218719Sroot case 2: 2228719Sroot mask = 0x03 << ((h & 0x3) << 1); 2238719Sroot return ((cp[h >> 2] & mask) == mask); 2248719Sroot case 1: 2258719Sroot mask = 0x01 << (h & 0x7); 2268719Sroot return ((cp[h >> 3] & mask) == mask); 2278719Sroot default: 2288719Sroot panic("isblock"); 2298719Sroot return (NULL); 2308719Sroot } 2318719Sroot } 2328719Sroot 2338719Sroot /* 2348719Sroot * take a block out of the map 2358719Sroot */ 2368719Sroot clrblock(fs, cp, h) 2378719Sroot struct fs *fs; 2388770Sroot u_char *cp; 2398719Sroot daddr_t h; 2408719Sroot { 2418719Sroot 24226309Skarels switch ((int)fs->fs_frag) { 2438719Sroot case 8: 2448719Sroot cp[h] = 0; 2458719Sroot return; 2468719Sroot case 4: 2478719Sroot cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 2488719Sroot return; 2498719Sroot case 2: 2508719Sroot cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 2518719Sroot return; 2528719Sroot case 1: 2538719Sroot cp[h >> 3] &= ~(0x01 << (h & 0x7)); 2548719Sroot return; 2558719Sroot default: 2568719Sroot panic("clrblock"); 2578719Sroot } 2588719Sroot } 2598719Sroot 2608719Sroot /* 2618719Sroot * put a block into the map 2628719Sroot */ 2638719Sroot setblock(fs, cp, h) 2648719Sroot struct fs *fs; 2658719Sroot unsigned char *cp; 2668719Sroot daddr_t h; 2678719Sroot { 2688719Sroot 26926309Skarels switch ((int)fs->fs_frag) { 2708719Sroot 2718719Sroot case 8: 2728719Sroot cp[h] = 0xff; 2738719Sroot return; 2748719Sroot case 4: 2758719Sroot cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 2768719Sroot return; 2778719Sroot case 2: 2788719Sroot cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 2798719Sroot return; 2808719Sroot case 1: 2818719Sroot cp[h >> 3] |= (0x01 << (h & 0x7)); 2828719Sroot return; 2838719Sroot default: 2848719Sroot panic("setblock"); 2858719Sroot } 2868719Sroot } 2879167Ssam 2889167Ssam #ifdef KERNEL 2899167Ssam /* 2909167Ssam * Getfs maps a device number into a pointer to the incore super block. 2919167Ssam * 2929167Ssam * The algorithm is a linear search through the mount table. A 2939167Ssam * consistency check of the super block magic number is performed. 2949167Ssam * 2959167Ssam * panic: no fs -- the device is not mounted. 2969167Ssam * this "cannot happen" 2979167Ssam */ 2989167Ssam struct fs * 2999167Ssam getfs(dev) 3009167Ssam dev_t dev; 3019167Ssam { 3029167Ssam register struct mount *mp; 3039167Ssam register struct fs *fs; 3049167Ssam 3059167Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 3069167Ssam if (mp->m_bufp == NULL || mp->m_dev != dev) 3079167Ssam continue; 3089167Ssam fs = mp->m_bufp->b_un.b_fs; 3099167Ssam if (fs->fs_magic != FS_MAGIC) { 3109167Ssam printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); 3119167Ssam panic("getfs: bad magic"); 3129167Ssam } 3139167Ssam return (fs); 3149167Ssam } 3159167Ssam printf("dev = 0x%x\n", dev); 3169167Ssam panic("getfs: no fs"); 3179167Ssam return (NULL); 3189167Ssam } 3199167Ssam 3209167Ssam /* 3219167Ssam * Getfsx returns the index in the file system 3229167Ssam * table of the specified device. The swap device 3239167Ssam * is also assigned a pseudo-index. The index may 3249167Ssam * be used as a compressed indication of the location 3259167Ssam * of a block, recording 3269167Ssam * <getfsx(dev),blkno> 3279167Ssam * rather than 3289167Ssam * <dev, blkno> 3299167Ssam * provided the information need remain valid only 3309167Ssam * as long as the file system is mounted. 3319167Ssam */ 3329167Ssam getfsx(dev) 3339167Ssam dev_t dev; 3349167Ssam { 3359167Ssam register struct mount *mp; 3369167Ssam 3379167Ssam if (dev == swapdev) 3389167Ssam return (MSWAPX); 3399167Ssam for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 3409167Ssam if (mp->m_dev == dev) 3419167Ssam return (mp - &mount[0]); 3429167Ssam return (-1); 3439167Ssam } 3449167Ssam 3459167Ssam /* 3469167Ssam * Print out statistics on the current allocation of the buffer pool. 3479167Ssam * Can be enabled to print out on every ``sync'' by setting "syncprt" 3489167Ssam * above. 3499167Ssam */ 3509167Ssam bufstats() 3519167Ssam { 3529167Ssam int s, i, j, count; 3539167Ssam register struct buf *bp, *dp; 3549167Ssam int counts[MAXBSIZE/CLBYTES+1]; 3559167Ssam static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 3569167Ssam 3579167Ssam for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 3589167Ssam count = 0; 3599167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3609167Ssam counts[j] = 0; 36126274Skarels s = splbio(); 3629167Ssam for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 3639167Ssam counts[dp->b_bufsize/CLBYTES]++; 3649167Ssam count++; 3659167Ssam } 3669167Ssam splx(s); 3679167Ssam printf("%s: total-%d", bname[i], count); 3689167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3699167Ssam if (counts[j] != 0) 3709167Ssam printf(", %d-%d", j * CLBYTES, counts[j]); 3719167Ssam printf("\n"); 3729167Ssam } 3739167Ssam } 3749167Ssam #endif 37521090Smckusick 376*29947Skarels #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) 37721090Smckusick /* 378*29947Skarels * C definitions of special instructions. 379*29947Skarels * Normally expanded with inline. 38021090Smckusick */ 38121090Smckusick scanc(size, cp, table, mask) 38221090Smckusick u_int size; 38321090Smckusick register u_char *cp, table[]; 38421090Smckusick register u_char mask; 38521090Smckusick { 38621090Smckusick register u_char *end = &cp[size]; 38721090Smckusick 38821090Smckusick while (cp < end && (table[*cp] & mask) == 0) 38921090Smckusick cp++; 39021090Smckusick return (end - cp); 39121090Smckusick } 39227476Skridle #endif 39327476Skridle 394*29947Skarels #if !defined(vax) && !defined(tahoe) 39521090Smckusick skpc(mask, size, cp) 39621090Smckusick register u_char mask; 39721090Smckusick u_int size; 39821090Smckusick register u_char *cp; 39921090Smckusick { 40021090Smckusick register u_char *end = &cp[size]; 40121090Smckusick 40221090Smckusick while (cp < end && *cp == mask) 40321090Smckusick cp++; 40421090Smckusick return (end - cp); 40521090Smckusick } 40621090Smckusick 40721090Smckusick locc(mask, size, cp) 40821090Smckusick register u_char mask; 40921090Smckusick u_int size; 41021090Smckusick register u_char *cp; 41121090Smckusick { 41221090Smckusick register u_char *end = &cp[size]; 41321090Smckusick 41421090Smckusick while (cp < end && *cp != mask) 41521090Smckusick cp++; 41621090Smckusick return (end - cp); 41721090Smckusick } 418*29947Skarels #endif 419