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*37574Sbostic * @(#)ffs_subr.c 7.7 (Berkeley) 05/01/89 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++) { 5834356Skarels if (mp->m_fs == NULL || mp->m_fs == (struct fs *)1) /* XXX */ 599167Ssam continue; 6031659Smckusick fs = mp->m_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 iupdat(ip, &time, &time, 1); 1439167Ssam } 1449167Ssam #endif 1459167Ssam 1468719Sroot extern int around[9]; 1478719Sroot extern int inside[9]; 1488719Sroot extern u_char *fragtbl[]; 1498719Sroot 1508719Sroot /* 1518719Sroot * Update the frsum fields to reflect addition or deletion 1528719Sroot * of some frags. 1538719Sroot */ 1548719Sroot fragacct(fs, fragmap, fraglist, cnt) 1558719Sroot struct fs *fs; 1568719Sroot int fragmap; 1578719Sroot long fraglist[]; 1588719Sroot int cnt; 1598719Sroot { 1608719Sroot int inblk; 1618719Sroot register int field, subfield; 1628719Sroot register int siz, pos; 1638719Sroot 1648719Sroot inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 1658719Sroot fragmap <<= 1; 1668719Sroot for (siz = 1; siz < fs->fs_frag; siz++) { 1678719Sroot if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 1688719Sroot continue; 1698719Sroot field = around[siz]; 1708719Sroot subfield = inside[siz]; 1718719Sroot for (pos = siz; pos <= fs->fs_frag; pos++) { 1728719Sroot if ((fragmap & field) == subfield) { 1738719Sroot fraglist[siz] += cnt; 1748719Sroot pos += siz; 1758719Sroot field <<= siz; 1768719Sroot subfield <<= siz; 1778719Sroot } 1788719Sroot field <<= 1; 1798719Sroot subfield <<= 1; 1808719Sroot } 1818719Sroot } 1828719Sroot } 1838719Sroot 1848719Sroot #ifdef KERNEL 1858719Sroot /* 1868719Sroot * Check that a specified block number is in range. 1878719Sroot */ 1888719Sroot badblock(fs, bn) 1898719Sroot register struct fs *fs; 1908719Sroot daddr_t bn; 1918719Sroot { 1928719Sroot 1938719Sroot if ((unsigned)bn >= fs->fs_size) { 1948719Sroot printf("bad block %d, ", bn); 1958719Sroot fserr(fs, "bad block"); 1968719Sroot return (1); 1978719Sroot } 1988719Sroot return (0); 1998719Sroot } 2008719Sroot #endif 2018719Sroot 2028719Sroot /* 2038719Sroot * block operations 2048719Sroot * 2058719Sroot * check if a block is available 2068719Sroot */ 2078719Sroot isblock(fs, cp, h) 2088719Sroot struct fs *fs; 2098719Sroot unsigned char *cp; 2108719Sroot daddr_t h; 2118719Sroot { 2128719Sroot unsigned char mask; 2138719Sroot 21426309Skarels switch ((int)fs->fs_frag) { 2158719Sroot case 8: 2168719Sroot return (cp[h] == 0xff); 2178719Sroot case 4: 2188719Sroot mask = 0x0f << ((h & 0x1) << 2); 2198719Sroot return ((cp[h >> 1] & mask) == mask); 2208719Sroot case 2: 2218719Sroot mask = 0x03 << ((h & 0x3) << 1); 2228719Sroot return ((cp[h >> 2] & mask) == mask); 2238719Sroot case 1: 2248719Sroot mask = 0x01 << (h & 0x7); 2258719Sroot return ((cp[h >> 3] & mask) == mask); 2268719Sroot default: 2278719Sroot panic("isblock"); 2288719Sroot return (NULL); 2298719Sroot } 2308719Sroot } 2318719Sroot 2328719Sroot /* 2338719Sroot * take a block out of the map 2348719Sroot */ 2358719Sroot clrblock(fs, cp, h) 2368719Sroot struct fs *fs; 2378770Sroot u_char *cp; 2388719Sroot daddr_t h; 2398719Sroot { 2408719Sroot 24126309Skarels switch ((int)fs->fs_frag) { 2428719Sroot case 8: 2438719Sroot cp[h] = 0; 2448719Sroot return; 2458719Sroot case 4: 2468719Sroot cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 2478719Sroot return; 2488719Sroot case 2: 2498719Sroot cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 2508719Sroot return; 2518719Sroot case 1: 2528719Sroot cp[h >> 3] &= ~(0x01 << (h & 0x7)); 2538719Sroot return; 2548719Sroot default: 2558719Sroot panic("clrblock"); 2568719Sroot } 2578719Sroot } 2588719Sroot 2598719Sroot /* 2608719Sroot * put a block into the map 2618719Sroot */ 2628719Sroot setblock(fs, cp, h) 2638719Sroot struct fs *fs; 2648719Sroot unsigned char *cp; 2658719Sroot daddr_t h; 2668719Sroot { 2678719Sroot 26826309Skarels switch ((int)fs->fs_frag) { 2698719Sroot 2708719Sroot case 8: 2718719Sroot cp[h] = 0xff; 2728719Sroot return; 2738719Sroot case 4: 2748719Sroot cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 2758719Sroot return; 2768719Sroot case 2: 2778719Sroot cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 2788719Sroot return; 2798719Sroot case 1: 2808719Sroot cp[h >> 3] |= (0x01 << (h & 0x7)); 2818719Sroot return; 2828719Sroot default: 2838719Sroot panic("setblock"); 2848719Sroot } 2858719Sroot } 2869167Ssam 2879167Ssam #ifdef KERNEL 2889167Ssam /* 2899167Ssam * Getfs maps a device number into a pointer to the incore super block. 2909167Ssam * 2919167Ssam * The algorithm is a linear search through the mount table. A 2929167Ssam * consistency check of the super block magic number is performed. 29334356Skarels * Filesystems still working on a mount are skipped. 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++) { 30634356Skarels if (mp->m_dev != dev || mp->m_fs == NULL || 30734356Skarels mp->m_fs == (struct fs *)1) /* XXX */ 3089167Ssam continue; 30931659Smckusick fs = mp->m_fs; 3109167Ssam if (fs->fs_magic != FS_MAGIC) { 3119167Ssam printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); 3129167Ssam panic("getfs: bad magic"); 3139167Ssam } 3149167Ssam return (fs); 3159167Ssam } 3169167Ssam printf("dev = 0x%x\n", dev); 3179167Ssam panic("getfs: no fs"); 3189167Ssam return (NULL); 3199167Ssam } 3209167Ssam 3219167Ssam /* 3229167Ssam * Getfsx returns the index in the file system 3239167Ssam * table of the specified device. The swap device 3249167Ssam * is also assigned a pseudo-index. The index may 3259167Ssam * be used as a compressed indication of the location 3269167Ssam * of a block, recording 3279167Ssam * <getfsx(dev),blkno> 3289167Ssam * rather than 3299167Ssam * <dev, blkno> 3309167Ssam * provided the information need remain valid only 3319167Ssam * as long as the file system is mounted. 3329167Ssam */ 3339167Ssam getfsx(dev) 3349167Ssam dev_t dev; 3359167Ssam { 3369167Ssam register struct mount *mp; 3379167Ssam 3389167Ssam if (dev == swapdev) 3399167Ssam return (MSWAPX); 3409167Ssam for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 3419167Ssam if (mp->m_dev == dev) 3429167Ssam return (mp - &mount[0]); 3439167Ssam return (-1); 3449167Ssam } 3459167Ssam 3469167Ssam /* 3479167Ssam * Print out statistics on the current allocation of the buffer pool. 3489167Ssam * Can be enabled to print out on every ``sync'' by setting "syncprt" 3499167Ssam * above. 3509167Ssam */ 3519167Ssam bufstats() 3529167Ssam { 3539167Ssam int s, i, j, count; 3549167Ssam register struct buf *bp, *dp; 3559167Ssam int counts[MAXBSIZE/CLBYTES+1]; 3569167Ssam static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 3579167Ssam 3589167Ssam for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 3599167Ssam count = 0; 3609167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3619167Ssam counts[j] = 0; 36226274Skarels s = splbio(); 3639167Ssam for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 3649167Ssam counts[dp->b_bufsize/CLBYTES]++; 3659167Ssam count++; 3669167Ssam } 3679167Ssam splx(s); 3689167Ssam printf("%s: total-%d", bname[i], count); 3699167Ssam for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 3709167Ssam if (counts[j] != 0) 3719167Ssam printf(", %d-%d", j * CLBYTES, counts[j]); 3729167Ssam printf("\n"); 3739167Ssam } 3749167Ssam } 3759167Ssam #endif 37621090Smckusick 377*37574Sbostic #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650) 37821090Smckusick /* 37929947Skarels * C definitions of special instructions. 38029947Skarels * Normally expanded with inline. 38121090Smckusick */ 38221090Smckusick scanc(size, cp, table, mask) 38321090Smckusick u_int size; 38421090Smckusick register u_char *cp, table[]; 38521090Smckusick register u_char mask; 38621090Smckusick { 38721090Smckusick register u_char *end = &cp[size]; 38821090Smckusick 38921090Smckusick while (cp < end && (table[*cp] & mask) == 0) 39021090Smckusick cp++; 39121090Smckusick return (end - cp); 39221090Smckusick } 39327476Skridle #endif 39427476Skridle 39529947Skarels #if !defined(vax) && !defined(tahoe) 39621090Smckusick skpc(mask, size, cp) 39721090Smckusick register u_char mask; 39821090Smckusick u_int size; 39921090Smckusick register u_char *cp; 40021090Smckusick { 40121090Smckusick register u_char *end = &cp[size]; 40221090Smckusick 40321090Smckusick while (cp < end && *cp == mask) 40421090Smckusick cp++; 40521090Smckusick return (end - cp); 40621090Smckusick } 40721090Smckusick 40821090Smckusick locc(mask, size, cp) 40921090Smckusick register u_char mask; 41021090Smckusick u_int size; 41121090Smckusick register u_char *cp; 41221090Smckusick { 41321090Smckusick register u_char *end = &cp[size]; 41421090Smckusick 41521090Smckusick while (cp < end && *cp != mask) 41621090Smckusick cp++; 41721090Smckusick return (end - cp); 41821090Smckusick } 41929947Skarels #endif 420