14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*6310Smckusick static char vers[] = "@(#)lfs_alloc.c 1.22 03/25/82"; 44359Smckusick 54359Smckusick /* alloc.c 4.8 81/03/08 */ 64359Smckusick 74359Smckusick #include "../h/param.h" 84359Smckusick #include "../h/systm.h" 94359Smckusick #include "../h/mount.h" 104359Smckusick #include "../h/fs.h" 114359Smckusick #include "../h/conf.h" 124359Smckusick #include "../h/buf.h" 134359Smckusick #include "../h/inode.h" 14*6310Smckusick #include "../h/ndir.h" 154359Smckusick #include "../h/user.h" 164359Smckusick 175212Smckusic extern u_long hashalloc(); 185212Smckusic extern ino_t ialloccg(); 194651Smckusic extern daddr_t alloccg(); 204651Smckusic extern daddr_t alloccgblk(); 214651Smckusic extern daddr_t fragextend(); 224651Smckusic extern daddr_t blkpref(); 234651Smckusic extern daddr_t mapsearch(); 244607Smckusic extern int inside[], around[]; 255322Smckusic extern unsigned char *fragtbl[]; 264359Smckusick 275375Smckusic /* 285375Smckusic * Allocate a block in the file system. 295375Smckusic * 305375Smckusic * The size of the requested block is given, which must be some 315375Smckusic * multiple of fs_fsize and <= fs_bsize. 325375Smckusic * A preference may be optionally specified. If a preference is given 335375Smckusic * the following hierarchy is used to allocate a block: 345375Smckusic * 1) allocate the requested block. 355375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 365375Smckusic * 3) allocate a block in the same cylinder group. 375375Smckusic * 4) quadradically rehash into other cylinder groups, until an 385375Smckusic * available block is located. 395375Smckusic * If no block preference is given the following heirarchy is used 405375Smckusic * to allocate a block: 415375Smckusic * 1) allocate a block in the cylinder group that contains the 425375Smckusic * inode for the file. 435375Smckusic * 2) quadradically rehash into other cylinder groups, until an 445375Smckusic * available block is located. 455375Smckusic */ 464359Smckusick struct buf * 475965Smckusic alloc(ip, bpref, size) 484463Smckusic register struct inode *ip; 494359Smckusick daddr_t bpref; 504359Smckusick int size; 514359Smckusick { 524359Smckusick daddr_t bno; 534359Smckusick register struct fs *fs; 544463Smckusic register struct buf *bp; 554359Smckusick int cg; 564359Smckusick 575965Smckusic fs = ip->i_fs; 585960Smckusic if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) 594463Smckusic panic("alloc: bad size"); 605322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 614359Smckusick goto nospace; 624792Smckusic if (u.u_uid != 0 && 635322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 645322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 654792Smckusic goto nospace; 664948Smckusic if (bpref >= fs->fs_size) 674948Smckusic bpref = 0; 684359Smckusick if (bpref == 0) 695377Smckusic cg = itog(fs, ip->i_number); 704359Smckusick else 715377Smckusic cg = dtog(fs, bpref); 725965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, alloccg); 734359Smckusick if (bno == 0) 744359Smckusick goto nospace; 755965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), size); 764359Smckusick clrbuf(bp); 774359Smckusick return (bp); 784359Smckusick nospace: 794359Smckusick fserr(fs, "file system full"); 804359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 814359Smckusick u.u_error = ENOSPC; 824359Smckusick return (NULL); 834359Smckusick } 844359Smckusick 855375Smckusic /* 865375Smckusic * Reallocate a fragment to a bigger size 875375Smckusic * 885375Smckusic * The number and size of the old block is given, and a preference 895375Smckusic * and new size is also specified. The allocator attempts to extend 905375Smckusic * the original block. Failing that, the regular block allocator is 915375Smckusic * invoked to get an appropriate block. 925375Smckusic */ 934426Smckusic struct buf * 945965Smckusic realloccg(ip, bprev, bpref, osize, nsize) 955965Smckusic register struct inode *ip; 964651Smckusic daddr_t bprev, bpref; 974426Smckusic int osize, nsize; 984426Smckusic { 994426Smckusic daddr_t bno; 1004426Smckusic register struct fs *fs; 1014463Smckusic register struct buf *bp, *obp; 1024463Smckusic caddr_t cp; 1034426Smckusic int cg; 1044426Smckusic 1055965Smckusic fs = ip->i_fs; 1065960Smckusic if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || 1075960Smckusic (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) 1084463Smckusic panic("realloccg: bad size"); 1094792Smckusic if (u.u_uid != 0 && 1105322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 1115322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 1124792Smckusic goto nospace; 1136294Smckusick if (bprev == 0) 1144463Smckusic panic("realloccg: bad bprev"); 1156294Smckusick cg = dtog(fs, bprev); 1165965Smckusic bno = fragextend(ip, cg, (long)bprev, osize, nsize); 1174463Smckusic if (bno != 0) { 1185965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bno), osize); 1195960Smckusic if (bp->b_flags & B_ERROR) { 1205960Smckusic brelse(bp); 1216294Smckusick return (NULL); 1225960Smckusic } 1234463Smckusic bp->b_bcount = nsize; 1244463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1254463Smckusic return (bp); 1264463Smckusic } 1274948Smckusic if (bpref >= fs->fs_size) 1284948Smckusic bpref = 0; 1295965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, nsize, alloccg); 1304463Smckusic if (bno != 0) { 1314463Smckusic /* 1324463Smckusic * make a new copy 1334463Smckusic */ 1345965Smckusic obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize); 1355960Smckusic if (obp->b_flags & B_ERROR) { 1365960Smckusic brelse(obp); 1376294Smckusick return (NULL); 1385960Smckusic } 1395965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), nsize); 1404463Smckusic cp = bp->b_un.b_addr; 1414463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1424463Smckusic obp->b_un.b_addr = cp; 1434463Smckusic obp->b_flags |= B_INVAL; 1444463Smckusic brelse(obp); 1455965Smckusic fre(ip, bprev, (off_t)osize); 1464463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1476294Smckusick return (bp); 1484463Smckusic } 1494792Smckusic nospace: 1504463Smckusic /* 1514463Smckusic * no space available 1524463Smckusic */ 1534426Smckusic fserr(fs, "file system full"); 1544426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1554426Smckusic u.u_error = ENOSPC; 1564426Smckusic return (NULL); 1574426Smckusic } 1584426Smckusic 1595375Smckusic /* 1605375Smckusic * Allocate an inode in the file system. 1615375Smckusic * 1625375Smckusic * A preference may be optionally specified. If a preference is given 1635375Smckusic * the following hierarchy is used to allocate an inode: 1645375Smckusic * 1) allocate the requested inode. 1655375Smckusic * 2) allocate an inode in the same cylinder group. 1665375Smckusic * 3) quadradically rehash into other cylinder groups, until an 1675375Smckusic * available inode is located. 1685375Smckusic * If no inode preference is given the following heirarchy is used 1695375Smckusic * to allocate an inode: 1705375Smckusic * 1) allocate an inode in cylinder group 0. 1715375Smckusic * 2) quadradically rehash into other cylinder groups, until an 1725375Smckusic * available inode is located. 1735375Smckusic */ 1744359Smckusick struct inode * 1755965Smckusic ialloc(pip, ipref, mode) 1765965Smckusic register struct inode *pip; 1774359Smckusick ino_t ipref; 1784359Smckusick int mode; 1794359Smckusick { 1805212Smckusic ino_t ino; 1814359Smckusick register struct fs *fs; 1824359Smckusick register struct inode *ip; 1834359Smckusick int cg; 1844359Smckusick 1855965Smckusic fs = pip->i_fs; 1864792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1874359Smckusick goto noinodes; 1884948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 1894948Smckusic ipref = 0; 1905377Smckusic cg = itog(fs, ipref); 1915965Smckusic ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); 1924359Smckusick if (ino == 0) 1934359Smckusick goto noinodes; 1945965Smckusic ip = iget(pip->i_dev, pip->i_fs, ino); 1954359Smckusick if (ip == NULL) { 1965965Smckusic ifree(ip, ino, 0); 1974359Smckusick return (NULL); 1984359Smckusick } 1994359Smckusick if (ip->i_mode) 2004359Smckusick panic("ialloc: dup alloc"); 2014359Smckusick return (ip); 2024359Smckusick noinodes: 2034359Smckusick fserr(fs, "out of inodes"); 2046294Smckusick uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 2054359Smckusick u.u_error = ENOSPC; 2064359Smckusick return (NULL); 2074359Smckusick } 2084359Smckusick 2094651Smckusic /* 2105375Smckusic * Find a cylinder to place a directory. 2115375Smckusic * 2125375Smckusic * The policy implemented by this algorithm is to select from 2135375Smckusic * among those cylinder groups with above the average number of 2145375Smckusic * free inodes, the one with the smallest number of directories. 2154651Smckusic */ 2165965Smckusic dirpref(fs) 2175965Smckusic register struct fs *fs; 2184359Smckusick { 2194651Smckusic int cg, minndir, mincg, avgifree; 2204359Smckusick 2214792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 2224651Smckusic minndir = fs->fs_ipg; 2234359Smckusick mincg = 0; 2244651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 2255322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 2265322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 2274359Smckusick mincg = cg; 2285322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 2294359Smckusick } 2304359Smckusick return (fs->fs_ipg * mincg); 2314359Smckusick } 2324359Smckusick 2334651Smckusic /* 2345375Smckusic * Select a cylinder to place a large block of data. 2355375Smckusic * 2365375Smckusic * The policy implemented by this algorithm is to maintain a 2375375Smckusic * rotor that sweeps the cylinder groups. When a block is 2385375Smckusic * needed, the rotor is advanced until a cylinder group with 2395375Smckusic * greater than the average number of free blocks is found. 2404651Smckusic */ 2415212Smckusic daddr_t 2425965Smckusic blkpref(fs) 2435965Smckusic register struct fs *fs; 2444651Smckusic { 2454651Smckusic int cg, avgbfree; 2464651Smckusic 2474792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 2484651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 2495322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2504651Smckusic fs->fs_cgrotor = cg; 2515322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2524651Smckusic } 2534651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 2545322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2554651Smckusic fs->fs_cgrotor = cg; 2565322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2574651Smckusic } 2586294Smckusick return (NULL); 2594651Smckusic } 2604651Smckusic 2615375Smckusic /* 2625375Smckusic * Implement the cylinder overflow algorithm. 2635375Smckusic * 2645375Smckusic * The policy implemented by this algorithm is: 2655375Smckusic * 1) allocate the block in its requested cylinder group. 2665375Smckusic * 2) quadradically rehash on the cylinder group number. 2675375Smckusic * 3) brute force search for a free block. 2685375Smckusic */ 2695212Smckusic /*VARARGS5*/ 2705212Smckusic u_long 2715965Smckusic hashalloc(ip, cg, pref, size, allocator) 2725965Smckusic struct inode *ip; 2734359Smckusick int cg; 2744359Smckusick long pref; 2754359Smckusick int size; /* size for data blocks, mode for inodes */ 2765212Smckusic u_long (*allocator)(); 2774359Smckusick { 2785965Smckusic register struct fs *fs; 2794359Smckusick long result; 2804359Smckusick int i, icg = cg; 2814359Smckusick 2825965Smckusic fs = ip->i_fs; 2834359Smckusick /* 2844359Smckusick * 1: preferred cylinder group 2854359Smckusick */ 2865965Smckusic result = (*allocator)(ip, cg, pref, size); 2874359Smckusick if (result) 2884359Smckusick return (result); 2894359Smckusick /* 2904359Smckusick * 2: quadratic rehash 2914359Smckusick */ 2924359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2934359Smckusick cg += i; 2944359Smckusick if (cg >= fs->fs_ncg) 2954359Smckusick cg -= fs->fs_ncg; 2965965Smckusic result = (*allocator)(ip, cg, 0, size); 2974359Smckusick if (result) 2984359Smckusick return (result); 2994359Smckusick } 3004359Smckusick /* 3014359Smckusick * 3: brute force search 3024359Smckusick */ 3034359Smckusick cg = icg; 3044359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 3055965Smckusic result = (*allocator)(ip, cg, 0, size); 3064359Smckusick if (result) 3074359Smckusick return (result); 3084359Smckusick cg++; 3094359Smckusick if (cg == fs->fs_ncg) 3104359Smckusick cg = 0; 3114359Smckusick } 3126294Smckusick return (NULL); 3134359Smckusick } 3144359Smckusick 3155375Smckusic /* 3165375Smckusic * Determine whether a fragment can be extended. 3175375Smckusic * 3185375Smckusic * Check to see if the necessary fragments are available, and 3195375Smckusic * if they are, allocate them. 3205375Smckusic */ 3214359Smckusick daddr_t 3225965Smckusic fragextend(ip, cg, bprev, osize, nsize) 3235965Smckusic struct inode *ip; 3244426Smckusic int cg; 3254463Smckusic long bprev; 3264426Smckusic int osize, nsize; 3274426Smckusic { 3285965Smckusic register struct fs *fs; 3294463Smckusic register struct buf *bp; 3304463Smckusic register struct cg *cgp; 3314463Smckusic long bno; 3324463Smckusic int frags, bbase; 3334426Smckusic int i; 3344426Smckusic 3355965Smckusic fs = ip->i_fs; 3365960Smckusic frags = numfrags(fs, nsize); 3375960Smckusic bbase = fragoff(fs, bprev); 3385322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 3394463Smckusic /* cannot extend across a block boundry */ 3406294Smckusick return (NULL); 3414463Smckusic } 3425965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 3435960Smckusic if (bp->b_flags & B_ERROR) { 3445960Smckusic brelse(bp); 3456294Smckusick return (NULL); 3465960Smckusic } 3474426Smckusic cgp = bp->b_un.b_cg; 3485377Smckusic bno = dtogd(fs, bprev); 3495960Smckusic for (i = numfrags(fs, osize); i < frags; i++) 3505361Smckusic if (isclr(cgp->cg_free, bno + i)) { 3515361Smckusic brelse(bp); 3526294Smckusick return (NULL); 3535361Smckusic } 3545361Smckusic /* 3555361Smckusic * the current fragment can be extended 3565361Smckusic * deduct the count on fragment being extended into 3575361Smckusic * increase the count on the remaining fragment (if any) 3585361Smckusic * allocate the extended piece 3595361Smckusic */ 3605361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 3614463Smckusic if (isclr(cgp->cg_free, bno + i)) 3624463Smckusic break; 3635960Smckusic cgp->cg_frsum[i - numfrags(fs, osize)]--; 3645361Smckusic if (i != frags) 3655361Smckusic cgp->cg_frsum[i - frags]++; 3665960Smckusic for (i = numfrags(fs, osize); i < frags; i++) { 3675361Smckusic clrbit(cgp->cg_free, bno + i); 3685361Smckusic cgp->cg_cs.cs_nffree--; 3695361Smckusic fs->fs_cstotal.cs_nffree--; 3705361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3714463Smckusic } 3725361Smckusic fs->fs_fmod++; 3735361Smckusic bdwrite(bp); 3745361Smckusic return (bprev); 3754426Smckusic } 3764426Smckusic 3775375Smckusic /* 3785375Smckusic * Determine whether a block can be allocated. 3795375Smckusic * 3805375Smckusic * Check to see if a block of the apprpriate size is available, 3815375Smckusic * and if it is, allocate it. 3825375Smckusic */ 3834426Smckusic daddr_t 3845965Smckusic alloccg(ip, cg, bpref, size) 3855965Smckusic struct inode *ip; 3864359Smckusick int cg; 3874359Smckusick daddr_t bpref; 3884359Smckusick int size; 3894359Smckusick { 3905965Smckusic register struct fs *fs; 3914463Smckusic register struct buf *bp; 3924463Smckusic register struct cg *cgp; 3934463Smckusic int bno, frags; 3944463Smckusic int allocsiz; 3954463Smckusic register int i; 3964359Smckusick 3975965Smckusic fs = ip->i_fs; 3985322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 3996294Smckusick return (NULL); 4005965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 4015960Smckusic if (bp->b_flags & B_ERROR) { 4025960Smckusic brelse(bp); 4036294Smckusick return (NULL); 4045960Smckusic } 4054359Smckusick cgp = bp->b_un.b_cg; 4065322Smckusic if (size == fs->fs_bsize) { 4075212Smckusic bno = alloccgblk(fs, cgp, bpref); 4084463Smckusic bdwrite(bp); 4094463Smckusic return (bno); 4104463Smckusic } 4114463Smckusic /* 4124463Smckusic * check to see if any fragments are already available 4134463Smckusic * allocsiz is the size which will be allocated, hacking 4144463Smckusic * it down to a smaller size if necessary 4154463Smckusic */ 4165960Smckusic frags = numfrags(fs, size); 4175322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 4184463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 4194463Smckusic break; 4205322Smckusic if (allocsiz == fs->fs_frag) { 4214463Smckusic /* 4224463Smckusic * no fragments were available, so a block will be 4234463Smckusic * allocated, and hacked up 4244463Smckusic */ 4254792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 4264463Smckusic brelse(bp); 4276294Smckusick return (NULL); 4284463Smckusic } 4295212Smckusic bno = alloccgblk(fs, cgp, bpref); 4305377Smckusic bpref = dtogd(fs, bno); 4315322Smckusic for (i = frags; i < fs->fs_frag; i++) 4324463Smckusic setbit(cgp->cg_free, bpref + i); 4335322Smckusic i = fs->fs_frag - frags; 4344792Smckusic cgp->cg_cs.cs_nffree += i; 4354792Smckusic fs->fs_cstotal.cs_nffree += i; 4365322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 4374463Smckusic cgp->cg_frsum[i]++; 4384463Smckusic bdwrite(bp); 4394463Smckusic return (bno); 4404463Smckusic } 4414651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 4424651Smckusic if (bno == 0) 4436294Smckusick return (NULL); 4444463Smckusic for (i = 0; i < frags; i++) 4454463Smckusic clrbit(cgp->cg_free, bno + i); 4464792Smckusic cgp->cg_cs.cs_nffree -= frags; 4474792Smckusic fs->fs_cstotal.cs_nffree -= frags; 4485322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 4494463Smckusic cgp->cg_frsum[allocsiz]--; 4504463Smckusic if (frags != allocsiz) 4514463Smckusic cgp->cg_frsum[allocsiz - frags]++; 4524463Smckusic bdwrite(bp); 4534463Smckusic return (cg * fs->fs_fpg + bno); 4544463Smckusic } 4554463Smckusic 4565375Smckusic /* 4575375Smckusic * Allocate a block in a cylinder group. 4585375Smckusic * 4595375Smckusic * This algorithm implements the following policy: 4605375Smckusic * 1) allocate the requested block. 4615375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 4625375Smckusic * 3) allocate the next available block on the block rotor for the 4635375Smckusic * specified cylinder group. 4645375Smckusic * Note that this routine only allocates fs_bsize blocks; these 4655375Smckusic * blocks may be fragmented by the routine that allocates them. 4665375Smckusic */ 4674463Smckusic daddr_t 4685212Smckusic alloccgblk(fs, cgp, bpref) 4695965Smckusic register struct fs *fs; 4704463Smckusic register struct cg *cgp; 4714463Smckusic daddr_t bpref; 4724463Smckusic { 4734651Smckusic daddr_t bno; 4746294Smckusick int cylno, pos, delta; 4754651Smckusic short *cylbp; 4765361Smckusic register int i; 4774463Smckusic 4784651Smckusic if (bpref == 0) { 4794651Smckusic bpref = cgp->cg_rotor; 4805361Smckusic goto norot; 4815361Smckusic } 4825361Smckusic bpref &= ~(fs->fs_frag - 1); 4835377Smckusic bpref = dtogd(fs, bpref); 4845361Smckusic /* 4855361Smckusic * if the requested block is available, use it 4865361Smckusic */ 4875361Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 4885361Smckusic bno = bpref; 4895361Smckusic goto gotit; 4905361Smckusic } 4915361Smckusic /* 4925361Smckusic * check for a block available on the same cylinder 4935361Smckusic */ 4945361Smckusic cylno = cbtocylno(fs, bpref); 4955375Smckusic if (cgp->cg_btot[cylno] == 0) 4965375Smckusic goto norot; 4975375Smckusic if (fs->fs_cpc == 0) { 4985375Smckusic /* 4995375Smckusic * block layout info is not available, so just have 5005375Smckusic * to take any block in this cylinder. 5015375Smckusic */ 5025375Smckusic bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); 5035375Smckusic goto norot; 5045375Smckusic } 5055375Smckusic /* 5065375Smckusic * find a block that is rotationally optimal 5075375Smckusic */ 5085361Smckusic cylbp = cgp->cg_b[cylno]; 5095361Smckusic if (fs->fs_rotdelay == 0) { 5105361Smckusic pos = cbtorpos(fs, bpref); 5114651Smckusic } else { 5124651Smckusic /* 5135361Smckusic * here we convert ms of delay to frags as: 5145361Smckusic * (frags) = (ms) * (rev/sec) * (sect/rev) / 5155361Smckusic * ((sect/frag) * (ms/sec)) 5165361Smckusic * then round up to the next rotational position 5174651Smckusic */ 5185361Smckusic bpref += fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 5195361Smckusic (NSPF(fs) * 1000); 5205361Smckusic pos = cbtorpos(fs, bpref); 5215361Smckusic pos = (pos + 1) % NRPOS; 5225361Smckusic } 5235361Smckusic /* 5245361Smckusic * check the summary information to see if a block is 5255361Smckusic * available in the requested cylinder starting at the 5265361Smckusic * optimal rotational position and proceeding around. 5275361Smckusic */ 5285361Smckusic for (i = pos; i < NRPOS; i++) 5295361Smckusic if (cylbp[i] > 0) 5305361Smckusic break; 5315361Smckusic if (i == NRPOS) 5325361Smckusic for (i = 0; i < pos; i++) 5335361Smckusic if (cylbp[i] > 0) 5345361Smckusic break; 5355361Smckusic if (cylbp[i] > 0) { 5364651Smckusic /* 5375361Smckusic * found a rotational position, now find the actual 5385361Smckusic * block. A panic if none is actually there. 5394651Smckusic */ 5405361Smckusic pos = cylno % fs->fs_cpc; 5415361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 5425361Smckusic if (fs->fs_postbl[pos][i] == -1) 5435361Smckusic panic("alloccgblk: cyl groups corrupted"); 5446294Smckusick for (i = fs->fs_postbl[pos][i];; ) { 5455361Smckusic if (isblock(fs, cgp->cg_free, bno + i)) { 5465361Smckusic bno = (bno + i) * fs->fs_frag; 5475361Smckusic goto gotit; 5485361Smckusic } 5496294Smckusick delta = fs->fs_rotbl[i]; 5506294Smckusick if (delta <= 0 || delta > MAXBPC - i) 5514651Smckusic break; 5526294Smckusick i += delta; 5534651Smckusic } 5545361Smckusic panic("alloccgblk: can't find blk in cyl"); 5554359Smckusick } 5565361Smckusic norot: 5575361Smckusic /* 5585361Smckusic * no blocks in the requested cylinder, so take next 5595361Smckusic * available one in this cylinder group. 5605361Smckusic */ 5615322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 5624651Smckusic if (bno == 0) 5636294Smckusick return (NULL); 5644651Smckusic cgp->cg_rotor = bno; 5654359Smckusick gotit: 5665322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 5674792Smckusic cgp->cg_cs.cs_nbfree--; 5684792Smckusic fs->fs_cstotal.cs_nbfree--; 5695322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 5705375Smckusic cylno = cbtocylno(fs, bno); 5715375Smckusic cgp->cg_b[cylno][cbtorpos(fs, bno)]--; 5725375Smckusic cgp->cg_btot[cylno]--; 5734359Smckusick fs->fs_fmod++; 5744651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 5754359Smckusick } 5764359Smckusick 5775375Smckusic /* 5785375Smckusic * Determine whether an inode can be allocated. 5795375Smckusic * 5805375Smckusic * Check to see if an inode is available, and if it is, 5815375Smckusic * allocate it using the following policy: 5825375Smckusic * 1) allocate the requested inode. 5835375Smckusic * 2) allocate the next available inode after the requested 5845375Smckusic * inode in the specified cylinder group. 5855375Smckusic */ 5865212Smckusic ino_t 5875965Smckusic ialloccg(ip, cg, ipref, mode) 5885965Smckusic struct inode *ip; 5894359Smckusick int cg; 5904359Smckusick daddr_t ipref; 5914359Smckusick int mode; 5924359Smckusick { 5935965Smckusic register struct fs *fs; 5944463Smckusic register struct buf *bp; 5954463Smckusic register struct cg *cgp; 5964359Smckusick int i; 5974359Smckusick 5985965Smckusic fs = ip->i_fs; 5995322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 6006294Smckusick return (NULL); 6015965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 6025960Smckusic if (bp->b_flags & B_ERROR) { 6035960Smckusic brelse(bp); 6046294Smckusick return (NULL); 6055960Smckusic } 6064359Smckusick cgp = bp->b_un.b_cg; 6074359Smckusick if (ipref) { 6084359Smckusick ipref %= fs->fs_ipg; 6094359Smckusick if (isclr(cgp->cg_iused, ipref)) 6104359Smckusick goto gotit; 6114359Smckusick } else 6124359Smckusick ipref = cgp->cg_irotor; 6134359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 6144359Smckusick ipref++; 6154359Smckusick if (ipref >= fs->fs_ipg) 6164359Smckusick ipref = 0; 6174359Smckusick if (isclr(cgp->cg_iused, ipref)) { 6184359Smckusick cgp->cg_irotor = ipref; 6194359Smckusick goto gotit; 6204359Smckusick } 6214359Smckusick } 6224359Smckusick brelse(bp); 6236294Smckusick return (NULL); 6244359Smckusick gotit: 6254359Smckusick setbit(cgp->cg_iused, ipref); 6264792Smckusic cgp->cg_cs.cs_nifree--; 6274792Smckusic fs->fs_cstotal.cs_nifree--; 6285322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 6294359Smckusick fs->fs_fmod++; 6304359Smckusick if ((mode & IFMT) == IFDIR) { 6314792Smckusic cgp->cg_cs.cs_ndir++; 6324792Smckusic fs->fs_cstotal.cs_ndir++; 6335322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 6344359Smckusick } 6354359Smckusick bdwrite(bp); 6364359Smckusick return (cg * fs->fs_ipg + ipref); 6374359Smckusick } 6384359Smckusick 6395375Smckusic /* 6405375Smckusic * Free a block or fragment. 6415375Smckusic * 6425375Smckusic * The specified block or fragment is placed back in the 6435375Smckusic * free map. If a fragment is deallocated, a possible 6445375Smckusic * block reassembly is checked. 6455375Smckusic */ 6465965Smckusic fre(ip, bno, size) 6475965Smckusic register struct inode *ip; 6484359Smckusick daddr_t bno; 6495212Smckusic off_t size; 6504359Smckusick { 6514359Smckusick register struct fs *fs; 6524359Smckusick register struct cg *cgp; 6534359Smckusick register struct buf *bp; 6544463Smckusic int cg, blk, frags, bbase; 6554463Smckusic register int i; 6564359Smckusick 6575965Smckusic fs = ip->i_fs; 6585960Smckusic if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) 6594426Smckusic panic("free: bad size"); 6605377Smckusic cg = dtog(fs, bno); 6614359Smckusick if (badblock(fs, bno)) 6624359Smckusick return; 6635965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 6645960Smckusic if (bp->b_flags & B_ERROR) { 6655960Smckusic brelse(bp); 6664359Smckusick return; 6675960Smckusic } 6684359Smckusick cgp = bp->b_un.b_cg; 6695377Smckusic bno = dtogd(fs, bno); 6705322Smckusic if (size == fs->fs_bsize) { 6715322Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) 6724426Smckusic panic("free: freeing free block"); 6735322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 6744792Smckusic cgp->cg_cs.cs_nbfree++; 6754792Smckusic fs->fs_cstotal.cs_nbfree++; 6765322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 6775375Smckusic i = cbtocylno(fs, bno); 6785375Smckusic cgp->cg_b[i][cbtorpos(fs, bno)]++; 6795375Smckusic cgp->cg_btot[i]++; 6804426Smckusic } else { 6815322Smckusic bbase = bno - (bno % fs->fs_frag); 6824463Smckusic /* 6834463Smckusic * decrement the counts associated with the old frags 6844463Smckusic */ 6856294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 6865322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 6874463Smckusic /* 6884463Smckusic * deallocate the fragment 6894463Smckusic */ 6905960Smckusic frags = numfrags(fs, size); 6914463Smckusic for (i = 0; i < frags; i++) { 6924426Smckusic if (isset(cgp->cg_free, bno + i)) 6934426Smckusic panic("free: freeing free frag"); 6944426Smckusic setbit(cgp->cg_free, bno + i); 6954426Smckusic } 6966294Smckusick cgp->cg_cs.cs_nffree += i; 6976294Smckusick fs->fs_cstotal.cs_nffree += i; 6986294Smckusick fs->fs_cs(fs, cg).cs_nffree += i; 6994463Smckusic /* 7004463Smckusic * add back in counts associated with the new frags 7014463Smckusic */ 7026294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 7035322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 7044463Smckusic /* 7054463Smckusic * if a complete block has been reassembled, account for it 7064463Smckusic */ 7075322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 7085322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 7095322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 7105322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 7114792Smckusic cgp->cg_cs.cs_nbfree++; 7124792Smckusic fs->fs_cstotal.cs_nbfree++; 7135322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 7145375Smckusic i = cbtocylno(fs, bbase); 7155375Smckusic cgp->cg_b[i][cbtorpos(fs, bbase)]++; 7165375Smckusic cgp->cg_btot[i]++; 7174426Smckusic } 7184426Smckusic } 7194359Smckusick fs->fs_fmod++; 7204359Smckusick bdwrite(bp); 7214359Smckusick } 7224359Smckusick 7235375Smckusic /* 7245375Smckusic * Free an inode. 7255375Smckusic * 7265375Smckusic * The specified inode is placed back in the free map. 7275375Smckusic */ 7285965Smckusic ifree(ip, ino, mode) 7295965Smckusic struct inode *ip; 7304359Smckusick ino_t ino; 7314359Smckusick int mode; 7324359Smckusick { 7334359Smckusick register struct fs *fs; 7344359Smckusick register struct cg *cgp; 7354359Smckusick register struct buf *bp; 7364359Smckusick int cg; 7374359Smckusick 7385965Smckusic fs = ip->i_fs; 7394359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 7404359Smckusick panic("ifree: range"); 7415377Smckusic cg = itog(fs, ino); 7425965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 7435960Smckusic if (bp->b_flags & B_ERROR) { 7445960Smckusic brelse(bp); 7454359Smckusick return; 7465960Smckusic } 7474359Smckusick cgp = bp->b_un.b_cg; 7484359Smckusick ino %= fs->fs_ipg; 7494359Smckusick if (isclr(cgp->cg_iused, ino)) 7504359Smckusick panic("ifree: freeing free inode"); 7514359Smckusick clrbit(cgp->cg_iused, ino); 7524792Smckusic cgp->cg_cs.cs_nifree++; 7534792Smckusic fs->fs_cstotal.cs_nifree++; 7545322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 7554359Smckusick if ((mode & IFMT) == IFDIR) { 7564792Smckusic cgp->cg_cs.cs_ndir--; 7574792Smckusic fs->fs_cstotal.cs_ndir--; 7585322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 7594359Smckusick } 7604359Smckusick fs->fs_fmod++; 7614359Smckusick bdwrite(bp); 7624359Smckusick } 7634359Smckusick 7644463Smckusic /* 7655375Smckusic * Find a block of the specified size in the specified cylinder group. 7665375Smckusic * 7674651Smckusic * It is a panic if a request is made to find a block if none are 7684651Smckusic * available. 7694651Smckusic */ 7704651Smckusic daddr_t 7714651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 7724651Smckusic register struct fs *fs; 7734651Smckusic register struct cg *cgp; 7744651Smckusic daddr_t bpref; 7754651Smckusic int allocsiz; 7764651Smckusic { 7774651Smckusic daddr_t bno; 7784651Smckusic int start, len, loc, i; 7794651Smckusic int blk, field, subfield, pos; 7804651Smckusic 7814651Smckusic /* 7824651Smckusic * find the fragment by searching through the free block 7834651Smckusic * map for an appropriate bit pattern 7844651Smckusic */ 7854651Smckusic if (bpref) 7865377Smckusic start = dtogd(fs, bpref) / NBBY; 7874651Smckusic else 7884651Smckusic start = cgp->cg_frotor / NBBY; 7895398Smckusic len = howmany(fs->fs_fpg, NBBY) - start; 7905322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7916292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 7924651Smckusic if (loc == 0) { 7935398Smckusic loc = fs->fs_dblkno / NBBY; 7945398Smckusic len = start - loc + 1; 7955398Smckusic start = loc; 7965322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7976292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 7984651Smckusic if (loc == 0) { 7994651Smckusic panic("alloccg: map corrupted"); 8006294Smckusick return (NULL); 8014651Smckusic } 8024651Smckusic } 8034651Smckusic bno = (start + len - loc) * NBBY; 8044651Smckusic cgp->cg_frotor = bno; 8054651Smckusic /* 8064651Smckusic * found the byte in the map 8074651Smckusic * sift through the bits to find the selected frag 8084651Smckusic */ 8096294Smckusick for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { 8106294Smckusick blk = blkmap(fs, cgp->cg_free, bno); 8114651Smckusic blk <<= 1; 8124651Smckusic field = around[allocsiz]; 8134651Smckusic subfield = inside[allocsiz]; 8145322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 8156294Smckusick if ((blk & field) == subfield) 8166294Smckusick return (bno + pos); 8174651Smckusic field <<= 1; 8184651Smckusic subfield <<= 1; 8194651Smckusic } 8204651Smckusic } 8214651Smckusic panic("alloccg: block not in map"); 8226294Smckusick return (NULL); 8234651Smckusic } 8244651Smckusic 8254651Smckusic /* 8265375Smckusic * Update the frsum fields to reflect addition or deletion 8275375Smckusic * of some frags. 8284463Smckusic */ 8295322Smckusic fragacct(fs, fragmap, fraglist, cnt) 8305322Smckusic struct fs *fs; 8314472Smckusic int fragmap; 8324792Smckusic long fraglist[]; 8334463Smckusic int cnt; 8344463Smckusic { 8354463Smckusic int inblk; 8364463Smckusic register int field, subfield; 8374463Smckusic register int siz, pos; 8384463Smckusic 8395322Smckusic inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 8404463Smckusic fragmap <<= 1; 8415322Smckusic for (siz = 1; siz < fs->fs_frag; siz++) { 8426292Smckusick if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 8434463Smckusic continue; 8444463Smckusic field = around[siz]; 8454463Smckusic subfield = inside[siz]; 8465322Smckusic for (pos = siz; pos <= fs->fs_frag; pos++) { 8474463Smckusic if ((fragmap & field) == subfield) { 8484463Smckusic fraglist[siz] += cnt; 8494463Smckusic pos += siz; 8504463Smckusic field <<= siz; 8514463Smckusic subfield <<= siz; 8524463Smckusic } 8534463Smckusic field <<= 1; 8544463Smckusic subfield <<= 1; 8554463Smckusic } 8564463Smckusic } 8574463Smckusic } 8584463Smckusic 8595375Smckusic /* 8605375Smckusic * Check that a specified block number is in range. 8615375Smckusic */ 8624359Smckusick badblock(fs, bn) 8634359Smckusick register struct fs *fs; 8644359Smckusick daddr_t bn; 8654359Smckusick { 8664359Smckusick 8675377Smckusic if ((unsigned)bn >= fs->fs_size || bn < cgdmin(fs, dtog(fs, bn))) { 8684359Smckusick fserr(fs, "bad block"); 8694359Smckusick return (1); 8704359Smckusick } 8714359Smckusick return (0); 8724359Smckusick } 8734359Smckusick 8744359Smckusick /* 8755375Smckusic * Getfs maps a device number into a pointer to the incore super block. 8764359Smckusick * 8775375Smckusic * The algorithm is a linear search through the mount table. A 8785375Smckusic * consistency check of the super block magic number is performed. 8795375Smckusic * 8804359Smckusick * panic: no fs -- the device is not mounted. 8814359Smckusick * this "cannot happen" 8824359Smckusick */ 8834359Smckusick struct fs * 8844359Smckusick getfs(dev) 8854359Smckusick dev_t dev; 8864359Smckusick { 8874359Smckusick register struct mount *mp; 8884359Smckusick register struct fs *fs; 8894359Smckusick 8906294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 8916294Smckusick if (mp->m_bufp == NULL || mp->m_dev != dev) 8926294Smckusick continue; 8936294Smckusick fs = mp->m_bufp->b_un.b_fs; 8946294Smckusick if (fs->fs_magic != FS_MAGIC) 8956294Smckusick panic("getfs: bad magic"); 8966294Smckusick return (fs); 8976294Smckusick } 8984359Smckusick panic("getfs: no fs"); 8994359Smckusick return (NULL); 9004359Smckusick } 9014359Smckusick 9024359Smckusick /* 9035375Smckusic * Fserr prints the name of a file system with an error diagnostic. 9045375Smckusic * 9055375Smckusic * The form of the error message is: 9064359Smckusick * fs: error message 9074359Smckusick */ 9084359Smckusick fserr(fs, cp) 9094359Smckusick struct fs *fs; 9104359Smckusick char *cp; 9114359Smckusick { 9124359Smckusick 9134359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 9144359Smckusick } 9154359Smckusick 9164359Smckusick /* 9174359Smckusick * Getfsx returns the index in the file system 9184359Smckusick * table of the specified device. The swap device 9194359Smckusick * is also assigned a pseudo-index. The index may 9204359Smckusick * be used as a compressed indication of the location 9214359Smckusick * of a block, recording 9224359Smckusick * <getfsx(dev),blkno> 9234359Smckusick * rather than 9244359Smckusick * <dev, blkno> 9254359Smckusick * provided the information need remain valid only 9264359Smckusick * as long as the file system is mounted. 9274359Smckusick */ 9284359Smckusick getfsx(dev) 9294359Smckusick dev_t dev; 9304359Smckusick { 9314359Smckusick register struct mount *mp; 9324359Smckusick 9334359Smckusick if (dev == swapdev) 9344359Smckusick return (MSWAPX); 9354359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9364359Smckusick if (mp->m_dev == dev) 9374359Smckusick return (mp - &mount[0]); 9384359Smckusick return (-1); 9394359Smckusick } 9404359Smckusick 9414359Smckusick /* 9424359Smckusick * Update is the internal name of 'sync'. It goes through the disk 9434359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 9445375Smckusic * modified nodes; and it goes through the mount table to initiate 9455375Smckusic * the writing of the modified super blocks. 9464359Smckusick */ 9476294Smckusick update(flag) 9486294Smckusick int flag; 9494359Smckusick { 9504359Smckusick register struct inode *ip; 9514359Smckusick register struct mount *mp; 9524359Smckusick register struct buf *bp; 9534359Smckusick struct fs *fs; 9544651Smckusic int i, blks; 9554359Smckusick 9564359Smckusick if (updlock) 9574359Smckusick return; 9584359Smckusick updlock++; 9594359Smckusick /* 9604359Smckusick * Write back modified superblocks. 9614359Smckusick * Consistency check that the superblock 9624359Smckusick * of each file system is still in the buffer cache. 9634359Smckusick */ 9646294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 9656294Smckusick if (mp->m_bufp == NULL) 9666294Smckusick continue; 9676294Smckusick fs = mp->m_bufp->b_un.b_fs; 9686294Smckusick if (fs->fs_fmod == 0) 9696294Smckusick continue; 9706294Smckusick if (fs->fs_ronly != 0) 9716294Smckusick panic("update: rofs mod"); 9726294Smckusick bp = getblk(mp->m_dev, SBLOCK, SBSIZE); 9736294Smckusick fs->fs_fmod = 0; 974*6310Smckusick fs->fs_time = time; 9756294Smckusick if (bp->b_un.b_fs != fs) 9766294Smckusick panic("update: bad b_fs"); 9776294Smckusick bwrite(bp); 9786294Smckusick blks = howmany(fs->fs_cssize, fs->fs_bsize); 9796294Smckusick for (i = 0; i < blks; i++) { 9806294Smckusick bp = getblk(mp->m_dev, 9816294Smckusick fsbtodb(fs, fs->fs_csaddr + (i * fs->fs_frag)), 9826294Smckusick fs->fs_bsize); 9834359Smckusick bwrite(bp); 9844359Smckusick } 9856294Smckusick } 9864359Smckusick /* 9874359Smckusick * Write back each (modified) inode. 9884359Smckusick */ 9896294Smckusick for (ip = inode; ip < inodeNINODE; ip++) { 9906294Smckusick if ((ip->i_flag & ILOCK) != 0 || ip->i_count == 0) 9916294Smckusick continue; 9926294Smckusick ip->i_flag |= ILOCK; 9936294Smckusick ip->i_count++; 994*6310Smckusick iupdat(ip, &time, &time, 0); 9956294Smckusick iput(ip); 9966294Smckusick } 9974359Smckusick updlock = 0; 9984359Smckusick /* 9994359Smckusick * Force stale buffer cache information to be flushed, 10004359Smckusick * for all devices. 10014359Smckusick */ 10024359Smckusick bflush(NODEV); 10034359Smckusick } 10045322Smckusic 10055322Smckusic /* 10065375Smckusic * block operations 10075375Smckusic * 10085375Smckusic * check if a block is available 10095322Smckusic */ 10105322Smckusic isblock(fs, cp, h) 10115322Smckusic struct fs *fs; 10125322Smckusic unsigned char *cp; 10135322Smckusic int h; 10145322Smckusic { 10155322Smckusic unsigned char mask; 10165322Smckusic 10175322Smckusic switch (fs->fs_frag) { 10185322Smckusic case 8: 10195322Smckusic return (cp[h] == 0xff); 10205322Smckusic case 4: 10215322Smckusic mask = 0x0f << ((h & 0x1) << 2); 10225322Smckusic return ((cp[h >> 1] & mask) == mask); 10235322Smckusic case 2: 10245322Smckusic mask = 0x03 << ((h & 0x3) << 1); 10255322Smckusic return ((cp[h >> 2] & mask) == mask); 10265322Smckusic case 1: 10275322Smckusic mask = 0x01 << (h & 0x7); 10285322Smckusic return ((cp[h >> 3] & mask) == mask); 10295322Smckusic default: 10306294Smckusick panic("isblock"); 10316294Smckusick return (NULL); 10325322Smckusic } 10335322Smckusic } 10345375Smckusic 10355375Smckusic /* 10365375Smckusic * take a block out of the map 10375375Smckusic */ 10385322Smckusic clrblock(fs, cp, h) 10395322Smckusic struct fs *fs; 10405322Smckusic unsigned char *cp; 10415322Smckusic int h; 10425322Smckusic { 10435322Smckusic switch ((fs)->fs_frag) { 10445322Smckusic case 8: 10455322Smckusic cp[h] = 0; 10465322Smckusic return; 10475322Smckusic case 4: 10485322Smckusic cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 10495322Smckusic return; 10505322Smckusic case 2: 10515322Smckusic cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 10525322Smckusic return; 10535322Smckusic case 1: 10545322Smckusic cp[h >> 3] &= ~(0x01 << (h & 0x7)); 10555322Smckusic return; 10565322Smckusic default: 10576294Smckusick panic("clrblock"); 10585322Smckusic return; 10595322Smckusic } 10605322Smckusic } 10615375Smckusic 10625375Smckusic /* 10635375Smckusic * put a block into the map 10645375Smckusic */ 10655322Smckusic setblock(fs, cp, h) 10665322Smckusic struct fs *fs; 10675322Smckusic unsigned char *cp; 10685322Smckusic int h; 10695322Smckusic { 10705322Smckusic switch (fs->fs_frag) { 10715322Smckusic case 8: 10725322Smckusic cp[h] = 0xff; 10735322Smckusic return; 10745322Smckusic case 4: 10755322Smckusic cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 10765322Smckusic return; 10775322Smckusic case 2: 10785322Smckusic cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 10795322Smckusic return; 10805322Smckusic case 1: 10815322Smckusic cp[h >> 3] |= (0x01 << (h & 0x7)); 10825322Smckusic return; 10835322Smckusic default: 10846294Smckusick panic("setblock"); 10855322Smckusic return; 10865322Smckusic } 10875322Smckusic } 1088