1*8617Sroot /* lfs_alloc.c 2.15 82/10/17 */ 24359Smckusick 34359Smckusick #include "../h/param.h" 44359Smckusick #include "../h/systm.h" 54359Smckusick #include "../h/mount.h" 64359Smckusick #include "../h/fs.h" 74359Smckusick #include "../h/conf.h" 84359Smckusick #include "../h/buf.h" 94359Smckusick #include "../h/inode.h" 106567Smckusic #include "../h/dir.h" 114359Smckusick #include "../h/user.h" 127483Skre #include "../h/quota.h" 138105Sroot #include "../h/kernel.h" 144359Smckusick 155212Smckusic extern u_long hashalloc(); 165212Smckusic extern ino_t ialloccg(); 174651Smckusic extern daddr_t alloccg(); 184651Smckusic extern daddr_t alloccgblk(); 194651Smckusic extern daddr_t fragextend(); 204651Smckusic extern daddr_t blkpref(); 214651Smckusic extern daddr_t mapsearch(); 224607Smckusic extern int inside[], around[]; 235322Smckusic extern unsigned char *fragtbl[]; 244359Smckusick 255375Smckusic /* 265375Smckusic * Allocate a block in the file system. 275375Smckusic * 285375Smckusic * The size of the requested block is given, which must be some 295375Smckusic * multiple of fs_fsize and <= fs_bsize. 305375Smckusic * A preference may be optionally specified. If a preference is given 315375Smckusic * the following hierarchy is used to allocate a block: 325375Smckusic * 1) allocate the requested block. 335375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 345375Smckusic * 3) allocate a block in the same cylinder group. 355375Smckusic * 4) quadradically rehash into other cylinder groups, until an 365375Smckusic * available block is located. 375375Smckusic * If no block preference is given the following heirarchy is used 385375Smckusic * to allocate a block: 395375Smckusic * 1) allocate a block in the cylinder group that contains the 405375Smckusic * inode for the file. 415375Smckusic * 2) quadradically rehash into other cylinder groups, until an 425375Smckusic * available block is located. 435375Smckusic */ 444359Smckusick struct buf * 455965Smckusic alloc(ip, bpref, size) 464463Smckusic register struct inode *ip; 474359Smckusick daddr_t bpref; 484359Smckusick int size; 494359Smckusick { 504359Smckusick daddr_t bno; 514359Smckusick register struct fs *fs; 524463Smckusic register struct buf *bp; 534359Smckusick int cg; 544359Smckusick 555965Smckusic fs = ip->i_fs; 566716Smckusick if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { 576716Smckusick printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", 586716Smckusick ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); 594463Smckusic panic("alloc: bad size"); 606716Smckusick } 615322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 624359Smckusick goto nospace; 634792Smckusic if (u.u_uid != 0 && 645322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 655322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 664792Smckusic goto nospace; 677650Ssam #ifdef QUOTA 687483Skre if (chkdq(ip, (long)((unsigned)size/DEV_BSIZE), 0)) 697483Skre return(NULL); 707483Skre #endif 714948Smckusic if (bpref >= fs->fs_size) 724948Smckusic bpref = 0; 734359Smckusick if (bpref == 0) 745377Smckusic cg = itog(fs, ip->i_number); 754359Smckusick else 765377Smckusic cg = dtog(fs, bpref); 775965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, alloccg); 786567Smckusic if (bno <= 0) 794359Smckusick goto nospace; 805965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), size); 814359Smckusick clrbuf(bp); 824359Smckusick return (bp); 834359Smckusick nospace: 844359Smckusick fserr(fs, "file system full"); 854359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 864359Smckusick u.u_error = ENOSPC; 874359Smckusick return (NULL); 884359Smckusick } 894359Smckusick 905375Smckusic /* 915375Smckusic * Reallocate a fragment to a bigger size 925375Smckusic * 935375Smckusic * The number and size of the old block is given, and a preference 945375Smckusic * and new size is also specified. The allocator attempts to extend 955375Smckusic * the original block. Failing that, the regular block allocator is 965375Smckusic * invoked to get an appropriate block. 975375Smckusic */ 984426Smckusic struct buf * 995965Smckusic realloccg(ip, bprev, bpref, osize, nsize) 1005965Smckusic register struct inode *ip; 1014651Smckusic daddr_t bprev, bpref; 1024426Smckusic int osize, nsize; 1034426Smckusic { 1044426Smckusic daddr_t bno; 1054426Smckusic register struct fs *fs; 1064463Smckusic register struct buf *bp, *obp; 1074426Smckusic int cg; 1084426Smckusic 1095965Smckusic fs = ip->i_fs; 1105960Smckusic if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || 1116716Smckusick (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { 1126716Smckusick printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n", 1136716Smckusick ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt); 1144463Smckusic panic("realloccg: bad size"); 1156716Smckusick } 1164792Smckusic if (u.u_uid != 0 && 1175322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 1185322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 1194792Smckusic goto nospace; 1206716Smckusick if (bprev == 0) { 1216716Smckusick printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n", 1226716Smckusick ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt); 1234463Smckusic panic("realloccg: bad bprev"); 1246716Smckusick } 1257650Ssam #ifdef QUOTA 1267483Skre if (chkdq(ip, (long)((unsigned)(nsize-osize)/DEV_BSIZE), 0)) 1277483Skre return(NULL); 1287483Skre #endif 1296294Smckusick cg = dtog(fs, bprev); 1305965Smckusic bno = fragextend(ip, cg, (long)bprev, osize, nsize); 1314463Smckusic if (bno != 0) { 1327187Sroot do { 1337187Sroot bp = bread(ip->i_dev, fsbtodb(fs, bno), osize); 1347187Sroot if (bp->b_flags & B_ERROR) { 1357187Sroot brelse(bp); 1367187Sroot return (NULL); 1377187Sroot } 1387187Sroot } while (brealloc(bp, nsize) == 0); 1397187Sroot bp->b_flags |= B_DONE; 1407437Sroot bzero(bp->b_un.b_addr + osize, nsize - osize); 1414463Smckusic return (bp); 1424463Smckusic } 1434948Smckusic if (bpref >= fs->fs_size) 1444948Smckusic bpref = 0; 1455965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, nsize, alloccg); 1466567Smckusic if (bno > 0) { 1475965Smckusic obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize); 1485960Smckusic if (obp->b_flags & B_ERROR) { 1495960Smckusic brelse(obp); 1506294Smckusick return (NULL); 1515960Smckusic } 1525965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), nsize); 153*8617Sroot bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize); 1547437Sroot bzero(bp->b_un.b_addr + osize, nsize - osize); 1554463Smckusic brelse(obp); 1565965Smckusic fre(ip, bprev, (off_t)osize); 1576294Smckusick return (bp); 1584463Smckusic } 1594792Smckusic nospace: 1604463Smckusic /* 1614463Smckusic * no space available 1624463Smckusic */ 1634426Smckusic fserr(fs, "file system full"); 1644426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1654426Smckusic u.u_error = ENOSPC; 1664426Smckusic return (NULL); 1674426Smckusic } 1684426Smckusic 1695375Smckusic /* 1705375Smckusic * Allocate an inode in the file system. 1715375Smckusic * 1725375Smckusic * A preference may be optionally specified. If a preference is given 1735375Smckusic * the following hierarchy is used to allocate an inode: 1745375Smckusic * 1) allocate the requested inode. 1755375Smckusic * 2) allocate an inode in the same cylinder group. 1765375Smckusic * 3) quadradically rehash into other cylinder groups, until an 1775375Smckusic * available inode is located. 1785375Smckusic * If no inode preference is given the following heirarchy is used 1795375Smckusic * to allocate an inode: 1805375Smckusic * 1) allocate an inode in cylinder group 0. 1815375Smckusic * 2) quadradically rehash into other cylinder groups, until an 1825375Smckusic * available inode is located. 1835375Smckusic */ 1844359Smckusick struct inode * 1855965Smckusic ialloc(pip, ipref, mode) 1865965Smckusic register struct inode *pip; 1874359Smckusick ino_t ipref; 1884359Smckusick int mode; 1894359Smckusick { 1905212Smckusic ino_t ino; 1914359Smckusick register struct fs *fs; 1924359Smckusick register struct inode *ip; 1934359Smckusick int cg; 1944359Smckusick 1955965Smckusic fs = pip->i_fs; 1964792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1974359Smckusick goto noinodes; 1987650Ssam #ifdef QUOTA 1997483Skre if (chkiq(pip->i_dev, NULL, u.u_uid, 0)) 2007483Skre return(NULL); 2017483Skre #endif 2024948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 2034948Smckusic ipref = 0; 2045377Smckusic cg = itog(fs, ipref); 2055965Smckusic ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); 2064359Smckusick if (ino == 0) 2074359Smckusick goto noinodes; 2085965Smckusic ip = iget(pip->i_dev, pip->i_fs, ino); 2094359Smckusick if (ip == NULL) { 2105965Smckusic ifree(ip, ino, 0); 2114359Smckusick return (NULL); 2124359Smckusick } 2136716Smckusick if (ip->i_mode) { 2146716Smckusick printf("mode = 0%o, inum = %d, fs = %s\n", 2156716Smckusick ip->i_mode, ip->i_number, fs->fs_fsmnt); 2164359Smckusick panic("ialloc: dup alloc"); 2176716Smckusick } 2184359Smckusick return (ip); 2194359Smckusick noinodes: 2204359Smckusick fserr(fs, "out of inodes"); 2216294Smckusick uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 2224359Smckusick u.u_error = ENOSPC; 2234359Smckusick return (NULL); 2244359Smckusick } 2254359Smckusick 2264651Smckusic /* 2275375Smckusic * Find a cylinder to place a directory. 2285375Smckusic * 2295375Smckusic * The policy implemented by this algorithm is to select from 2305375Smckusic * among those cylinder groups with above the average number of 2315375Smckusic * free inodes, the one with the smallest number of directories. 2324651Smckusic */ 2335965Smckusic dirpref(fs) 2345965Smckusic register struct fs *fs; 2354359Smckusick { 2364651Smckusic int cg, minndir, mincg, avgifree; 2374359Smckusick 2384792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 2394651Smckusic minndir = fs->fs_ipg; 2404359Smckusick mincg = 0; 2414651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 2425322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 2435322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 2444359Smckusick mincg = cg; 2455322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 2464359Smckusick } 2474359Smckusick return (fs->fs_ipg * mincg); 2484359Smckusick } 2494359Smckusick 2504651Smckusic /* 2515375Smckusic * Select a cylinder to place a large block of data. 2525375Smckusic * 2535375Smckusic * The policy implemented by this algorithm is to maintain a 2545375Smckusic * rotor that sweeps the cylinder groups. When a block is 2555375Smckusic * needed, the rotor is advanced until a cylinder group with 2565375Smckusic * greater than the average number of free blocks is found. 2574651Smckusic */ 2585212Smckusic daddr_t 2595965Smckusic blkpref(fs) 2605965Smckusic register struct fs *fs; 2614651Smckusic { 2624651Smckusic int cg, avgbfree; 2634651Smckusic 2644792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 2654651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 2665322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2674651Smckusic fs->fs_cgrotor = cg; 2685322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2694651Smckusic } 2704651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 2715322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2724651Smckusic fs->fs_cgrotor = cg; 2735322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2744651Smckusic } 2756294Smckusick return (NULL); 2764651Smckusic } 2774651Smckusic 2785375Smckusic /* 2795375Smckusic * Implement the cylinder overflow algorithm. 2805375Smckusic * 2815375Smckusic * The policy implemented by this algorithm is: 2825375Smckusic * 1) allocate the block in its requested cylinder group. 2835375Smckusic * 2) quadradically rehash on the cylinder group number. 2845375Smckusic * 3) brute force search for a free block. 2855375Smckusic */ 2865212Smckusic /*VARARGS5*/ 2875212Smckusic u_long 2885965Smckusic hashalloc(ip, cg, pref, size, allocator) 2895965Smckusic struct inode *ip; 2904359Smckusick int cg; 2914359Smckusick long pref; 2924359Smckusick int size; /* size for data blocks, mode for inodes */ 2935212Smckusic u_long (*allocator)(); 2944359Smckusick { 2955965Smckusic register struct fs *fs; 2964359Smckusick long result; 2974359Smckusick int i, icg = cg; 2984359Smckusick 2995965Smckusic fs = ip->i_fs; 3004359Smckusick /* 3014359Smckusick * 1: preferred cylinder group 3024359Smckusick */ 3035965Smckusic result = (*allocator)(ip, cg, pref, size); 3044359Smckusick if (result) 3054359Smckusick return (result); 3064359Smckusick /* 3074359Smckusick * 2: quadratic rehash 3084359Smckusick */ 3094359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 3104359Smckusick cg += i; 3114359Smckusick if (cg >= fs->fs_ncg) 3124359Smckusick cg -= fs->fs_ncg; 3135965Smckusic result = (*allocator)(ip, cg, 0, size); 3144359Smckusick if (result) 3154359Smckusick return (result); 3164359Smckusick } 3174359Smckusick /* 3184359Smckusick * 3: brute force search 3194359Smckusick */ 3204359Smckusick cg = icg; 3214359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 3225965Smckusic result = (*allocator)(ip, cg, 0, size); 3234359Smckusick if (result) 3244359Smckusick return (result); 3254359Smckusick cg++; 3264359Smckusick if (cg == fs->fs_ncg) 3274359Smckusick cg = 0; 3284359Smckusick } 3296294Smckusick return (NULL); 3304359Smckusick } 3314359Smckusick 3325375Smckusic /* 3335375Smckusic * Determine whether a fragment can be extended. 3345375Smckusic * 3355375Smckusic * Check to see if the necessary fragments are available, and 3365375Smckusic * if they are, allocate them. 3375375Smckusic */ 3384359Smckusick daddr_t 3395965Smckusic fragextend(ip, cg, bprev, osize, nsize) 3405965Smckusic struct inode *ip; 3414426Smckusic int cg; 3424463Smckusic long bprev; 3434426Smckusic int osize, nsize; 3444426Smckusic { 3455965Smckusic register struct fs *fs; 3464463Smckusic register struct buf *bp; 3474463Smckusic register struct cg *cgp; 3484463Smckusic long bno; 3494463Smckusic int frags, bbase; 3504426Smckusic int i; 3514426Smckusic 3525965Smckusic fs = ip->i_fs; 3536531Smckusick if (fs->fs_cs(fs, cg).cs_nffree < nsize - osize) 3546531Smckusick return (NULL); 3555960Smckusic frags = numfrags(fs, nsize); 3565960Smckusic bbase = fragoff(fs, bprev); 3575322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 3584463Smckusic /* cannot extend across a block boundry */ 3596294Smckusick return (NULL); 3604463Smckusic } 361*8617Sroot bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_bsize); 3626531Smckusick cgp = bp->b_un.b_cg; 3636531Smckusick if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { 3645960Smckusic brelse(bp); 3656294Smckusick return (NULL); 3665960Smckusic } 3678105Sroot cgp->cg_time = time.tv_sec; 3685377Smckusic bno = dtogd(fs, bprev); 3695960Smckusic for (i = numfrags(fs, osize); i < frags; i++) 3705361Smckusic if (isclr(cgp->cg_free, bno + i)) { 3715361Smckusic brelse(bp); 3726294Smckusick return (NULL); 3735361Smckusic } 3745361Smckusic /* 3755361Smckusic * the current fragment can be extended 3765361Smckusic * deduct the count on fragment being extended into 3775361Smckusic * increase the count on the remaining fragment (if any) 3785361Smckusic * allocate the extended piece 3795361Smckusic */ 3805361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 3814463Smckusic if (isclr(cgp->cg_free, bno + i)) 3824463Smckusic break; 3835960Smckusic cgp->cg_frsum[i - numfrags(fs, osize)]--; 3845361Smckusic if (i != frags) 3855361Smckusic cgp->cg_frsum[i - frags]++; 3865960Smckusic for (i = numfrags(fs, osize); i < frags; i++) { 3875361Smckusic clrbit(cgp->cg_free, bno + i); 3885361Smckusic cgp->cg_cs.cs_nffree--; 3895361Smckusic fs->fs_cstotal.cs_nffree--; 3905361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3914463Smckusic } 3925361Smckusic fs->fs_fmod++; 3935361Smckusic bdwrite(bp); 3945361Smckusic return (bprev); 3954426Smckusic } 3964426Smckusic 3975375Smckusic /* 3985375Smckusic * Determine whether a block can be allocated. 3995375Smckusic * 4005375Smckusic * Check to see if a block of the apprpriate size is available, 4015375Smckusic * and if it is, allocate it. 4025375Smckusic */ 4034426Smckusic daddr_t 4045965Smckusic alloccg(ip, cg, bpref, size) 4055965Smckusic struct inode *ip; 4064359Smckusick int cg; 4074359Smckusick daddr_t bpref; 4084359Smckusick int size; 4094359Smckusick { 4105965Smckusic register struct fs *fs; 4114463Smckusic register struct buf *bp; 4124463Smckusic register struct cg *cgp; 4134463Smckusic int bno, frags; 4144463Smckusic int allocsiz; 4154463Smckusic register int i; 4164359Smckusick 4175965Smckusic fs = ip->i_fs; 4185322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 4196294Smckusick return (NULL); 420*8617Sroot bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_bsize); 4216531Smckusick cgp = bp->b_un.b_cg; 4226531Smckusick if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { 4235960Smckusic brelse(bp); 4246294Smckusick return (NULL); 4255960Smckusic } 4268105Sroot cgp->cg_time = time.tv_sec; 4275322Smckusic if (size == fs->fs_bsize) { 4285212Smckusic bno = alloccgblk(fs, cgp, bpref); 4294463Smckusic bdwrite(bp); 4304463Smckusic return (bno); 4314463Smckusic } 4324463Smckusic /* 4334463Smckusic * check to see if any fragments are already available 4344463Smckusic * allocsiz is the size which will be allocated, hacking 4354463Smckusic * it down to a smaller size if necessary 4364463Smckusic */ 4375960Smckusic frags = numfrags(fs, size); 4385322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 4394463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 4404463Smckusic break; 4415322Smckusic if (allocsiz == fs->fs_frag) { 4424463Smckusic /* 4434463Smckusic * no fragments were available, so a block will be 4444463Smckusic * allocated, and hacked up 4454463Smckusic */ 4464792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 4474463Smckusic brelse(bp); 4486294Smckusick return (NULL); 4494463Smckusic } 4505212Smckusic bno = alloccgblk(fs, cgp, bpref); 4515377Smckusic bpref = dtogd(fs, bno); 4525322Smckusic for (i = frags; i < fs->fs_frag; i++) 4534463Smckusic setbit(cgp->cg_free, bpref + i); 4545322Smckusic i = fs->fs_frag - frags; 4554792Smckusic cgp->cg_cs.cs_nffree += i; 4564792Smckusic fs->fs_cstotal.cs_nffree += i; 4575322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 4584463Smckusic cgp->cg_frsum[i]++; 4594463Smckusic bdwrite(bp); 4604463Smckusic return (bno); 4614463Smckusic } 4624651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 4636567Smckusic if (bno < 0) 4646294Smckusick return (NULL); 4654463Smckusic for (i = 0; i < frags; i++) 4664463Smckusic clrbit(cgp->cg_free, bno + i); 4674792Smckusic cgp->cg_cs.cs_nffree -= frags; 4684792Smckusic fs->fs_cstotal.cs_nffree -= frags; 4695322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 4704463Smckusic cgp->cg_frsum[allocsiz]--; 4714463Smckusic if (frags != allocsiz) 4724463Smckusic cgp->cg_frsum[allocsiz - frags]++; 4734463Smckusic bdwrite(bp); 4744463Smckusic return (cg * fs->fs_fpg + bno); 4754463Smckusic } 4764463Smckusic 4775375Smckusic /* 4785375Smckusic * Allocate a block in a cylinder group. 4795375Smckusic * 4805375Smckusic * This algorithm implements the following policy: 4815375Smckusic * 1) allocate the requested block. 4825375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 4835375Smckusic * 3) allocate the next available block on the block rotor for the 4845375Smckusic * specified cylinder group. 4855375Smckusic * Note that this routine only allocates fs_bsize blocks; these 4865375Smckusic * blocks may be fragmented by the routine that allocates them. 4875375Smckusic */ 4884463Smckusic daddr_t 4895212Smckusic alloccgblk(fs, cgp, bpref) 4905965Smckusic register struct fs *fs; 4914463Smckusic register struct cg *cgp; 4924463Smckusic daddr_t bpref; 4934463Smckusic { 4944651Smckusic daddr_t bno; 4956294Smckusick int cylno, pos, delta; 4964651Smckusic short *cylbp; 4975361Smckusic register int i; 4984463Smckusic 4994651Smckusic if (bpref == 0) { 5004651Smckusic bpref = cgp->cg_rotor; 5015361Smckusic goto norot; 5025361Smckusic } 5035361Smckusic bpref &= ~(fs->fs_frag - 1); 5045377Smckusic bpref = dtogd(fs, bpref); 5055361Smckusic /* 5065361Smckusic * if the requested block is available, use it 5075361Smckusic */ 5087187Sroot /* 5097187Sroot * disallow sequential layout. 5107187Sroot * 5115361Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 5125361Smckusic bno = bpref; 5135361Smckusic goto gotit; 5145361Smckusic } 5157187Sroot */ 5165361Smckusic /* 5175361Smckusic * check for a block available on the same cylinder 5185361Smckusic */ 5195361Smckusic cylno = cbtocylno(fs, bpref); 5205375Smckusic if (cgp->cg_btot[cylno] == 0) 5215375Smckusic goto norot; 5225375Smckusic if (fs->fs_cpc == 0) { 5235375Smckusic /* 5245375Smckusic * block layout info is not available, so just have 5255375Smckusic * to take any block in this cylinder. 5265375Smckusic */ 5275375Smckusic bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); 5285375Smckusic goto norot; 5295375Smckusic } 5305375Smckusic /* 5315375Smckusic * find a block that is rotationally optimal 5325375Smckusic */ 5335361Smckusic cylbp = cgp->cg_b[cylno]; 5345361Smckusic if (fs->fs_rotdelay == 0) { 5355361Smckusic pos = cbtorpos(fs, bpref); 5364651Smckusic } else { 5374651Smckusic /* 5385361Smckusic * here we convert ms of delay to frags as: 5395361Smckusic * (frags) = (ms) * (rev/sec) * (sect/rev) / 5405361Smckusic * ((sect/frag) * (ms/sec)) 5415361Smckusic * then round up to the next rotational position 5424651Smckusic */ 5435361Smckusic bpref += fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 5445361Smckusic (NSPF(fs) * 1000); 5455361Smckusic pos = cbtorpos(fs, bpref); 5465361Smckusic pos = (pos + 1) % NRPOS; 5475361Smckusic } 5485361Smckusic /* 5495361Smckusic * check the summary information to see if a block is 5505361Smckusic * available in the requested cylinder starting at the 5515361Smckusic * optimal rotational position and proceeding around. 5525361Smckusic */ 5535361Smckusic for (i = pos; i < NRPOS; i++) 5545361Smckusic if (cylbp[i] > 0) 5555361Smckusic break; 5565361Smckusic if (i == NRPOS) 5575361Smckusic for (i = 0; i < pos; i++) 5585361Smckusic if (cylbp[i] > 0) 5595361Smckusic break; 5605361Smckusic if (cylbp[i] > 0) { 5614651Smckusic /* 5625361Smckusic * found a rotational position, now find the actual 5635361Smckusic * block. A panic if none is actually there. 5644651Smckusic */ 5655361Smckusic pos = cylno % fs->fs_cpc; 5665361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 5676716Smckusick if (fs->fs_postbl[pos][i] == -1) { 5686716Smckusick printf("pos = %d, i = %d, fs = %s\n", 5696716Smckusick pos, i, fs->fs_fsmnt); 5705361Smckusic panic("alloccgblk: cyl groups corrupted"); 5716716Smckusick } 5726294Smckusick for (i = fs->fs_postbl[pos][i];; ) { 5735361Smckusic if (isblock(fs, cgp->cg_free, bno + i)) { 5745361Smckusic bno = (bno + i) * fs->fs_frag; 5755361Smckusic goto gotit; 5765361Smckusic } 5776294Smckusick delta = fs->fs_rotbl[i]; 5786294Smckusick if (delta <= 0 || delta > MAXBPC - i) 5794651Smckusic break; 5806294Smckusick i += delta; 5814651Smckusic } 5826716Smckusick printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt); 5835361Smckusic panic("alloccgblk: can't find blk in cyl"); 5844359Smckusick } 5855361Smckusic norot: 5865361Smckusic /* 5875361Smckusic * no blocks in the requested cylinder, so take next 5885361Smckusic * available one in this cylinder group. 5895361Smckusic */ 5905322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 5916567Smckusic if (bno < 0) 5926294Smckusick return (NULL); 5934651Smckusic cgp->cg_rotor = bno; 5944359Smckusick gotit: 5955322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 5964792Smckusic cgp->cg_cs.cs_nbfree--; 5974792Smckusic fs->fs_cstotal.cs_nbfree--; 5985322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 5995375Smckusic cylno = cbtocylno(fs, bno); 6005375Smckusic cgp->cg_b[cylno][cbtorpos(fs, bno)]--; 6015375Smckusic cgp->cg_btot[cylno]--; 6024359Smckusick fs->fs_fmod++; 6034651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 6044359Smckusick } 6054359Smckusick 6065375Smckusic /* 6075375Smckusic * Determine whether an inode can be allocated. 6085375Smckusic * 6095375Smckusic * Check to see if an inode is available, and if it is, 6105375Smckusic * allocate it using the following policy: 6115375Smckusic * 1) allocate the requested inode. 6125375Smckusic * 2) allocate the next available inode after the requested 6135375Smckusic * inode in the specified cylinder group. 6145375Smckusic */ 6155212Smckusic ino_t 6165965Smckusic ialloccg(ip, cg, ipref, mode) 6175965Smckusic struct inode *ip; 6184359Smckusick int cg; 6194359Smckusick daddr_t ipref; 6204359Smckusick int mode; 6214359Smckusick { 6225965Smckusic register struct fs *fs; 6234463Smckusic register struct buf *bp; 6244463Smckusic register struct cg *cgp; 6254359Smckusick int i; 6264359Smckusick 6275965Smckusic fs = ip->i_fs; 6285322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 6296294Smckusick return (NULL); 630*8617Sroot bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_bsize); 6316531Smckusick cgp = bp->b_un.b_cg; 6326531Smckusick if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { 6335960Smckusic brelse(bp); 6346294Smckusick return (NULL); 6355960Smckusic } 6368105Sroot cgp->cg_time = time.tv_sec; 6374359Smckusick if (ipref) { 6384359Smckusick ipref %= fs->fs_ipg; 6394359Smckusick if (isclr(cgp->cg_iused, ipref)) 6404359Smckusick goto gotit; 6414359Smckusick } else 6424359Smckusick ipref = cgp->cg_irotor; 6434359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 6444359Smckusick ipref++; 6454359Smckusick if (ipref >= fs->fs_ipg) 6464359Smckusick ipref = 0; 6474359Smckusick if (isclr(cgp->cg_iused, ipref)) { 6484359Smckusick cgp->cg_irotor = ipref; 6494359Smckusick goto gotit; 6504359Smckusick } 6514359Smckusick } 6524359Smckusick brelse(bp); 6536294Smckusick return (NULL); 6544359Smckusick gotit: 6554359Smckusick setbit(cgp->cg_iused, ipref); 6564792Smckusic cgp->cg_cs.cs_nifree--; 6574792Smckusic fs->fs_cstotal.cs_nifree--; 6585322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 6594359Smckusick fs->fs_fmod++; 6604359Smckusick if ((mode & IFMT) == IFDIR) { 6614792Smckusic cgp->cg_cs.cs_ndir++; 6624792Smckusic fs->fs_cstotal.cs_ndir++; 6635322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 6644359Smckusick } 6654359Smckusick bdwrite(bp); 6664359Smckusick return (cg * fs->fs_ipg + ipref); 6674359Smckusick } 6684359Smckusick 6695375Smckusic /* 6705375Smckusic * Free a block or fragment. 6715375Smckusic * 6725375Smckusic * The specified block or fragment is placed back in the 6735375Smckusic * free map. If a fragment is deallocated, a possible 6745375Smckusic * block reassembly is checked. 6755375Smckusic */ 6765965Smckusic fre(ip, bno, size) 6775965Smckusic register struct inode *ip; 6784359Smckusick daddr_t bno; 6795212Smckusic off_t size; 6804359Smckusick { 6814359Smckusick register struct fs *fs; 6824359Smckusick register struct cg *cgp; 6834359Smckusick register struct buf *bp; 6844463Smckusic int cg, blk, frags, bbase; 6854463Smckusic register int i; 6864359Smckusick 6875965Smckusic fs = ip->i_fs; 6886716Smckusick if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { 6896716Smckusick printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", 6906716Smckusick ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); 6914426Smckusic panic("free: bad size"); 6926716Smckusick } 6935377Smckusic cg = dtog(fs, bno); 6946567Smckusic if (badblock(fs, bno)) { 6956567Smckusic printf("bad block %d, ino %d\n", bno, ip->i_number); 6964359Smckusick return; 6976567Smckusic } 698*8617Sroot bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_bsize); 6996531Smckusick cgp = bp->b_un.b_cg; 7006531Smckusick if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { 7015960Smckusic brelse(bp); 7024359Smckusick return; 7035960Smckusic } 7048105Sroot cgp->cg_time = time.tv_sec; 7055377Smckusic bno = dtogd(fs, bno); 7065322Smckusic if (size == fs->fs_bsize) { 7076567Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) { 7086716Smckusick printf("dev = 0x%x, block = %d, fs = %s\n", 7096716Smckusick ip->i_dev, bno, fs->fs_fsmnt); 7104426Smckusic panic("free: freeing free block"); 7116567Smckusic } 7125322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 7134792Smckusic cgp->cg_cs.cs_nbfree++; 7144792Smckusic fs->fs_cstotal.cs_nbfree++; 7155322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 7165375Smckusic i = cbtocylno(fs, bno); 7175375Smckusic cgp->cg_b[i][cbtorpos(fs, bno)]++; 7185375Smckusic cgp->cg_btot[i]++; 7194426Smckusic } else { 7205322Smckusic bbase = bno - (bno % fs->fs_frag); 7214463Smckusic /* 7224463Smckusic * decrement the counts associated with the old frags 7234463Smckusic */ 7246294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 7255322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 7264463Smckusic /* 7274463Smckusic * deallocate the fragment 7284463Smckusic */ 7295960Smckusic frags = numfrags(fs, size); 7304463Smckusic for (i = 0; i < frags; i++) { 7316716Smckusick if (isset(cgp->cg_free, bno + i)) { 7326716Smckusick printf("dev = 0x%x, block = %d, fs = %s\n", 7336716Smckusick ip->i_dev, bno + i, fs->fs_fsmnt); 7344426Smckusic panic("free: freeing free frag"); 7356716Smckusick } 7364426Smckusic setbit(cgp->cg_free, bno + i); 7374426Smckusic } 7386294Smckusick cgp->cg_cs.cs_nffree += i; 7396294Smckusick fs->fs_cstotal.cs_nffree += i; 7406294Smckusick fs->fs_cs(fs, cg).cs_nffree += i; 7414463Smckusic /* 7424463Smckusic * add back in counts associated with the new frags 7434463Smckusic */ 7446294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 7455322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 7464463Smckusic /* 7474463Smckusic * if a complete block has been reassembled, account for it 7484463Smckusic */ 7495322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 7505322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 7515322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 7525322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 7534792Smckusic cgp->cg_cs.cs_nbfree++; 7544792Smckusic fs->fs_cstotal.cs_nbfree++; 7555322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 7565375Smckusic i = cbtocylno(fs, bbase); 7575375Smckusic cgp->cg_b[i][cbtorpos(fs, bbase)]++; 7585375Smckusic cgp->cg_btot[i]++; 7594426Smckusic } 7604426Smckusic } 7614359Smckusick fs->fs_fmod++; 7624359Smckusick bdwrite(bp); 7634359Smckusick } 7644359Smckusick 7655375Smckusic /* 7665375Smckusic * Free an inode. 7675375Smckusic * 7685375Smckusic * The specified inode is placed back in the free map. 7695375Smckusic */ 7705965Smckusic ifree(ip, ino, mode) 7715965Smckusic struct inode *ip; 7724359Smckusick ino_t ino; 7734359Smckusick int mode; 7744359Smckusick { 7754359Smckusick register struct fs *fs; 7764359Smckusick register struct cg *cgp; 7774359Smckusick register struct buf *bp; 7784359Smckusick int cg; 7794359Smckusick 7805965Smckusic fs = ip->i_fs; 7816716Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) { 7826716Smckusick printf("dev = 0x%x, ino = %d, fs = %s\n", 7836716Smckusick ip->i_dev, ino, fs->fs_fsmnt); 7844359Smckusick panic("ifree: range"); 7856716Smckusick } 7865377Smckusic cg = itog(fs, ino); 787*8617Sroot bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_bsize); 7886531Smckusick cgp = bp->b_un.b_cg; 7896531Smckusick if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { 7905960Smckusic brelse(bp); 7914359Smckusick return; 7925960Smckusic } 7938105Sroot cgp->cg_time = time.tv_sec; 7944359Smckusick ino %= fs->fs_ipg; 7956716Smckusick if (isclr(cgp->cg_iused, ino)) { 7966716Smckusick printf("dev = 0x%x, ino = %d, fs = %s\n", 7976716Smckusick ip->i_dev, ino, fs->fs_fsmnt); 7984359Smckusick panic("ifree: freeing free inode"); 7996716Smckusick } 8004359Smckusick clrbit(cgp->cg_iused, ino); 8014792Smckusic cgp->cg_cs.cs_nifree++; 8024792Smckusic fs->fs_cstotal.cs_nifree++; 8035322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 8044359Smckusick if ((mode & IFMT) == IFDIR) { 8054792Smckusic cgp->cg_cs.cs_ndir--; 8064792Smckusic fs->fs_cstotal.cs_ndir--; 8075322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 8084359Smckusick } 8094359Smckusick fs->fs_fmod++; 8104359Smckusick bdwrite(bp); 8114359Smckusick } 8124359Smckusick 8134463Smckusic /* 8145375Smckusic * Find a block of the specified size in the specified cylinder group. 8155375Smckusic * 8164651Smckusic * It is a panic if a request is made to find a block if none are 8174651Smckusic * available. 8184651Smckusic */ 8194651Smckusic daddr_t 8204651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 8214651Smckusic register struct fs *fs; 8224651Smckusic register struct cg *cgp; 8234651Smckusic daddr_t bpref; 8244651Smckusic int allocsiz; 8254651Smckusic { 8264651Smckusic daddr_t bno; 8274651Smckusic int start, len, loc, i; 8284651Smckusic int blk, field, subfield, pos; 8294651Smckusic 8304651Smckusic /* 8314651Smckusic * find the fragment by searching through the free block 8324651Smckusic * map for an appropriate bit pattern 8334651Smckusic */ 8344651Smckusic if (bpref) 8355377Smckusic start = dtogd(fs, bpref) / NBBY; 8364651Smckusic else 8374651Smckusic start = cgp->cg_frotor / NBBY; 8385398Smckusic len = howmany(fs->fs_fpg, NBBY) - start; 8395322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 8406292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 8414651Smckusic if (loc == 0) { 8426531Smckusick len = start + 1; 8436531Smckusick start = 0; 8445322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 8456292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 8464651Smckusic if (loc == 0) { 8476716Smckusick printf("start = %d, len = %d, fs = %s\n", 8486716Smckusick start, len, fs->fs_fsmnt); 8494651Smckusic panic("alloccg: map corrupted"); 8506531Smckusick return (-1); 8514651Smckusic } 8524651Smckusic } 8534651Smckusic bno = (start + len - loc) * NBBY; 8544651Smckusic cgp->cg_frotor = bno; 8554651Smckusic /* 8564651Smckusic * found the byte in the map 8574651Smckusic * sift through the bits to find the selected frag 8584651Smckusic */ 8596294Smckusick for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { 8606294Smckusick blk = blkmap(fs, cgp->cg_free, bno); 8614651Smckusic blk <<= 1; 8624651Smckusic field = around[allocsiz]; 8634651Smckusic subfield = inside[allocsiz]; 8645322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 8656294Smckusick if ((blk & field) == subfield) 8666294Smckusick return (bno + pos); 8674651Smckusic field <<= 1; 8684651Smckusic subfield <<= 1; 8694651Smckusic } 8704651Smckusic } 8716716Smckusick printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt); 8724651Smckusic panic("alloccg: block not in map"); 8736531Smckusick return (-1); 8744651Smckusic } 8754651Smckusic 8764651Smckusic /* 8775375Smckusic * Getfs maps a device number into a pointer to the incore super block. 8784359Smckusick * 8795375Smckusic * The algorithm is a linear search through the mount table. A 8805375Smckusic * consistency check of the super block magic number is performed. 8815375Smckusic * 8824359Smckusick * panic: no fs -- the device is not mounted. 8834359Smckusick * this "cannot happen" 8844359Smckusick */ 8854359Smckusick struct fs * 8864359Smckusick getfs(dev) 8874359Smckusick dev_t dev; 8884359Smckusick { 8894359Smckusick register struct mount *mp; 8904359Smckusick register struct fs *fs; 8914359Smckusick 8926294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 8936294Smckusick if (mp->m_bufp == NULL || mp->m_dev != dev) 8946294Smckusick continue; 8956294Smckusick fs = mp->m_bufp->b_un.b_fs; 8966716Smckusick if (fs->fs_magic != FS_MAGIC) { 8976716Smckusick printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt); 8986294Smckusick panic("getfs: bad magic"); 8996716Smckusick } 9006294Smckusick return (fs); 9016294Smckusick } 9026716Smckusick printf("dev = 0x%x\n", dev); 9034359Smckusick panic("getfs: no fs"); 9044359Smckusick return (NULL); 9054359Smckusick } 9064359Smckusick 9074359Smckusick /* 9085375Smckusic * Fserr prints the name of a file system with an error diagnostic. 9095375Smckusic * 9105375Smckusic * The form of the error message is: 9114359Smckusick * fs: error message 9124359Smckusick */ 9134359Smckusick fserr(fs, cp) 9144359Smckusick struct fs *fs; 9154359Smckusick char *cp; 9164359Smckusick { 9174359Smckusick 9184359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 9194359Smckusick } 9204359Smckusick 9214359Smckusick /* 9224359Smckusick * Getfsx returns the index in the file system 9234359Smckusick * table of the specified device. The swap device 9244359Smckusick * is also assigned a pseudo-index. The index may 9254359Smckusick * be used as a compressed indication of the location 9264359Smckusick * of a block, recording 9274359Smckusick * <getfsx(dev),blkno> 9284359Smckusick * rather than 9294359Smckusick * <dev, blkno> 9304359Smckusick * provided the information need remain valid only 9314359Smckusick * as long as the file system is mounted. 9324359Smckusick */ 9334359Smckusick getfsx(dev) 9344359Smckusick dev_t dev; 9354359Smckusick { 9364359Smckusick register struct mount *mp; 9374359Smckusick 9384359Smckusick if (dev == swapdev) 9394359Smckusick return (MSWAPX); 9404359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9414359Smckusick if (mp->m_dev == dev) 9424359Smckusick return (mp - &mount[0]); 9434359Smckusick return (-1); 9444359Smckusick } 9454359Smckusick 9464359Smckusick /* 9474359Smckusick * Update is the internal name of 'sync'. It goes through the disk 9484359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 9495375Smckusic * modified nodes; and it goes through the mount table to initiate 9505375Smckusic * the writing of the modified super blocks. 9514359Smckusick */ 9528591Sroot update() 9534359Smckusick { 9544359Smckusick register struct inode *ip; 9554359Smckusick register struct mount *mp; 9564359Smckusick struct fs *fs; 9574359Smckusick 9584359Smckusick if (updlock) 9594359Smckusick return; 9604359Smckusick updlock++; 9614359Smckusick /* 9624359Smckusick * Write back modified superblocks. 9634359Smckusick * Consistency check that the superblock 9644359Smckusick * of each file system is still in the buffer cache. 9654359Smckusick */ 9666294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 9676294Smckusick if (mp->m_bufp == NULL) 9686294Smckusick continue; 9696294Smckusick fs = mp->m_bufp->b_un.b_fs; 9706294Smckusick if (fs->fs_fmod == 0) 9716294Smckusick continue; 9728591Sroot if (fs->fs_ronly != 0) { /* XXX */ 9736716Smckusick printf("fs = %s\n", fs->fs_fsmnt); 9746294Smckusick panic("update: rofs mod"); 9756716Smckusick } 9766294Smckusick fs->fs_fmod = 0; 9778105Sroot fs->fs_time = time.tv_sec; 9787187Sroot sbupdate(mp); 9796294Smckusick } 9804359Smckusick /* 9814359Smckusick * Write back each (modified) inode. 9824359Smckusick */ 9836294Smckusick for (ip = inode; ip < inodeNINODE; ip++) { 9848451Sroot if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0) 9856294Smckusick continue; 9868451Sroot ip->i_flag |= ILOCKED; 9876294Smckusick ip->i_count++; 9888105Sroot iupdat(ip, &time.tv_sec, &time.tv_sec, 0); 9896294Smckusick iput(ip); 9906294Smckusick } 9914359Smckusick updlock = 0; 9924359Smckusick /* 9934359Smckusick * Force stale buffer cache information to be flushed, 9944359Smckusick * for all devices. 9954359Smckusick */ 9964359Smckusick bflush(NODEV); 9974359Smckusick } 9985322Smckusic 999