14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*5377Smckusic static char vers[] = "@(#)lfs_alloc.c 1.15 01/12/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" 144359Smckusick #include "../h/dir.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 * 474359Smckusick alloc(dev, ip, bpref, size) 484359Smckusick dev_t dev; 494463Smckusic register struct inode *ip; 504359Smckusick daddr_t bpref; 514359Smckusick int size; 524359Smckusick { 534359Smckusick daddr_t bno; 544359Smckusick register struct fs *fs; 554463Smckusic register struct buf *bp; 564359Smckusick int cg; 574359Smckusick 585322Smckusic fs = getfs(dev); 595322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 604463Smckusic panic("alloc: bad size"); 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; 674948Smckusic if (bpref >= fs->fs_size) 684948Smckusic bpref = 0; 694359Smckusick if (bpref == 0) 70*5377Smckusic cg = itog(fs, ip->i_number); 714359Smckusick else 72*5377Smckusic cg = dtog(fs, bpref); 735212Smckusic bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, size, alloccg); 744359Smckusick if (bno == 0) 754359Smckusick goto nospace; 765322Smckusic bp = getblk(dev, fsbtodb(fs, bno), size); 774359Smckusick clrbuf(bp); 784359Smckusick return (bp); 794359Smckusick nospace: 804359Smckusick fserr(fs, "file system full"); 814359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 824359Smckusick u.u_error = ENOSPC; 834359Smckusick return (NULL); 844359Smckusick } 854359Smckusick 865375Smckusic /* 875375Smckusic * Reallocate a fragment to a bigger size 885375Smckusic * 895375Smckusic * The number and size of the old block is given, and a preference 905375Smckusic * and new size is also specified. The allocator attempts to extend 915375Smckusic * the original block. Failing that, the regular block allocator is 925375Smckusic * invoked to get an appropriate block. 935375Smckusic */ 944426Smckusic struct buf * 955212Smckusic realloccg(dev, bprev, bpref, osize, nsize) 964426Smckusic dev_t dev; 974651Smckusic daddr_t bprev, bpref; 984426Smckusic int osize, nsize; 994426Smckusic { 1004426Smckusic daddr_t bno; 1014426Smckusic register struct fs *fs; 1024463Smckusic register struct buf *bp, *obp; 1034463Smckusic caddr_t cp; 1044426Smckusic int cg; 1054426Smckusic 1065322Smckusic fs = getfs(dev); 1075322Smckusic if ((unsigned)osize > fs->fs_bsize || osize % fs->fs_fsize != 0 || 1085322Smckusic (unsigned)nsize > fs->fs_bsize || nsize % fs->fs_fsize != 0) 1094463Smckusic panic("realloccg: bad size"); 1104792Smckusic if (u.u_uid != 0 && 1115322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 1125322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 1134792Smckusic goto nospace; 1145375Smckusic if (bprev != 0) 115*5377Smckusic cg = dtog(fs, bprev); 1165375Smckusic else 1174463Smckusic panic("realloccg: bad bprev"); 1184463Smckusic bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize); 1194463Smckusic if (bno != 0) { 1205322Smckusic bp = bread(dev, fsbtodb(fs, bno), osize); 1215361Smckusic if (bp->b_flags & B_ERROR) 1225361Smckusic return (0); 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; 1295212Smckusic bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg); 1304463Smckusic if (bno != 0) { 1314463Smckusic /* 1324463Smckusic * make a new copy 1334463Smckusic */ 1345322Smckusic obp = bread(dev, fsbtodb(fs, bprev), osize); 1355361Smckusic if (obp->b_flags & B_ERROR) 1365361Smckusic return (0); 1375322Smckusic bp = getblk(dev, fsbtodb(fs, bno), nsize); 1384463Smckusic cp = bp->b_un.b_addr; 1394463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1404463Smckusic obp->b_un.b_addr = cp; 1414463Smckusic obp->b_flags |= B_INVAL; 1424463Smckusic brelse(obp); 1435212Smckusic fre(dev, bprev, (off_t)osize); 1444463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1454463Smckusic return(bp); 1464463Smckusic } 1474792Smckusic nospace: 1484463Smckusic /* 1494463Smckusic * no space available 1504463Smckusic */ 1514426Smckusic fserr(fs, "file system full"); 1524426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1534426Smckusic u.u_error = ENOSPC; 1544426Smckusic return (NULL); 1554426Smckusic } 1564426Smckusic 1575375Smckusic /* 1585375Smckusic * Allocate an inode in the file system. 1595375Smckusic * 1605375Smckusic * A preference may be optionally specified. If a preference is given 1615375Smckusic * the following hierarchy is used to allocate an inode: 1625375Smckusic * 1) allocate the requested inode. 1635375Smckusic * 2) allocate an inode in the same cylinder group. 1645375Smckusic * 3) quadradically rehash into other cylinder groups, until an 1655375Smckusic * available inode is located. 1665375Smckusic * If no inode preference is given the following heirarchy is used 1675375Smckusic * to allocate an inode: 1685375Smckusic * 1) allocate an inode in cylinder group 0. 1695375Smckusic * 2) quadradically rehash into other cylinder groups, until an 1705375Smckusic * available inode is located. 1715375Smckusic */ 1724359Smckusick struct inode * 1734359Smckusick ialloc(dev, ipref, mode) 1744359Smckusick dev_t dev; 1754359Smckusick ino_t ipref; 1764359Smckusick int mode; 1774359Smckusick { 1785212Smckusic ino_t ino; 1794359Smckusick register struct fs *fs; 1804359Smckusick register struct inode *ip; 1814359Smckusick int cg; 1824359Smckusick 1834359Smckusick fs = getfs(dev); 1844792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1854359Smckusick goto noinodes; 1864948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 1874948Smckusic ipref = 0; 188*5377Smckusic cg = itog(fs, ipref); 1895212Smckusic ino = (ino_t)hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 1904359Smckusick if (ino == 0) 1914359Smckusick goto noinodes; 1924359Smckusick ip = iget(dev, ino); 1934359Smckusick if (ip == NULL) { 1945212Smckusic ifree(dev, ino, 0); 1954359Smckusick return (NULL); 1964359Smckusick } 1974359Smckusick if (ip->i_mode) 1984359Smckusick panic("ialloc: dup alloc"); 1994359Smckusick return (ip); 2004359Smckusick noinodes: 2014359Smckusick fserr(fs, "out of inodes"); 2024359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 2034359Smckusick u.u_error = ENOSPC; 2044359Smckusick return (NULL); 2054359Smckusick } 2064359Smckusick 2074651Smckusic /* 2085375Smckusic * Find a cylinder to place a directory. 2095375Smckusic * 2105375Smckusic * The policy implemented by this algorithm is to select from 2115375Smckusic * among those cylinder groups with above the average number of 2125375Smckusic * free inodes, the one with the smallest number of directories. 2134651Smckusic */ 2144651Smckusic dirpref(dev) 2154359Smckusick dev_t dev; 2164359Smckusick { 2174359Smckusick register struct fs *fs; 2184651Smckusic int cg, minndir, mincg, avgifree; 2194359Smckusick 2204359Smckusick fs = getfs(dev); 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 2424651Smckusic blkpref(dev) 2434651Smckusic dev_t dev; 2444651Smckusic { 2454651Smckusic register struct fs *fs; 2464651Smckusic int cg, avgbfree; 2474651Smckusic 2484651Smckusic fs = getfs(dev); 2494792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 2504651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 2515322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2524651Smckusic fs->fs_cgrotor = cg; 2535322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2544651Smckusic } 2554651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 2565322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2574651Smckusic fs->fs_cgrotor = cg; 2585322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2594651Smckusic } 2604651Smckusic return (0); 2614651Smckusic } 2624651Smckusic 2635375Smckusic /* 2645375Smckusic * Implement the cylinder overflow algorithm. 2655375Smckusic * 2665375Smckusic * The policy implemented by this algorithm is: 2675375Smckusic * 1) allocate the block in its requested cylinder group. 2685375Smckusic * 2) quadradically rehash on the cylinder group number. 2695375Smckusic * 3) brute force search for a free block. 2705375Smckusic */ 2715212Smckusic /*VARARGS5*/ 2725212Smckusic u_long 2734359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 2744359Smckusick dev_t dev; 2754359Smckusick register struct fs *fs; 2764359Smckusick int cg; 2774359Smckusick long pref; 2784359Smckusick int size; /* size for data blocks, mode for inodes */ 2795212Smckusic u_long (*allocator)(); 2804359Smckusick { 2814359Smckusick long result; 2824359Smckusick int i, icg = cg; 2834359Smckusick 2844359Smckusick /* 2854359Smckusick * 1: preferred cylinder group 2864359Smckusick */ 2874359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 2884359Smckusick if (result) 2894359Smckusick return (result); 2904359Smckusick /* 2914359Smckusick * 2: quadratic rehash 2924359Smckusick */ 2934359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2944359Smckusick cg += i; 2954359Smckusick if (cg >= fs->fs_ncg) 2964359Smckusick cg -= fs->fs_ncg; 2974359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2984359Smckusick if (result) 2994359Smckusick return (result); 3004359Smckusick } 3014359Smckusick /* 3024359Smckusick * 3: brute force search 3034359Smckusick */ 3044359Smckusick cg = icg; 3054359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 3064359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 3074359Smckusick if (result) 3084359Smckusick return (result); 3094359Smckusick cg++; 3104359Smckusick if (cg == fs->fs_ncg) 3114359Smckusick cg = 0; 3124359Smckusick } 3134359Smckusick return (0); 3144359Smckusick } 3154359Smckusick 3165375Smckusic /* 3175375Smckusic * Determine whether a fragment can be extended. 3185375Smckusic * 3195375Smckusic * Check to see if the necessary fragments are available, and 3205375Smckusic * if they are, allocate them. 3215375Smckusic */ 3224359Smckusick daddr_t 3234463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize) 3244426Smckusic dev_t dev; 3254426Smckusic register struct fs *fs; 3264426Smckusic int cg; 3274463Smckusic long bprev; 3284426Smckusic int osize, nsize; 3294426Smckusic { 3304463Smckusic register struct buf *bp; 3314463Smckusic register struct cg *cgp; 3324463Smckusic long bno; 3334463Smckusic int frags, bbase; 3344426Smckusic int i; 3354426Smckusic 3365322Smckusic frags = nsize / fs->fs_fsize; 3375322Smckusic bbase = bprev % fs->fs_frag; 3385322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 3394463Smckusic /* cannot extend across a block boundry */ 3404463Smckusic return (0); 3414463Smckusic } 342*5377Smckusic bp = bread(dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 3434426Smckusic if (bp->b_flags & B_ERROR) 3444426Smckusic return (0); 3454426Smckusic cgp = bp->b_un.b_cg; 346*5377Smckusic bno = dtogd(fs, bprev); 3475361Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) 3485361Smckusic if (isclr(cgp->cg_free, bno + i)) { 3495361Smckusic brelse(bp); 3505361Smckusic return (0); 3515361Smckusic } 3525361Smckusic /* 3535361Smckusic * the current fragment can be extended 3545361Smckusic * deduct the count on fragment being extended into 3555361Smckusic * increase the count on the remaining fragment (if any) 3565361Smckusic * allocate the extended piece 3575361Smckusic */ 3585361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 3594463Smckusic if (isclr(cgp->cg_free, bno + i)) 3604463Smckusic break; 3615361Smckusic cgp->cg_frsum[i - osize / fs->fs_fsize]--; 3625361Smckusic if (i != frags) 3635361Smckusic cgp->cg_frsum[i - frags]++; 3645361Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) { 3655361Smckusic clrbit(cgp->cg_free, bno + i); 3665361Smckusic cgp->cg_cs.cs_nffree--; 3675361Smckusic fs->fs_cstotal.cs_nffree--; 3685361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3694463Smckusic } 3705361Smckusic fs->fs_fmod++; 3715361Smckusic bdwrite(bp); 3725361Smckusic return (bprev); 3734426Smckusic } 3744426Smckusic 3755375Smckusic /* 3765375Smckusic * Determine whether a block can be allocated. 3775375Smckusic * 3785375Smckusic * Check to see if a block of the apprpriate size is available, 3795375Smckusic * and if it is, allocate it. 3805375Smckusic */ 3814426Smckusic daddr_t 3824359Smckusick alloccg(dev, fs, cg, bpref, size) 3834359Smckusick dev_t dev; 3844463Smckusic register struct fs *fs; 3854359Smckusick int cg; 3864359Smckusick daddr_t bpref; 3874359Smckusick int size; 3884359Smckusick { 3894463Smckusic register struct buf *bp; 3904463Smckusic register struct cg *cgp; 3914463Smckusic int bno, frags; 3924463Smckusic int allocsiz; 3934463Smckusic register int i; 3944359Smckusick 3955322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 3964792Smckusic return (0); 397*5377Smckusic bp = bread(dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 3984359Smckusick if (bp->b_flags & B_ERROR) 3994359Smckusick return (0); 4004359Smckusick cgp = bp->b_un.b_cg; 4015322Smckusic if (size == fs->fs_bsize) { 4025212Smckusic bno = alloccgblk(fs, cgp, bpref); 4034463Smckusic bdwrite(bp); 4044463Smckusic return (bno); 4054463Smckusic } 4064463Smckusic /* 4074463Smckusic * check to see if any fragments are already available 4084463Smckusic * allocsiz is the size which will be allocated, hacking 4094463Smckusic * it down to a smaller size if necessary 4104463Smckusic */ 4115322Smckusic frags = size / fs->fs_fsize; 4125322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 4134463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 4144463Smckusic break; 4155322Smckusic if (allocsiz == fs->fs_frag) { 4164463Smckusic /* 4174463Smckusic * no fragments were available, so a block will be 4184463Smckusic * allocated, and hacked up 4194463Smckusic */ 4204792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 4214463Smckusic brelse(bp); 4224463Smckusic return (0); 4234463Smckusic } 4245212Smckusic bno = alloccgblk(fs, cgp, bpref); 425*5377Smckusic bpref = dtogd(fs, bno); 4265322Smckusic for (i = frags; i < fs->fs_frag; i++) 4274463Smckusic setbit(cgp->cg_free, bpref + i); 4285322Smckusic i = fs->fs_frag - frags; 4294792Smckusic cgp->cg_cs.cs_nffree += i; 4304792Smckusic fs->fs_cstotal.cs_nffree += i; 4315322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 4324463Smckusic cgp->cg_frsum[i]++; 4334463Smckusic bdwrite(bp); 4344463Smckusic return (bno); 4354463Smckusic } 4364651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 4374651Smckusic if (bno == 0) 4384651Smckusic return (0); 4394463Smckusic for (i = 0; i < frags; i++) 4404463Smckusic clrbit(cgp->cg_free, bno + i); 4414792Smckusic cgp->cg_cs.cs_nffree -= frags; 4424792Smckusic fs->fs_cstotal.cs_nffree -= frags; 4435322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 4444463Smckusic cgp->cg_frsum[allocsiz]--; 4454463Smckusic if (frags != allocsiz) 4464463Smckusic cgp->cg_frsum[allocsiz - frags]++; 4474463Smckusic bdwrite(bp); 4484463Smckusic return (cg * fs->fs_fpg + bno); 4494463Smckusic } 4504463Smckusic 4515375Smckusic /* 4525375Smckusic * Allocate a block in a cylinder group. 4535375Smckusic * 4545375Smckusic * This algorithm implements the following policy: 4555375Smckusic * 1) allocate the requested block. 4565375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 4575375Smckusic * 3) allocate the next available block on the block rotor for the 4585375Smckusic * specified cylinder group. 4595375Smckusic * Note that this routine only allocates fs_bsize blocks; these 4605375Smckusic * blocks may be fragmented by the routine that allocates them. 4615375Smckusic */ 4624463Smckusic daddr_t 4635212Smckusic alloccgblk(fs, cgp, bpref) 4644463Smckusic struct fs *fs; 4654463Smckusic register struct cg *cgp; 4664463Smckusic daddr_t bpref; 4674463Smckusic { 4684651Smckusic daddr_t bno; 4694651Smckusic int cylno, pos; 4704651Smckusic short *cylbp; 4715361Smckusic register int i; 4724463Smckusic 4734651Smckusic if (bpref == 0) { 4744651Smckusic bpref = cgp->cg_rotor; 4755361Smckusic goto norot; 4765361Smckusic } 4775361Smckusic bpref &= ~(fs->fs_frag - 1); 478*5377Smckusic bpref = dtogd(fs, bpref); 4795361Smckusic /* 4805361Smckusic * if the requested block is available, use it 4815361Smckusic */ 4825361Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 4835361Smckusic bno = bpref; 4845361Smckusic goto gotit; 4855361Smckusic } 4865361Smckusic /* 4875361Smckusic * check for a block available on the same cylinder 4885361Smckusic */ 4895361Smckusic cylno = cbtocylno(fs, bpref); 4905375Smckusic if (cgp->cg_btot[cylno] == 0) 4915375Smckusic goto norot; 4925375Smckusic if (fs->fs_cpc == 0) { 4935375Smckusic /* 4945375Smckusic * block layout info is not available, so just have 4955375Smckusic * to take any block in this cylinder. 4965375Smckusic */ 4975375Smckusic bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); 4985375Smckusic goto norot; 4995375Smckusic } 5005375Smckusic /* 5015375Smckusic * find a block that is rotationally optimal 5025375Smckusic */ 5035361Smckusic cylbp = cgp->cg_b[cylno]; 5045361Smckusic if (fs->fs_rotdelay == 0) { 5055361Smckusic pos = cbtorpos(fs, bpref); 5064651Smckusic } else { 5074651Smckusic /* 5085361Smckusic * here we convert ms of delay to frags as: 5095361Smckusic * (frags) = (ms) * (rev/sec) * (sect/rev) / 5105361Smckusic * ((sect/frag) * (ms/sec)) 5115361Smckusic * then round up to the next rotational position 5124651Smckusic */ 5135361Smckusic bpref += fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 5145361Smckusic (NSPF(fs) * 1000); 5155361Smckusic pos = cbtorpos(fs, bpref); 5165361Smckusic pos = (pos + 1) % NRPOS; 5175361Smckusic } 5185361Smckusic /* 5195361Smckusic * check the summary information to see if a block is 5205361Smckusic * available in the requested cylinder starting at the 5215361Smckusic * optimal rotational position and proceeding around. 5225361Smckusic */ 5235361Smckusic for (i = pos; i < NRPOS; i++) 5245361Smckusic if (cylbp[i] > 0) 5255361Smckusic break; 5265361Smckusic if (i == NRPOS) 5275361Smckusic for (i = 0; i < pos; i++) 5285361Smckusic if (cylbp[i] > 0) 5295361Smckusic break; 5305361Smckusic if (cylbp[i] > 0) { 5314651Smckusic /* 5325361Smckusic * found a rotational position, now find the actual 5335361Smckusic * block. A panic if none is actually there. 5344651Smckusic */ 5355361Smckusic pos = cylno % fs->fs_cpc; 5365361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 5375361Smckusic if (fs->fs_postbl[pos][i] == -1) 5385361Smckusic panic("alloccgblk: cyl groups corrupted"); 5395361Smckusic for (i = fs->fs_postbl[pos][i]; ; i += fs->fs_rotbl[i]) { 5405361Smckusic if (isblock(fs, cgp->cg_free, bno + i)) { 5415361Smckusic bno = (bno + i) * fs->fs_frag; 5425361Smckusic goto gotit; 5435361Smckusic } 5445361Smckusic if (fs->fs_rotbl[i] == 0) 5454651Smckusic break; 5464651Smckusic } 5475361Smckusic panic("alloccgblk: can't find blk in cyl"); 5484359Smckusick } 5495361Smckusic norot: 5505361Smckusic /* 5515361Smckusic * no blocks in the requested cylinder, so take next 5525361Smckusic * available one in this cylinder group. 5535361Smckusic */ 5545322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 5554651Smckusic if (bno == 0) 5564651Smckusic return (0); 5574651Smckusic cgp->cg_rotor = bno; 5584359Smckusick gotit: 5595322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 5604792Smckusic cgp->cg_cs.cs_nbfree--; 5614792Smckusic fs->fs_cstotal.cs_nbfree--; 5625322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 5635375Smckusic cylno = cbtocylno(fs, bno); 5645375Smckusic cgp->cg_b[cylno][cbtorpos(fs, bno)]--; 5655375Smckusic cgp->cg_btot[cylno]--; 5664359Smckusick fs->fs_fmod++; 5674651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 5684359Smckusick } 5694359Smckusick 5705375Smckusic /* 5715375Smckusic * Determine whether an inode can be allocated. 5725375Smckusic * 5735375Smckusic * Check to see if an inode is available, and if it is, 5745375Smckusic * allocate it using the following policy: 5755375Smckusic * 1) allocate the requested inode. 5765375Smckusic * 2) allocate the next available inode after the requested 5775375Smckusic * inode in the specified cylinder group. 5785375Smckusic */ 5795212Smckusic ino_t 5804359Smckusick ialloccg(dev, fs, cg, ipref, mode) 5814359Smckusick dev_t dev; 5824463Smckusic register struct fs *fs; 5834359Smckusick int cg; 5844359Smckusick daddr_t ipref; 5854359Smckusick int mode; 5864359Smckusick { 5874463Smckusic register struct buf *bp; 5884463Smckusic register struct cg *cgp; 5894359Smckusick int i; 5904359Smckusick 5915322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 5924792Smckusic return (0); 593*5377Smckusic bp = bread(dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 5944359Smckusick if (bp->b_flags & B_ERROR) 5954359Smckusick return (0); 5964359Smckusick cgp = bp->b_un.b_cg; 5974359Smckusick if (ipref) { 5984359Smckusick ipref %= fs->fs_ipg; 5994359Smckusick if (isclr(cgp->cg_iused, ipref)) 6004359Smckusick goto gotit; 6014359Smckusick } else 6024359Smckusick ipref = cgp->cg_irotor; 6034359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 6044359Smckusick ipref++; 6054359Smckusick if (ipref >= fs->fs_ipg) 6064359Smckusick ipref = 0; 6074359Smckusick if (isclr(cgp->cg_iused, ipref)) { 6084359Smckusick cgp->cg_irotor = ipref; 6094359Smckusick goto gotit; 6104359Smckusick } 6114359Smckusick } 6124359Smckusick brelse(bp); 6134359Smckusick return (0); 6144359Smckusick gotit: 6154359Smckusick setbit(cgp->cg_iused, ipref); 6164792Smckusic cgp->cg_cs.cs_nifree--; 6174792Smckusic fs->fs_cstotal.cs_nifree--; 6185322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 6194359Smckusick fs->fs_fmod++; 6204359Smckusick if ((mode & IFMT) == IFDIR) { 6214792Smckusic cgp->cg_cs.cs_ndir++; 6224792Smckusic fs->fs_cstotal.cs_ndir++; 6235322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 6244359Smckusick } 6254359Smckusick bdwrite(bp); 6264359Smckusick return (cg * fs->fs_ipg + ipref); 6274359Smckusick } 6284359Smckusick 6295375Smckusic /* 6305375Smckusic * Free a block or fragment. 6315375Smckusic * 6325375Smckusic * The specified block or fragment is placed back in the 6335375Smckusic * free map. If a fragment is deallocated, a possible 6345375Smckusic * block reassembly is checked. 6355375Smckusic */ 6364359Smckusick fre(dev, bno, size) 6374359Smckusick dev_t dev; 6384359Smckusick daddr_t bno; 6395212Smckusic off_t size; 6404359Smckusick { 6414359Smckusick register struct fs *fs; 6424359Smckusick register struct cg *cgp; 6434359Smckusick register struct buf *bp; 6444463Smckusic int cg, blk, frags, bbase; 6454463Smckusic register int i; 6464359Smckusick 6475322Smckusic fs = getfs(dev); 6485322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 6494426Smckusic panic("free: bad size"); 650*5377Smckusic cg = dtog(fs, bno); 6514359Smckusick if (badblock(fs, bno)) 6524359Smckusick return; 653*5377Smckusic bp = bread(dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 6544359Smckusick if (bp->b_flags & B_ERROR) 6554359Smckusick return; 6564359Smckusick cgp = bp->b_un.b_cg; 657*5377Smckusic bno = dtogd(fs, bno); 6585322Smckusic if (size == fs->fs_bsize) { 6595322Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) 6604426Smckusic panic("free: freeing free block"); 6615322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 6624792Smckusic cgp->cg_cs.cs_nbfree++; 6634792Smckusic fs->fs_cstotal.cs_nbfree++; 6645322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 6655375Smckusic i = cbtocylno(fs, bno); 6665375Smckusic cgp->cg_b[i][cbtorpos(fs, bno)]++; 6675375Smckusic cgp->cg_btot[i]++; 6684426Smckusic } else { 6695322Smckusic bbase = bno - (bno % fs->fs_frag); 6704463Smckusic /* 6714463Smckusic * decrement the counts associated with the old frags 6724463Smckusic */ 6734463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 6745322Smckusic (0xff >> (NBBY - fs->fs_frag))); 6755322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 6764463Smckusic /* 6774463Smckusic * deallocate the fragment 6784463Smckusic */ 6795322Smckusic frags = size / fs->fs_fsize; 6804463Smckusic for (i = 0; i < frags; i++) { 6814426Smckusic if (isset(cgp->cg_free, bno + i)) 6824426Smckusic panic("free: freeing free frag"); 6834426Smckusic setbit(cgp->cg_free, bno + i); 6844792Smckusic cgp->cg_cs.cs_nffree++; 6854792Smckusic fs->fs_cstotal.cs_nffree++; 6865322Smckusic fs->fs_cs(fs, cg).cs_nffree++; 6874426Smckusic } 6884463Smckusic /* 6894463Smckusic * add back in counts associated with the new frags 6904463Smckusic */ 6914463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 6925322Smckusic (0xff >> (NBBY - fs->fs_frag))); 6935322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 6944463Smckusic /* 6954463Smckusic * if a complete block has been reassembled, account for it 6964463Smckusic */ 6975322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 6985322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 6995322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 7005322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 7014792Smckusic cgp->cg_cs.cs_nbfree++; 7024792Smckusic fs->fs_cstotal.cs_nbfree++; 7035322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 7045375Smckusic i = cbtocylno(fs, bbase); 7055375Smckusic cgp->cg_b[i][cbtorpos(fs, bbase)]++; 7065375Smckusic cgp->cg_btot[i]++; 7074426Smckusic } 7084426Smckusic } 7094359Smckusick fs->fs_fmod++; 7104359Smckusick bdwrite(bp); 7114359Smckusick } 7124359Smckusick 7135375Smckusic /* 7145375Smckusic * Free an inode. 7155375Smckusic * 7165375Smckusic * The specified inode is placed back in the free map. 7175375Smckusic */ 7184359Smckusick ifree(dev, ino, mode) 7194359Smckusick dev_t dev; 7204359Smckusick ino_t ino; 7214359Smckusick int mode; 7224359Smckusick { 7234359Smckusick register struct fs *fs; 7244359Smckusick register struct cg *cgp; 7254359Smckusick register struct buf *bp; 7264359Smckusick int cg; 7274359Smckusick 7284359Smckusick fs = getfs(dev); 7294359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 7304359Smckusick panic("ifree: range"); 731*5377Smckusic cg = itog(fs, ino); 732*5377Smckusic bp = bread(dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 7334359Smckusick if (bp->b_flags & B_ERROR) 7344359Smckusick return; 7354359Smckusick cgp = bp->b_un.b_cg; 7364359Smckusick ino %= fs->fs_ipg; 7374359Smckusick if (isclr(cgp->cg_iused, ino)) 7384359Smckusick panic("ifree: freeing free inode"); 7394359Smckusick clrbit(cgp->cg_iused, ino); 7404792Smckusic cgp->cg_cs.cs_nifree++; 7414792Smckusic fs->fs_cstotal.cs_nifree++; 7425322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 7434359Smckusick if ((mode & IFMT) == IFDIR) { 7444792Smckusic cgp->cg_cs.cs_ndir--; 7454792Smckusic fs->fs_cstotal.cs_ndir--; 7465322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 7474359Smckusick } 7484359Smckusick fs->fs_fmod++; 7494359Smckusick bdwrite(bp); 7504359Smckusick } 7514359Smckusick 7524463Smckusic /* 7535375Smckusic * Find a block of the specified size in the specified cylinder group. 7545375Smckusic * 7554651Smckusic * It is a panic if a request is made to find a block if none are 7564651Smckusic * available. 7574651Smckusic */ 7584651Smckusic daddr_t 7594651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 7604651Smckusic register struct fs *fs; 7614651Smckusic register struct cg *cgp; 7624651Smckusic daddr_t bpref; 7634651Smckusic int allocsiz; 7644651Smckusic { 7654651Smckusic daddr_t bno; 7664651Smckusic int start, len, loc, i; 7674651Smckusic int blk, field, subfield, pos; 7684651Smckusic 7694651Smckusic /* 7704651Smckusic * find the fragment by searching through the free block 7714651Smckusic * map for an appropriate bit pattern 7724651Smckusic */ 7734651Smckusic if (bpref) 774*5377Smckusic start = dtogd(fs, bpref) / NBBY; 7754651Smckusic else 7764651Smckusic start = cgp->cg_frotor / NBBY; 7774651Smckusic len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start; 7785322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7795322Smckusic 1 << (allocsiz - 1)); 7804651Smckusic if (loc == 0) { 7814651Smckusic len = start - 1; 7825375Smckusic start = fs->fs_dblkno / NBBY; 7835322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7844651Smckusic 1 << (allocsiz - 1)); 7854651Smckusic if (loc == 0) { 7864651Smckusic panic("alloccg: map corrupted"); 7874651Smckusic return (0); 7884651Smckusic } 7894651Smckusic } 7904651Smckusic bno = (start + len - loc) * NBBY; 7914651Smckusic cgp->cg_frotor = bno; 7924651Smckusic /* 7934651Smckusic * found the byte in the map 7944651Smckusic * sift through the bits to find the selected frag 7954651Smckusic */ 7965322Smckusic for (i = 0; i < NBBY; i += fs->fs_frag) { 7975322Smckusic blk = (cgp->cg_free[bno / NBBY] >> i) & 7985322Smckusic (0xff >> NBBY - fs->fs_frag); 7994651Smckusic blk <<= 1; 8004651Smckusic field = around[allocsiz]; 8014651Smckusic subfield = inside[allocsiz]; 8025322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 8034651Smckusic if ((blk & field) == subfield) { 8044651Smckusic return (bno + i + pos); 8054651Smckusic } 8064651Smckusic field <<= 1; 8074651Smckusic subfield <<= 1; 8084651Smckusic } 8094651Smckusic } 8104651Smckusic panic("alloccg: block not in map"); 8114651Smckusic return (0); 8124651Smckusic } 8134651Smckusic 8144651Smckusic /* 8155375Smckusic * Update the frsum fields to reflect addition or deletion 8165375Smckusic * of some frags. 8174463Smckusic */ 8185322Smckusic fragacct(fs, fragmap, fraglist, cnt) 8195322Smckusic struct fs *fs; 8204472Smckusic int fragmap; 8214792Smckusic long fraglist[]; 8224463Smckusic int cnt; 8234463Smckusic { 8244463Smckusic int inblk; 8254463Smckusic register int field, subfield; 8264463Smckusic register int siz, pos; 8274463Smckusic 8285322Smckusic inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 8294463Smckusic fragmap <<= 1; 8305322Smckusic for (siz = 1; siz < fs->fs_frag; siz++) { 8314463Smckusic if (((1 << siz) & inblk) == 0) 8324463Smckusic continue; 8334463Smckusic field = around[siz]; 8344463Smckusic subfield = inside[siz]; 8355322Smckusic for (pos = siz; pos <= fs->fs_frag; pos++) { 8364463Smckusic if ((fragmap & field) == subfield) { 8374463Smckusic fraglist[siz] += cnt; 8384463Smckusic pos += siz; 8394463Smckusic field <<= siz; 8404463Smckusic subfield <<= siz; 8414463Smckusic } 8424463Smckusic field <<= 1; 8434463Smckusic subfield <<= 1; 8444463Smckusic } 8454463Smckusic } 8464463Smckusic } 8474463Smckusic 8485375Smckusic /* 8495375Smckusic * Check that a specified block number is in range. 8505375Smckusic */ 8514359Smckusick badblock(fs, bn) 8524359Smckusick register struct fs *fs; 8534359Smckusick daddr_t bn; 8544359Smckusick { 8554359Smckusick 856*5377Smckusic if ((unsigned)bn >= fs->fs_size || bn < cgdmin(fs, dtog(fs, bn))) { 8574359Smckusick fserr(fs, "bad block"); 8584359Smckusick return (1); 8594359Smckusick } 8604359Smckusick return (0); 8614359Smckusick } 8624359Smckusick 8634359Smckusick /* 8645375Smckusic * Getfs maps a device number into a pointer to the incore super block. 8654359Smckusick * 8665375Smckusic * The algorithm is a linear search through the mount table. A 8675375Smckusic * consistency check of the super block magic number is performed. 8685375Smckusic * 8694359Smckusick * panic: no fs -- the device is not mounted. 8704359Smckusick * this "cannot happen" 8714359Smckusick */ 8724359Smckusick struct fs * 8734359Smckusick getfs(dev) 8744359Smckusick dev_t dev; 8754359Smckusick { 8764359Smckusick register struct mount *mp; 8774359Smckusick register struct fs *fs; 8784359Smckusick 8794359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8804359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 8814359Smckusick fs = mp->m_bufp->b_un.b_fs; 8824359Smckusick if (fs->fs_magic != FS_MAGIC) 8834359Smckusick panic("getfs: bad magic"); 8844359Smckusick return (fs); 8854359Smckusick } 8864359Smckusick panic("getfs: no fs"); 8874359Smckusick return (NULL); 8884359Smckusick } 8894359Smckusick 8904359Smckusick /* 8915375Smckusic * Fserr prints the name of a file system with an error diagnostic. 8925375Smckusic * 8935375Smckusic * The form of the error message is: 8944359Smckusick * fs: error message 8954359Smckusick */ 8964359Smckusick fserr(fs, cp) 8974359Smckusick struct fs *fs; 8984359Smckusick char *cp; 8994359Smckusick { 9004359Smckusick 9014359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 9024359Smckusick } 9034359Smckusick 9044359Smckusick /* 9054359Smckusick * Getfsx returns the index in the file system 9064359Smckusick * table of the specified device. The swap device 9074359Smckusick * is also assigned a pseudo-index. The index may 9084359Smckusick * be used as a compressed indication of the location 9094359Smckusick * of a block, recording 9104359Smckusick * <getfsx(dev),blkno> 9114359Smckusick * rather than 9124359Smckusick * <dev, blkno> 9134359Smckusick * provided the information need remain valid only 9144359Smckusick * as long as the file system is mounted. 9154359Smckusick */ 9164359Smckusick getfsx(dev) 9174359Smckusick dev_t dev; 9184359Smckusick { 9194359Smckusick register struct mount *mp; 9204359Smckusick 9214359Smckusick if (dev == swapdev) 9224359Smckusick return (MSWAPX); 9234359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9244359Smckusick if (mp->m_dev == dev) 9254359Smckusick return (mp - &mount[0]); 9264359Smckusick return (-1); 9274359Smckusick } 9284359Smckusick 9294359Smckusick /* 9304359Smckusick * Update is the internal name of 'sync'. It goes through the disk 9314359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 9325375Smckusic * modified nodes; and it goes through the mount table to initiate 9335375Smckusic * the writing of the modified super blocks. 9344359Smckusick */ 9354359Smckusick update() 9364359Smckusick { 9374359Smckusick register struct inode *ip; 9384359Smckusick register struct mount *mp; 9394359Smckusick register struct buf *bp; 9404359Smckusick struct fs *fs; 9414359Smckusick time_t tim; 9424651Smckusic int i, blks; 9434359Smckusick 9444359Smckusick if (updlock) 9454359Smckusick return; 9464359Smckusick updlock++; 9474359Smckusick /* 9484359Smckusick * Write back modified superblocks. 9494359Smckusick * Consistency check that the superblock 9504359Smckusick * of each file system is still in the buffer cache. 9514359Smckusick */ 9524359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9534359Smckusick if (mp->m_bufp != NULL) { 9544359Smckusick fs = mp->m_bufp->b_un.b_fs; 9554359Smckusick if (fs->fs_fmod == 0) 9564359Smckusick continue; 9574359Smckusick if (fs->fs_ronly != 0) 9584359Smckusick panic("update: rofs mod"); 9595344Smckusic bp = getblk(mp->m_dev, SBLOCK, SBSIZE); 9604359Smckusick fs->fs_fmod = 0; 9614359Smckusick fs->fs_time = TIME; 9624359Smckusick if (bp->b_un.b_fs != fs) 9634359Smckusick panic("update: bad b_fs"); 9644359Smckusick bwrite(bp); 9655322Smckusic blks = howmany(fs->fs_cssize, fs->fs_bsize); 9664651Smckusic for (i = 0; i < blks; i++) { 9675322Smckusic bp = getblk(mp->m_dev, 9685322Smckusic fsbtodb(fs, fs->fs_csaddr + (i * fs->fs_frag)), 9695322Smckusic fs->fs_bsize); 9704359Smckusick bwrite(bp); 9714359Smckusick } 9724359Smckusick } 9734359Smckusick /* 9744359Smckusick * Write back each (modified) inode. 9754359Smckusick */ 9764359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 9774359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 9784359Smckusick ip->i_flag |= ILOCK; 9794359Smckusick ip->i_count++; 9804359Smckusick tim = TIME; 9814359Smckusick iupdat(ip, &tim, &tim, 0); 9824359Smckusick iput(ip); 9834359Smckusick } 9844359Smckusick updlock = 0; 9854359Smckusick /* 9864359Smckusick * Force stale buffer cache information to be flushed, 9874359Smckusick * for all devices. 9884359Smckusick */ 9894359Smckusick bflush(NODEV); 9904359Smckusick } 9915322Smckusic 9925322Smckusic /* 9935375Smckusic * block operations 9945375Smckusic * 9955375Smckusic * check if a block is available 9965322Smckusic */ 9975322Smckusic isblock(fs, cp, h) 9985322Smckusic struct fs *fs; 9995322Smckusic unsigned char *cp; 10005322Smckusic int h; 10015322Smckusic { 10025322Smckusic unsigned char mask; 10035322Smckusic 10045322Smckusic switch (fs->fs_frag) { 10055322Smckusic case 8: 10065322Smckusic return (cp[h] == 0xff); 10075322Smckusic case 4: 10085322Smckusic mask = 0x0f << ((h & 0x1) << 2); 10095322Smckusic return ((cp[h >> 1] & mask) == mask); 10105322Smckusic case 2: 10115322Smckusic mask = 0x03 << ((h & 0x3) << 1); 10125322Smckusic return ((cp[h >> 2] & mask) == mask); 10135322Smckusic case 1: 10145322Smckusic mask = 0x01 << (h & 0x7); 10155322Smckusic return ((cp[h >> 3] & mask) == mask); 10165322Smckusic default: 10175322Smckusic panic("isblock bad fs_frag"); 10185322Smckusic return; 10195322Smckusic } 10205322Smckusic } 10215375Smckusic 10225375Smckusic /* 10235375Smckusic * take a block out of the map 10245375Smckusic */ 10255322Smckusic clrblock(fs, cp, h) 10265322Smckusic struct fs *fs; 10275322Smckusic unsigned char *cp; 10285322Smckusic int h; 10295322Smckusic { 10305322Smckusic switch ((fs)->fs_frag) { 10315322Smckusic case 8: 10325322Smckusic cp[h] = 0; 10335322Smckusic return; 10345322Smckusic case 4: 10355322Smckusic cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 10365322Smckusic return; 10375322Smckusic case 2: 10385322Smckusic cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 10395322Smckusic return; 10405322Smckusic case 1: 10415322Smckusic cp[h >> 3] &= ~(0x01 << (h & 0x7)); 10425322Smckusic return; 10435322Smckusic default: 10445322Smckusic panic("clrblock bad fs_frag"); 10455322Smckusic return; 10465322Smckusic } 10475322Smckusic } 10485375Smckusic 10495375Smckusic /* 10505375Smckusic * put a block into the map 10515375Smckusic */ 10525322Smckusic setblock(fs, cp, h) 10535322Smckusic struct fs *fs; 10545322Smckusic unsigned char *cp; 10555322Smckusic int h; 10565322Smckusic { 10575322Smckusic switch (fs->fs_frag) { 10585322Smckusic case 8: 10595322Smckusic cp[h] = 0xff; 10605322Smckusic return; 10615322Smckusic case 4: 10625322Smckusic cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 10635322Smckusic return; 10645322Smckusic case 2: 10655322Smckusic cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 10665322Smckusic return; 10675322Smckusic case 1: 10685322Smckusic cp[h >> 3] |= (0x01 << (h & 0x7)); 10695322Smckusic return; 10705322Smckusic default: 10715322Smckusic panic("setblock bad fs_frag"); 10725322Smckusic return; 10735322Smckusic } 10745322Smckusic } 1075