14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*6294Smckusick static char vers[] = "@(#)lfs_alloc.c 1.21 03/23/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/user.h" 154359Smckusick 165212Smckusic extern u_long hashalloc(); 175212Smckusic extern ino_t ialloccg(); 184651Smckusic extern daddr_t alloccg(); 194651Smckusic extern daddr_t alloccgblk(); 204651Smckusic extern daddr_t fragextend(); 214651Smckusic extern daddr_t blkpref(); 224651Smckusic extern daddr_t mapsearch(); 234607Smckusic extern int inside[], around[]; 245322Smckusic extern unsigned char *fragtbl[]; 254359Smckusick 265375Smckusic /* 275375Smckusic * Allocate a block in the file system. 285375Smckusic * 295375Smckusic * The size of the requested block is given, which must be some 305375Smckusic * multiple of fs_fsize and <= fs_bsize. 315375Smckusic * A preference may be optionally specified. If a preference is given 325375Smckusic * the following hierarchy is used to allocate a block: 335375Smckusic * 1) allocate the requested block. 345375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 355375Smckusic * 3) allocate a block in the same cylinder group. 365375Smckusic * 4) quadradically rehash into other cylinder groups, until an 375375Smckusic * available block is located. 385375Smckusic * If no block preference is given the following heirarchy is used 395375Smckusic * to allocate a block: 405375Smckusic * 1) allocate a block in the cylinder group that contains the 415375Smckusic * inode for the file. 425375Smckusic * 2) quadradically rehash into other cylinder groups, until an 435375Smckusic * available block is located. 445375Smckusic */ 454359Smckusick struct buf * 465965Smckusic alloc(ip, bpref, size) 474463Smckusic register struct inode *ip; 484359Smckusick daddr_t bpref; 494359Smckusick int size; 504359Smckusick { 514359Smckusick daddr_t bno; 524359Smckusick register struct fs *fs; 534463Smckusic register struct buf *bp; 544359Smckusick int cg; 554359Smckusick 565965Smckusic fs = ip->i_fs; 575960Smckusic if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) 584463Smckusic panic("alloc: bad size"); 595322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 604359Smckusick goto nospace; 614792Smckusic if (u.u_uid != 0 && 625322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 635322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 644792Smckusic goto nospace; 654948Smckusic if (bpref >= fs->fs_size) 664948Smckusic bpref = 0; 674359Smckusick if (bpref == 0) 685377Smckusic cg = itog(fs, ip->i_number); 694359Smckusick else 705377Smckusic cg = dtog(fs, bpref); 715965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, alloccg); 724359Smckusick if (bno == 0) 734359Smckusick goto nospace; 745965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), size); 754359Smckusick clrbuf(bp); 764359Smckusick return (bp); 774359Smckusick nospace: 784359Smckusick fserr(fs, "file system full"); 794359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 804359Smckusick u.u_error = ENOSPC; 814359Smckusick return (NULL); 824359Smckusick } 834359Smckusick 845375Smckusic /* 855375Smckusic * Reallocate a fragment to a bigger size 865375Smckusic * 875375Smckusic * The number and size of the old block is given, and a preference 885375Smckusic * and new size is also specified. The allocator attempts to extend 895375Smckusic * the original block. Failing that, the regular block allocator is 905375Smckusic * invoked to get an appropriate block. 915375Smckusic */ 924426Smckusic struct buf * 935965Smckusic realloccg(ip, bprev, bpref, osize, nsize) 945965Smckusic register struct inode *ip; 954651Smckusic daddr_t bprev, bpref; 964426Smckusic int osize, nsize; 974426Smckusic { 984426Smckusic daddr_t bno; 994426Smckusic register struct fs *fs; 1004463Smckusic register struct buf *bp, *obp; 1014463Smckusic caddr_t cp; 1024426Smckusic int cg; 1034426Smckusic 1045965Smckusic fs = ip->i_fs; 1055960Smckusic if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || 1065960Smckusic (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) 1074463Smckusic panic("realloccg: bad size"); 1084792Smckusic if (u.u_uid != 0 && 1095322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 1105322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 1114792Smckusic goto nospace; 112*6294Smckusick if (bprev == 0) 1134463Smckusic panic("realloccg: bad bprev"); 114*6294Smckusick cg = dtog(fs, bprev); 1155965Smckusic bno = fragextend(ip, cg, (long)bprev, osize, nsize); 1164463Smckusic if (bno != 0) { 1175965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bno), osize); 1185960Smckusic if (bp->b_flags & B_ERROR) { 1195960Smckusic brelse(bp); 120*6294Smckusick return (NULL); 1215960Smckusic } 1224463Smckusic bp->b_bcount = nsize; 1234463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1244463Smckusic return (bp); 1254463Smckusic } 1264948Smckusic if (bpref >= fs->fs_size) 1274948Smckusic bpref = 0; 1285965Smckusic bno = (daddr_t)hashalloc(ip, cg, (long)bpref, nsize, alloccg); 1294463Smckusic if (bno != 0) { 1304463Smckusic /* 1314463Smckusic * make a new copy 1324463Smckusic */ 1335965Smckusic obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize); 1345960Smckusic if (obp->b_flags & B_ERROR) { 1355960Smckusic brelse(obp); 136*6294Smckusick return (NULL); 1375960Smckusic } 1385965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), nsize); 1394463Smckusic cp = bp->b_un.b_addr; 1404463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1414463Smckusic obp->b_un.b_addr = cp; 1424463Smckusic obp->b_flags |= B_INVAL; 1434463Smckusic brelse(obp); 1445965Smckusic fre(ip, bprev, (off_t)osize); 1454463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 146*6294Smckusick return (bp); 1474463Smckusic } 1484792Smckusic nospace: 1494463Smckusic /* 1504463Smckusic * no space available 1514463Smckusic */ 1524426Smckusic fserr(fs, "file system full"); 1534426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1544426Smckusic u.u_error = ENOSPC; 1554426Smckusic return (NULL); 1564426Smckusic } 1574426Smckusic 1585375Smckusic /* 1595375Smckusic * Allocate an inode in the file system. 1605375Smckusic * 1615375Smckusic * A preference may be optionally specified. If a preference is given 1625375Smckusic * the following hierarchy is used to allocate an inode: 1635375Smckusic * 1) allocate the requested inode. 1645375Smckusic * 2) allocate an inode in the same cylinder group. 1655375Smckusic * 3) quadradically rehash into other cylinder groups, until an 1665375Smckusic * available inode is located. 1675375Smckusic * If no inode preference is given the following heirarchy is used 1685375Smckusic * to allocate an inode: 1695375Smckusic * 1) allocate an inode in cylinder group 0. 1705375Smckusic * 2) quadradically rehash into other cylinder groups, until an 1715375Smckusic * available inode is located. 1725375Smckusic */ 1734359Smckusick struct inode * 1745965Smckusic ialloc(pip, ipref, mode) 1755965Smckusic register struct inode *pip; 1764359Smckusick ino_t ipref; 1774359Smckusick int mode; 1784359Smckusick { 1795212Smckusic ino_t ino; 1804359Smckusick register struct fs *fs; 1814359Smckusick register struct inode *ip; 1824359Smckusick int cg; 1834359Smckusick 1845965Smckusic fs = pip->i_fs; 1854792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1864359Smckusick goto noinodes; 1874948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 1884948Smckusic ipref = 0; 1895377Smckusic cg = itog(fs, ipref); 1905965Smckusic ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); 1914359Smckusick if (ino == 0) 1924359Smckusick goto noinodes; 1935965Smckusic ip = iget(pip->i_dev, pip->i_fs, ino); 1944359Smckusick if (ip == NULL) { 1955965Smckusic ifree(ip, ino, 0); 1964359Smckusick return (NULL); 1974359Smckusick } 1984359Smckusick if (ip->i_mode) 1994359Smckusick panic("ialloc: dup alloc"); 2004359Smckusick return (ip); 2014359Smckusick noinodes: 2024359Smckusick fserr(fs, "out of inodes"); 203*6294Smckusick uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 2044359Smckusick u.u_error = ENOSPC; 2054359Smckusick return (NULL); 2064359Smckusick } 2074359Smckusick 2084651Smckusic /* 2095375Smckusic * Find a cylinder to place a directory. 2105375Smckusic * 2115375Smckusic * The policy implemented by this algorithm is to select from 2125375Smckusic * among those cylinder groups with above the average number of 2135375Smckusic * free inodes, the one with the smallest number of directories. 2144651Smckusic */ 2155965Smckusic dirpref(fs) 2165965Smckusic register struct fs *fs; 2174359Smckusick { 2184651Smckusic int cg, minndir, mincg, avgifree; 2194359Smckusick 2204792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 2214651Smckusic minndir = fs->fs_ipg; 2224359Smckusick mincg = 0; 2234651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 2245322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 2255322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 2264359Smckusick mincg = cg; 2275322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 2284359Smckusick } 2294359Smckusick return (fs->fs_ipg * mincg); 2304359Smckusick } 2314359Smckusick 2324651Smckusic /* 2335375Smckusic * Select a cylinder to place a large block of data. 2345375Smckusic * 2355375Smckusic * The policy implemented by this algorithm is to maintain a 2365375Smckusic * rotor that sweeps the cylinder groups. When a block is 2375375Smckusic * needed, the rotor is advanced until a cylinder group with 2385375Smckusic * greater than the average number of free blocks is found. 2394651Smckusic */ 2405212Smckusic daddr_t 2415965Smckusic blkpref(fs) 2425965Smckusic register struct fs *fs; 2434651Smckusic { 2444651Smckusic int cg, avgbfree; 2454651Smckusic 2464792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 2474651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 2485322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2494651Smckusic fs->fs_cgrotor = cg; 2505322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2514651Smckusic } 2524651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 2535322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2544651Smckusic fs->fs_cgrotor = cg; 2555322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2564651Smckusic } 257*6294Smckusick return (NULL); 2584651Smckusic } 2594651Smckusic 2605375Smckusic /* 2615375Smckusic * Implement the cylinder overflow algorithm. 2625375Smckusic * 2635375Smckusic * The policy implemented by this algorithm is: 2645375Smckusic * 1) allocate the block in its requested cylinder group. 2655375Smckusic * 2) quadradically rehash on the cylinder group number. 2665375Smckusic * 3) brute force search for a free block. 2675375Smckusic */ 2685212Smckusic /*VARARGS5*/ 2695212Smckusic u_long 2705965Smckusic hashalloc(ip, cg, pref, size, allocator) 2715965Smckusic struct inode *ip; 2724359Smckusick int cg; 2734359Smckusick long pref; 2744359Smckusick int size; /* size for data blocks, mode for inodes */ 2755212Smckusic u_long (*allocator)(); 2764359Smckusick { 2775965Smckusic register struct fs *fs; 2784359Smckusick long result; 2794359Smckusick int i, icg = cg; 2804359Smckusick 2815965Smckusic fs = ip->i_fs; 2824359Smckusick /* 2834359Smckusick * 1: preferred cylinder group 2844359Smckusick */ 2855965Smckusic result = (*allocator)(ip, cg, pref, size); 2864359Smckusick if (result) 2874359Smckusick return (result); 2884359Smckusick /* 2894359Smckusick * 2: quadratic rehash 2904359Smckusick */ 2914359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2924359Smckusick cg += i; 2934359Smckusick if (cg >= fs->fs_ncg) 2944359Smckusick cg -= fs->fs_ncg; 2955965Smckusic result = (*allocator)(ip, cg, 0, size); 2964359Smckusick if (result) 2974359Smckusick return (result); 2984359Smckusick } 2994359Smckusick /* 3004359Smckusick * 3: brute force search 3014359Smckusick */ 3024359Smckusick cg = icg; 3034359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 3045965Smckusic result = (*allocator)(ip, cg, 0, size); 3054359Smckusick if (result) 3064359Smckusick return (result); 3074359Smckusick cg++; 3084359Smckusick if (cg == fs->fs_ncg) 3094359Smckusick cg = 0; 3104359Smckusick } 311*6294Smckusick return (NULL); 3124359Smckusick } 3134359Smckusick 3145375Smckusic /* 3155375Smckusic * Determine whether a fragment can be extended. 3165375Smckusic * 3175375Smckusic * Check to see if the necessary fragments are available, and 3185375Smckusic * if they are, allocate them. 3195375Smckusic */ 3204359Smckusick daddr_t 3215965Smckusic fragextend(ip, cg, bprev, osize, nsize) 3225965Smckusic struct inode *ip; 3234426Smckusic int cg; 3244463Smckusic long bprev; 3254426Smckusic int osize, nsize; 3264426Smckusic { 3275965Smckusic register struct fs *fs; 3284463Smckusic register struct buf *bp; 3294463Smckusic register struct cg *cgp; 3304463Smckusic long bno; 3314463Smckusic int frags, bbase; 3324426Smckusic int i; 3334426Smckusic 3345965Smckusic fs = ip->i_fs; 3355960Smckusic frags = numfrags(fs, nsize); 3365960Smckusic bbase = fragoff(fs, bprev); 3375322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 3384463Smckusic /* cannot extend across a block boundry */ 339*6294Smckusick return (NULL); 3404463Smckusic } 3415965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 3425960Smckusic if (bp->b_flags & B_ERROR) { 3435960Smckusic brelse(bp); 344*6294Smckusick return (NULL); 3455960Smckusic } 3464426Smckusic cgp = bp->b_un.b_cg; 3475377Smckusic bno = dtogd(fs, bprev); 3485960Smckusic for (i = numfrags(fs, osize); i < frags; i++) 3495361Smckusic if (isclr(cgp->cg_free, bno + i)) { 3505361Smckusic brelse(bp); 351*6294Smckusick return (NULL); 3525361Smckusic } 3535361Smckusic /* 3545361Smckusic * the current fragment can be extended 3555361Smckusic * deduct the count on fragment being extended into 3565361Smckusic * increase the count on the remaining fragment (if any) 3575361Smckusic * allocate the extended piece 3585361Smckusic */ 3595361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 3604463Smckusic if (isclr(cgp->cg_free, bno + i)) 3614463Smckusic break; 3625960Smckusic cgp->cg_frsum[i - numfrags(fs, osize)]--; 3635361Smckusic if (i != frags) 3645361Smckusic cgp->cg_frsum[i - frags]++; 3655960Smckusic for (i = numfrags(fs, osize); i < frags; i++) { 3665361Smckusic clrbit(cgp->cg_free, bno + i); 3675361Smckusic cgp->cg_cs.cs_nffree--; 3685361Smckusic fs->fs_cstotal.cs_nffree--; 3695361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3704463Smckusic } 3715361Smckusic fs->fs_fmod++; 3725361Smckusic bdwrite(bp); 3735361Smckusic return (bprev); 3744426Smckusic } 3754426Smckusic 3765375Smckusic /* 3775375Smckusic * Determine whether a block can be allocated. 3785375Smckusic * 3795375Smckusic * Check to see if a block of the apprpriate size is available, 3805375Smckusic * and if it is, allocate it. 3815375Smckusic */ 3824426Smckusic daddr_t 3835965Smckusic alloccg(ip, cg, bpref, size) 3845965Smckusic struct inode *ip; 3854359Smckusick int cg; 3864359Smckusick daddr_t bpref; 3874359Smckusick int size; 3884359Smckusick { 3895965Smckusic register struct fs *fs; 3904463Smckusic register struct buf *bp; 3914463Smckusic register struct cg *cgp; 3924463Smckusic int bno, frags; 3934463Smckusic int allocsiz; 3944463Smckusic register int i; 3954359Smckusick 3965965Smckusic fs = ip->i_fs; 3975322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 398*6294Smckusick return (NULL); 3995965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 4005960Smckusic if (bp->b_flags & B_ERROR) { 4015960Smckusic brelse(bp); 402*6294Smckusick return (NULL); 4035960Smckusic } 4044359Smckusick cgp = bp->b_un.b_cg; 4055322Smckusic if (size == fs->fs_bsize) { 4065212Smckusic bno = alloccgblk(fs, cgp, bpref); 4074463Smckusic bdwrite(bp); 4084463Smckusic return (bno); 4094463Smckusic } 4104463Smckusic /* 4114463Smckusic * check to see if any fragments are already available 4124463Smckusic * allocsiz is the size which will be allocated, hacking 4134463Smckusic * it down to a smaller size if necessary 4144463Smckusic */ 4155960Smckusic frags = numfrags(fs, size); 4165322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 4174463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 4184463Smckusic break; 4195322Smckusic if (allocsiz == fs->fs_frag) { 4204463Smckusic /* 4214463Smckusic * no fragments were available, so a block will be 4224463Smckusic * allocated, and hacked up 4234463Smckusic */ 4244792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 4254463Smckusic brelse(bp); 426*6294Smckusick return (NULL); 4274463Smckusic } 4285212Smckusic bno = alloccgblk(fs, cgp, bpref); 4295377Smckusic bpref = dtogd(fs, bno); 4305322Smckusic for (i = frags; i < fs->fs_frag; i++) 4314463Smckusic setbit(cgp->cg_free, bpref + i); 4325322Smckusic i = fs->fs_frag - frags; 4334792Smckusic cgp->cg_cs.cs_nffree += i; 4344792Smckusic fs->fs_cstotal.cs_nffree += i; 4355322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 4364463Smckusic cgp->cg_frsum[i]++; 4374463Smckusic bdwrite(bp); 4384463Smckusic return (bno); 4394463Smckusic } 4404651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 4414651Smckusic if (bno == 0) 442*6294Smckusick return (NULL); 4434463Smckusic for (i = 0; i < frags; i++) 4444463Smckusic clrbit(cgp->cg_free, bno + i); 4454792Smckusic cgp->cg_cs.cs_nffree -= frags; 4464792Smckusic fs->fs_cstotal.cs_nffree -= frags; 4475322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 4484463Smckusic cgp->cg_frsum[allocsiz]--; 4494463Smckusic if (frags != allocsiz) 4504463Smckusic cgp->cg_frsum[allocsiz - frags]++; 4514463Smckusic bdwrite(bp); 4524463Smckusic return (cg * fs->fs_fpg + bno); 4534463Smckusic } 4544463Smckusic 4555375Smckusic /* 4565375Smckusic * Allocate a block in a cylinder group. 4575375Smckusic * 4585375Smckusic * This algorithm implements the following policy: 4595375Smckusic * 1) allocate the requested block. 4605375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 4615375Smckusic * 3) allocate the next available block on the block rotor for the 4625375Smckusic * specified cylinder group. 4635375Smckusic * Note that this routine only allocates fs_bsize blocks; these 4645375Smckusic * blocks may be fragmented by the routine that allocates them. 4655375Smckusic */ 4664463Smckusic daddr_t 4675212Smckusic alloccgblk(fs, cgp, bpref) 4685965Smckusic register struct fs *fs; 4694463Smckusic register struct cg *cgp; 4704463Smckusic daddr_t bpref; 4714463Smckusic { 4724651Smckusic daddr_t bno; 473*6294Smckusick int cylno, pos, delta; 4744651Smckusic short *cylbp; 4755361Smckusic register int i; 4764463Smckusic 4774651Smckusic if (bpref == 0) { 4784651Smckusic bpref = cgp->cg_rotor; 4795361Smckusic goto norot; 4805361Smckusic } 4815361Smckusic bpref &= ~(fs->fs_frag - 1); 4825377Smckusic bpref = dtogd(fs, bpref); 4835361Smckusic /* 4845361Smckusic * if the requested block is available, use it 4855361Smckusic */ 4865361Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 4875361Smckusic bno = bpref; 4885361Smckusic goto gotit; 4895361Smckusic } 4905361Smckusic /* 4915361Smckusic * check for a block available on the same cylinder 4925361Smckusic */ 4935361Smckusic cylno = cbtocylno(fs, bpref); 4945375Smckusic if (cgp->cg_btot[cylno] == 0) 4955375Smckusic goto norot; 4965375Smckusic if (fs->fs_cpc == 0) { 4975375Smckusic /* 4985375Smckusic * block layout info is not available, so just have 4995375Smckusic * to take any block in this cylinder. 5005375Smckusic */ 5015375Smckusic bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); 5025375Smckusic goto norot; 5035375Smckusic } 5045375Smckusic /* 5055375Smckusic * find a block that is rotationally optimal 5065375Smckusic */ 5075361Smckusic cylbp = cgp->cg_b[cylno]; 5085361Smckusic if (fs->fs_rotdelay == 0) { 5095361Smckusic pos = cbtorpos(fs, bpref); 5104651Smckusic } else { 5114651Smckusic /* 5125361Smckusic * here we convert ms of delay to frags as: 5135361Smckusic * (frags) = (ms) * (rev/sec) * (sect/rev) / 5145361Smckusic * ((sect/frag) * (ms/sec)) 5155361Smckusic * then round up to the next rotational position 5164651Smckusic */ 5175361Smckusic bpref += fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 5185361Smckusic (NSPF(fs) * 1000); 5195361Smckusic pos = cbtorpos(fs, bpref); 5205361Smckusic pos = (pos + 1) % NRPOS; 5215361Smckusic } 5225361Smckusic /* 5235361Smckusic * check the summary information to see if a block is 5245361Smckusic * available in the requested cylinder starting at the 5255361Smckusic * optimal rotational position and proceeding around. 5265361Smckusic */ 5275361Smckusic for (i = pos; i < NRPOS; i++) 5285361Smckusic if (cylbp[i] > 0) 5295361Smckusic break; 5305361Smckusic if (i == NRPOS) 5315361Smckusic for (i = 0; i < pos; i++) 5325361Smckusic if (cylbp[i] > 0) 5335361Smckusic break; 5345361Smckusic if (cylbp[i] > 0) { 5354651Smckusic /* 5365361Smckusic * found a rotational position, now find the actual 5375361Smckusic * block. A panic if none is actually there. 5384651Smckusic */ 5395361Smckusic pos = cylno % fs->fs_cpc; 5405361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 5415361Smckusic if (fs->fs_postbl[pos][i] == -1) 5425361Smckusic panic("alloccgblk: cyl groups corrupted"); 543*6294Smckusick for (i = fs->fs_postbl[pos][i];; ) { 5445361Smckusic if (isblock(fs, cgp->cg_free, bno + i)) { 5455361Smckusic bno = (bno + i) * fs->fs_frag; 5465361Smckusic goto gotit; 5475361Smckusic } 548*6294Smckusick delta = fs->fs_rotbl[i]; 549*6294Smckusick if (delta <= 0 || delta > MAXBPC - i) 5504651Smckusic break; 551*6294Smckusick i += delta; 5524651Smckusic } 5535361Smckusic panic("alloccgblk: can't find blk in cyl"); 5544359Smckusick } 5555361Smckusic norot: 5565361Smckusic /* 5575361Smckusic * no blocks in the requested cylinder, so take next 5585361Smckusic * available one in this cylinder group. 5595361Smckusic */ 5605322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 5614651Smckusic if (bno == 0) 562*6294Smckusick return (NULL); 5634651Smckusic cgp->cg_rotor = bno; 5644359Smckusick gotit: 5655322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 5664792Smckusic cgp->cg_cs.cs_nbfree--; 5674792Smckusic fs->fs_cstotal.cs_nbfree--; 5685322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 5695375Smckusic cylno = cbtocylno(fs, bno); 5705375Smckusic cgp->cg_b[cylno][cbtorpos(fs, bno)]--; 5715375Smckusic cgp->cg_btot[cylno]--; 5724359Smckusick fs->fs_fmod++; 5734651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 5744359Smckusick } 5754359Smckusick 5765375Smckusic /* 5775375Smckusic * Determine whether an inode can be allocated. 5785375Smckusic * 5795375Smckusic * Check to see if an inode is available, and if it is, 5805375Smckusic * allocate it using the following policy: 5815375Smckusic * 1) allocate the requested inode. 5825375Smckusic * 2) allocate the next available inode after the requested 5835375Smckusic * inode in the specified cylinder group. 5845375Smckusic */ 5855212Smckusic ino_t 5865965Smckusic ialloccg(ip, cg, ipref, mode) 5875965Smckusic struct inode *ip; 5884359Smckusick int cg; 5894359Smckusick daddr_t ipref; 5904359Smckusick int mode; 5914359Smckusick { 5925965Smckusic register struct fs *fs; 5934463Smckusic register struct buf *bp; 5944463Smckusic register struct cg *cgp; 5954359Smckusick int i; 5964359Smckusick 5975965Smckusic fs = ip->i_fs; 5985322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 599*6294Smckusick return (NULL); 6005965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 6015960Smckusic if (bp->b_flags & B_ERROR) { 6025960Smckusic brelse(bp); 603*6294Smckusick return (NULL); 6045960Smckusic } 6054359Smckusick cgp = bp->b_un.b_cg; 6064359Smckusick if (ipref) { 6074359Smckusick ipref %= fs->fs_ipg; 6084359Smckusick if (isclr(cgp->cg_iused, ipref)) 6094359Smckusick goto gotit; 6104359Smckusick } else 6114359Smckusick ipref = cgp->cg_irotor; 6124359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 6134359Smckusick ipref++; 6144359Smckusick if (ipref >= fs->fs_ipg) 6154359Smckusick ipref = 0; 6164359Smckusick if (isclr(cgp->cg_iused, ipref)) { 6174359Smckusick cgp->cg_irotor = ipref; 6184359Smckusick goto gotit; 6194359Smckusick } 6204359Smckusick } 6214359Smckusick brelse(bp); 622*6294Smckusick return (NULL); 6234359Smckusick gotit: 6244359Smckusick setbit(cgp->cg_iused, ipref); 6254792Smckusic cgp->cg_cs.cs_nifree--; 6264792Smckusic fs->fs_cstotal.cs_nifree--; 6275322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 6284359Smckusick fs->fs_fmod++; 6294359Smckusick if ((mode & IFMT) == IFDIR) { 6304792Smckusic cgp->cg_cs.cs_ndir++; 6314792Smckusic fs->fs_cstotal.cs_ndir++; 6325322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 6334359Smckusick } 6344359Smckusick bdwrite(bp); 6354359Smckusick return (cg * fs->fs_ipg + ipref); 6364359Smckusick } 6374359Smckusick 6385375Smckusic /* 6395375Smckusic * Free a block or fragment. 6405375Smckusic * 6415375Smckusic * The specified block or fragment is placed back in the 6425375Smckusic * free map. If a fragment is deallocated, a possible 6435375Smckusic * block reassembly is checked. 6445375Smckusic */ 6455965Smckusic fre(ip, bno, size) 6465965Smckusic register struct inode *ip; 6474359Smckusick daddr_t bno; 6485212Smckusic off_t size; 6494359Smckusick { 6504359Smckusick register struct fs *fs; 6514359Smckusick register struct cg *cgp; 6524359Smckusick register struct buf *bp; 6534463Smckusic int cg, blk, frags, bbase; 6544463Smckusic register int i; 6554359Smckusick 6565965Smckusic fs = ip->i_fs; 6575960Smckusic if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) 6584426Smckusic panic("free: bad size"); 6595377Smckusic cg = dtog(fs, bno); 6604359Smckusick if (badblock(fs, bno)) 6614359Smckusick return; 6625965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 6635960Smckusic if (bp->b_flags & B_ERROR) { 6645960Smckusic brelse(bp); 6654359Smckusick return; 6665960Smckusic } 6674359Smckusick cgp = bp->b_un.b_cg; 6685377Smckusic bno = dtogd(fs, bno); 6695322Smckusic if (size == fs->fs_bsize) { 6705322Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) 6714426Smckusic panic("free: freeing free block"); 6725322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 6734792Smckusic cgp->cg_cs.cs_nbfree++; 6744792Smckusic fs->fs_cstotal.cs_nbfree++; 6755322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 6765375Smckusic i = cbtocylno(fs, bno); 6775375Smckusic cgp->cg_b[i][cbtorpos(fs, bno)]++; 6785375Smckusic cgp->cg_btot[i]++; 6794426Smckusic } else { 6805322Smckusic bbase = bno - (bno % fs->fs_frag); 6814463Smckusic /* 6824463Smckusic * decrement the counts associated with the old frags 6834463Smckusic */ 684*6294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 6855322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 6864463Smckusic /* 6874463Smckusic * deallocate the fragment 6884463Smckusic */ 6895960Smckusic frags = numfrags(fs, size); 6904463Smckusic for (i = 0; i < frags; i++) { 6914426Smckusic if (isset(cgp->cg_free, bno + i)) 6924426Smckusic panic("free: freeing free frag"); 6934426Smckusic setbit(cgp->cg_free, bno + i); 6944426Smckusic } 695*6294Smckusick cgp->cg_cs.cs_nffree += i; 696*6294Smckusick fs->fs_cstotal.cs_nffree += i; 697*6294Smckusick fs->fs_cs(fs, cg).cs_nffree += i; 6984463Smckusic /* 6994463Smckusic * add back in counts associated with the new frags 7004463Smckusic */ 701*6294Smckusick blk = blkmap(fs, cgp->cg_free, bbase); 7025322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 7034463Smckusic /* 7044463Smckusic * if a complete block has been reassembled, account for it 7054463Smckusic */ 7065322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 7075322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 7085322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 7095322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 7104792Smckusic cgp->cg_cs.cs_nbfree++; 7114792Smckusic fs->fs_cstotal.cs_nbfree++; 7125322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 7135375Smckusic i = cbtocylno(fs, bbase); 7145375Smckusic cgp->cg_b[i][cbtorpos(fs, bbase)]++; 7155375Smckusic cgp->cg_btot[i]++; 7164426Smckusic } 7174426Smckusic } 7184359Smckusick fs->fs_fmod++; 7194359Smckusick bdwrite(bp); 7204359Smckusick } 7214359Smckusick 7225375Smckusic /* 7235375Smckusic * Free an inode. 7245375Smckusic * 7255375Smckusic * The specified inode is placed back in the free map. 7265375Smckusic */ 7275965Smckusic ifree(ip, ino, mode) 7285965Smckusic struct inode *ip; 7294359Smckusick ino_t ino; 7304359Smckusick int mode; 7314359Smckusick { 7324359Smckusick register struct fs *fs; 7334359Smckusick register struct cg *cgp; 7344359Smckusick register struct buf *bp; 7354359Smckusick int cg; 7364359Smckusick 7375965Smckusic fs = ip->i_fs; 7384359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 7394359Smckusick panic("ifree: range"); 7405377Smckusic cg = itog(fs, ino); 7415965Smckusic bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 7425960Smckusic if (bp->b_flags & B_ERROR) { 7435960Smckusic brelse(bp); 7444359Smckusick return; 7455960Smckusic } 7464359Smckusick cgp = bp->b_un.b_cg; 7474359Smckusick ino %= fs->fs_ipg; 7484359Smckusick if (isclr(cgp->cg_iused, ino)) 7494359Smckusick panic("ifree: freeing free inode"); 7504359Smckusick clrbit(cgp->cg_iused, ino); 7514792Smckusic cgp->cg_cs.cs_nifree++; 7524792Smckusic fs->fs_cstotal.cs_nifree++; 7535322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 7544359Smckusick if ((mode & IFMT) == IFDIR) { 7554792Smckusic cgp->cg_cs.cs_ndir--; 7564792Smckusic fs->fs_cstotal.cs_ndir--; 7575322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 7584359Smckusick } 7594359Smckusick fs->fs_fmod++; 7604359Smckusick bdwrite(bp); 7614359Smckusick } 7624359Smckusick 7634463Smckusic /* 7645375Smckusic * Find a block of the specified size in the specified cylinder group. 7655375Smckusic * 7664651Smckusic * It is a panic if a request is made to find a block if none are 7674651Smckusic * available. 7684651Smckusic */ 7694651Smckusic daddr_t 7704651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 7714651Smckusic register struct fs *fs; 7724651Smckusic register struct cg *cgp; 7734651Smckusic daddr_t bpref; 7744651Smckusic int allocsiz; 7754651Smckusic { 7764651Smckusic daddr_t bno; 7774651Smckusic int start, len, loc, i; 7784651Smckusic int blk, field, subfield, pos; 7794651Smckusic 7804651Smckusic /* 7814651Smckusic * find the fragment by searching through the free block 7824651Smckusic * map for an appropriate bit pattern 7834651Smckusic */ 7844651Smckusic if (bpref) 7855377Smckusic start = dtogd(fs, bpref) / NBBY; 7864651Smckusic else 7874651Smckusic start = cgp->cg_frotor / NBBY; 7885398Smckusic len = howmany(fs->fs_fpg, NBBY) - start; 7895322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7906292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 7914651Smckusic if (loc == 0) { 7925398Smckusic loc = fs->fs_dblkno / NBBY; 7935398Smckusic len = start - loc + 1; 7945398Smckusic start = loc; 7955322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 7966292Smckusick 1 << (allocsiz - 1 + (fs->fs_frag % NBBY))); 7974651Smckusic if (loc == 0) { 7984651Smckusic panic("alloccg: map corrupted"); 799*6294Smckusick return (NULL); 8004651Smckusic } 8014651Smckusic } 8024651Smckusic bno = (start + len - loc) * NBBY; 8034651Smckusic cgp->cg_frotor = bno; 8044651Smckusic /* 8054651Smckusic * found the byte in the map 8064651Smckusic * sift through the bits to find the selected frag 8074651Smckusic */ 808*6294Smckusick for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { 809*6294Smckusick blk = blkmap(fs, cgp->cg_free, bno); 8104651Smckusic blk <<= 1; 8114651Smckusic field = around[allocsiz]; 8124651Smckusic subfield = inside[allocsiz]; 8135322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 814*6294Smckusick if ((blk & field) == subfield) 815*6294Smckusick return (bno + pos); 8164651Smckusic field <<= 1; 8174651Smckusic subfield <<= 1; 8184651Smckusic } 8194651Smckusic } 8204651Smckusic panic("alloccg: block not in map"); 821*6294Smckusick return (NULL); 8224651Smckusic } 8234651Smckusic 8244651Smckusic /* 8255375Smckusic * Update the frsum fields to reflect addition or deletion 8265375Smckusic * of some frags. 8274463Smckusic */ 8285322Smckusic fragacct(fs, fragmap, fraglist, cnt) 8295322Smckusic struct fs *fs; 8304472Smckusic int fragmap; 8314792Smckusic long fraglist[]; 8324463Smckusic int cnt; 8334463Smckusic { 8344463Smckusic int inblk; 8354463Smckusic register int field, subfield; 8364463Smckusic register int siz, pos; 8374463Smckusic 8385322Smckusic inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 8394463Smckusic fragmap <<= 1; 8405322Smckusic for (siz = 1; siz < fs->fs_frag; siz++) { 8416292Smckusick if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 8424463Smckusic continue; 8434463Smckusic field = around[siz]; 8444463Smckusic subfield = inside[siz]; 8455322Smckusic for (pos = siz; pos <= fs->fs_frag; pos++) { 8464463Smckusic if ((fragmap & field) == subfield) { 8474463Smckusic fraglist[siz] += cnt; 8484463Smckusic pos += siz; 8494463Smckusic field <<= siz; 8504463Smckusic subfield <<= siz; 8514463Smckusic } 8524463Smckusic field <<= 1; 8534463Smckusic subfield <<= 1; 8544463Smckusic } 8554463Smckusic } 8564463Smckusic } 8574463Smckusic 8585375Smckusic /* 8595375Smckusic * Check that a specified block number is in range. 8605375Smckusic */ 8614359Smckusick badblock(fs, bn) 8624359Smckusick register struct fs *fs; 8634359Smckusick daddr_t bn; 8644359Smckusick { 8654359Smckusick 8665377Smckusic if ((unsigned)bn >= fs->fs_size || bn < cgdmin(fs, dtog(fs, bn))) { 8674359Smckusick fserr(fs, "bad block"); 8684359Smckusick return (1); 8694359Smckusick } 8704359Smckusick return (0); 8714359Smckusick } 8724359Smckusick 8734359Smckusick /* 8745375Smckusic * Getfs maps a device number into a pointer to the incore super block. 8754359Smckusick * 8765375Smckusic * The algorithm is a linear search through the mount table. A 8775375Smckusic * consistency check of the super block magic number is performed. 8785375Smckusic * 8794359Smckusick * panic: no fs -- the device is not mounted. 8804359Smckusick * this "cannot happen" 8814359Smckusick */ 8824359Smckusick struct fs * 8834359Smckusick getfs(dev) 8844359Smckusick dev_t dev; 8854359Smckusick { 8864359Smckusick register struct mount *mp; 8874359Smckusick register struct fs *fs; 8884359Smckusick 889*6294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 890*6294Smckusick if (mp->m_bufp == NULL || mp->m_dev != dev) 891*6294Smckusick continue; 892*6294Smckusick fs = mp->m_bufp->b_un.b_fs; 893*6294Smckusick if (fs->fs_magic != FS_MAGIC) 894*6294Smckusick panic("getfs: bad magic"); 895*6294Smckusick return (fs); 896*6294Smckusick } 8974359Smckusick panic("getfs: no fs"); 8984359Smckusick return (NULL); 8994359Smckusick } 9004359Smckusick 9014359Smckusick /* 9025375Smckusic * Fserr prints the name of a file system with an error diagnostic. 9035375Smckusic * 9045375Smckusic * The form of the error message is: 9054359Smckusick * fs: error message 9064359Smckusick */ 9074359Smckusick fserr(fs, cp) 9084359Smckusick struct fs *fs; 9094359Smckusick char *cp; 9104359Smckusick { 9114359Smckusick 9124359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 9134359Smckusick } 9144359Smckusick 9154359Smckusick /* 9164359Smckusick * Getfsx returns the index in the file system 9174359Smckusick * table of the specified device. The swap device 9184359Smckusick * is also assigned a pseudo-index. The index may 9194359Smckusick * be used as a compressed indication of the location 9204359Smckusick * of a block, recording 9214359Smckusick * <getfsx(dev),blkno> 9224359Smckusick * rather than 9234359Smckusick * <dev, blkno> 9244359Smckusick * provided the information need remain valid only 9254359Smckusick * as long as the file system is mounted. 9264359Smckusick */ 9274359Smckusick getfsx(dev) 9284359Smckusick dev_t dev; 9294359Smckusick { 9304359Smckusick register struct mount *mp; 9314359Smckusick 9324359Smckusick if (dev == swapdev) 9334359Smckusick return (MSWAPX); 9344359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9354359Smckusick if (mp->m_dev == dev) 9364359Smckusick return (mp - &mount[0]); 9374359Smckusick return (-1); 9384359Smckusick } 9394359Smckusick 9404359Smckusick /* 9414359Smckusick * Update is the internal name of 'sync'. It goes through the disk 9424359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 9435375Smckusic * modified nodes; and it goes through the mount table to initiate 9445375Smckusic * the writing of the modified super blocks. 9454359Smckusick */ 946*6294Smckusick update(flag) 947*6294Smckusick int flag; 9484359Smckusick { 9494359Smckusick register struct inode *ip; 9504359Smckusick register struct mount *mp; 9514359Smckusick register struct buf *bp; 9524359Smckusick struct fs *fs; 9534359Smckusick time_t tim; 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 */ 964*6294Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 965*6294Smckusick if (mp->m_bufp == NULL) 966*6294Smckusick continue; 967*6294Smckusick fs = mp->m_bufp->b_un.b_fs; 968*6294Smckusick if (fs->fs_fmod == 0) 969*6294Smckusick continue; 970*6294Smckusick if (fs->fs_ronly != 0) 971*6294Smckusick panic("update: rofs mod"); 972*6294Smckusick bp = getblk(mp->m_dev, SBLOCK, SBSIZE); 973*6294Smckusick fs->fs_fmod = 0; 974*6294Smckusick fs->fs_time = TIME; 975*6294Smckusick if (bp->b_un.b_fs != fs) 976*6294Smckusick panic("update: bad b_fs"); 977*6294Smckusick bwrite(bp); 978*6294Smckusick blks = howmany(fs->fs_cssize, fs->fs_bsize); 979*6294Smckusick for (i = 0; i < blks; i++) { 980*6294Smckusick bp = getblk(mp->m_dev, 981*6294Smckusick fsbtodb(fs, fs->fs_csaddr + (i * fs->fs_frag)), 982*6294Smckusick fs->fs_bsize); 9834359Smckusick bwrite(bp); 9844359Smckusick } 985*6294Smckusick } 9864359Smckusick /* 9874359Smckusick * Write back each (modified) inode. 9884359Smckusick */ 989*6294Smckusick for (ip = inode; ip < inodeNINODE; ip++) { 990*6294Smckusick if ((ip->i_flag & ILOCK) != 0 || ip->i_count == 0) 991*6294Smckusick continue; 992*6294Smckusick ip->i_flag |= ILOCK; 993*6294Smckusick ip->i_count++; 994*6294Smckusick tim = TIME; 995*6294Smckusick iupdat(ip, &tim, &tim, 0); 996*6294Smckusick iput(ip); 997*6294Smckusick } 9984359Smckusick updlock = 0; 9994359Smckusick /* 10004359Smckusick * Force stale buffer cache information to be flushed, 10014359Smckusick * for all devices. 10024359Smckusick */ 10034359Smckusick bflush(NODEV); 10044359Smckusick } 10055322Smckusic 10065322Smckusic /* 10075375Smckusic * block operations 10085375Smckusic * 10095375Smckusic * check if a block is available 10105322Smckusic */ 10115322Smckusic isblock(fs, cp, h) 10125322Smckusic struct fs *fs; 10135322Smckusic unsigned char *cp; 10145322Smckusic int h; 10155322Smckusic { 10165322Smckusic unsigned char mask; 10175322Smckusic 10185322Smckusic switch (fs->fs_frag) { 10195322Smckusic case 8: 10205322Smckusic return (cp[h] == 0xff); 10215322Smckusic case 4: 10225322Smckusic mask = 0x0f << ((h & 0x1) << 2); 10235322Smckusic return ((cp[h >> 1] & mask) == mask); 10245322Smckusic case 2: 10255322Smckusic mask = 0x03 << ((h & 0x3) << 1); 10265322Smckusic return ((cp[h >> 2] & mask) == mask); 10275322Smckusic case 1: 10285322Smckusic mask = 0x01 << (h & 0x7); 10295322Smckusic return ((cp[h >> 3] & mask) == mask); 10305322Smckusic default: 1031*6294Smckusick panic("isblock"); 1032*6294Smckusick return (NULL); 10335322Smckusic } 10345322Smckusic } 10355375Smckusic 10365375Smckusic /* 10375375Smckusic * take a block out of the map 10385375Smckusic */ 10395322Smckusic clrblock(fs, cp, h) 10405322Smckusic struct fs *fs; 10415322Smckusic unsigned char *cp; 10425322Smckusic int h; 10435322Smckusic { 10445322Smckusic switch ((fs)->fs_frag) { 10455322Smckusic case 8: 10465322Smckusic cp[h] = 0; 10475322Smckusic return; 10485322Smckusic case 4: 10495322Smckusic cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 10505322Smckusic return; 10515322Smckusic case 2: 10525322Smckusic cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 10535322Smckusic return; 10545322Smckusic case 1: 10555322Smckusic cp[h >> 3] &= ~(0x01 << (h & 0x7)); 10565322Smckusic return; 10575322Smckusic default: 1058*6294Smckusick panic("clrblock"); 10595322Smckusic return; 10605322Smckusic } 10615322Smckusic } 10625375Smckusic 10635375Smckusic /* 10645375Smckusic * put a block into the map 10655375Smckusic */ 10665322Smckusic setblock(fs, cp, h) 10675322Smckusic struct fs *fs; 10685322Smckusic unsigned char *cp; 10695322Smckusic int h; 10705322Smckusic { 10715322Smckusic switch (fs->fs_frag) { 10725322Smckusic case 8: 10735322Smckusic cp[h] = 0xff; 10745322Smckusic return; 10755322Smckusic case 4: 10765322Smckusic cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 10775322Smckusic return; 10785322Smckusic case 2: 10795322Smckusic cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 10805322Smckusic return; 10815322Smckusic case 1: 10825322Smckusic cp[h >> 3] |= (0x01 << (h & 0x7)); 10835322Smckusic return; 10845322Smckusic default: 1085*6294Smckusick panic("setblock"); 10865322Smckusic return; 10875322Smckusic } 10885322Smckusic } 1089