14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*4792Smckusic static char vers[] = "@(#)lfs_alloc.c 1.8 11/07/81"; 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 174607Smckusic extern long hashalloc(); 184607Smckusic extern long 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[]; 254607Smckusic extern unsigned char fragtbl[]; 264359Smckusick 274359Smckusick struct buf * 284359Smckusick alloc(dev, ip, bpref, size) 294359Smckusick dev_t dev; 304463Smckusic register struct inode *ip; 314359Smckusick daddr_t bpref; 324359Smckusick int size; 334359Smckusick { 344359Smckusick daddr_t bno; 354359Smckusick register struct fs *fs; 364463Smckusic register struct buf *bp; 374359Smckusick int cg; 384359Smckusick 394463Smckusic if ((unsigned)size > BSIZE || size % FSIZE != 0) 404463Smckusic panic("alloc: bad size"); 414359Smckusick fs = getfs(dev); 42*4792Smckusic if (size == BSIZE && fs->fs_cstotal.cs_nbfree == 0) 434359Smckusick goto nospace; 44*4792Smckusic if (u.u_uid != 0 && 45*4792Smckusic fs->fs_cstotal.cs_nbfree * FRAG + fs->fs_cstotal.cs_nffree < 46*4792Smckusic fs->fs_dsize * minfree / 100) 47*4792Smckusic goto nospace; 484359Smckusick if (bpref == 0) 494359Smckusick cg = itog(ip->i_number, fs); 504359Smckusick else 514359Smckusick cg = dtog(bpref, fs); 524359Smckusick bno = hashalloc(dev, fs, cg, (long)bpref, size, alloccg); 534359Smckusick if (bno == 0) 544359Smckusick goto nospace; 554426Smckusic bp = getblk(dev, bno, size); 564359Smckusick clrbuf(bp); 574359Smckusick return (bp); 584359Smckusick nospace: 594359Smckusick fserr(fs, "file system full"); 604359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 614359Smckusick u.u_error = ENOSPC; 624359Smckusick return (NULL); 634359Smckusick } 644359Smckusick 654426Smckusic struct buf * 664651Smckusic realloccg(dev, ip, bprev, bpref, osize, nsize) 674426Smckusic dev_t dev; 684463Smckusic register struct inode *ip; 694651Smckusic daddr_t bprev, bpref; 704426Smckusic int osize, nsize; 714426Smckusic { 724426Smckusic daddr_t bno; 734426Smckusic register struct fs *fs; 744463Smckusic register struct buf *bp, *obp; 754463Smckusic caddr_t cp; 764426Smckusic int cg; 774426Smckusic 784463Smckusic if ((unsigned)osize > BSIZE || osize % FSIZE != 0 || 794463Smckusic (unsigned)nsize > BSIZE || nsize % FSIZE != 0) 804463Smckusic panic("realloccg: bad size"); 814426Smckusic fs = getfs(dev); 82*4792Smckusic if (u.u_uid != 0 && 83*4792Smckusic fs->fs_cstotal.cs_nbfree * FRAG + fs->fs_cstotal.cs_nffree < 84*4792Smckusic fs->fs_dsize * minfree / 100) 85*4792Smckusic goto nospace; 864463Smckusic if (bprev == 0) 874463Smckusic panic("realloccg: bad bprev"); 884426Smckusic else 894463Smckusic cg = dtog(bprev, fs); 904463Smckusic bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize); 914463Smckusic if (bno != 0) { 924463Smckusic bp = bread(dev, bno, osize); 934463Smckusic bp->b_bcount = nsize; 944463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 954463Smckusic return (bp); 964463Smckusic } 974651Smckusic bno = hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg); 984463Smckusic if (bno != 0) { 994463Smckusic /* 1004463Smckusic * make a new copy 1014463Smckusic */ 1024463Smckusic obp = bread(dev, bprev, osize); 1034463Smckusic bp = getblk(dev, bno, nsize); 1044463Smckusic cp = bp->b_un.b_addr; 1054463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1064463Smckusic obp->b_un.b_addr = cp; 1074463Smckusic obp->b_flags |= B_INVAL; 1084463Smckusic brelse(obp); 1094463Smckusic fre(dev, bprev, osize); 1104463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1114463Smckusic return(bp); 1124463Smckusic } 113*4792Smckusic nospace: 1144463Smckusic /* 1154463Smckusic * no space available 1164463Smckusic */ 1174426Smckusic fserr(fs, "file system full"); 1184426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1194426Smckusic u.u_error = ENOSPC; 1204426Smckusic return (NULL); 1214426Smckusic } 1224426Smckusic 1234359Smckusick struct inode * 1244359Smckusick ialloc(dev, ipref, mode) 1254359Smckusick dev_t dev; 1264359Smckusick ino_t ipref; 1274359Smckusick int mode; 1284359Smckusick { 1294359Smckusick daddr_t ino; 1304359Smckusick register struct fs *fs; 1314359Smckusick register struct inode *ip; 1324359Smckusick int cg; 1334359Smckusick 1344359Smckusick fs = getfs(dev); 135*4792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1364359Smckusick goto noinodes; 1374359Smckusick cg = itog(ipref, fs); 1384359Smckusick ino = hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 1394359Smckusick if (ino == 0) 1404359Smckusick goto noinodes; 1414359Smckusick ip = iget(dev, ino); 1424359Smckusick if (ip == NULL) { 1434359Smckusick ifree(dev, ino); 1444359Smckusick return (NULL); 1454359Smckusick } 1464359Smckusick if (ip->i_mode) 1474359Smckusick panic("ialloc: dup alloc"); 1484359Smckusick return (ip); 1494359Smckusick noinodes: 1504359Smckusick fserr(fs, "out of inodes"); 1514359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 1524359Smckusick u.u_error = ENOSPC; 1534359Smckusick return (NULL); 1544359Smckusick } 1554359Smckusick 1564651Smckusic /* 1574651Smckusic * find a cylinder to place a directory 1584651Smckusic */ 1594651Smckusic dirpref(dev) 1604359Smckusick dev_t dev; 1614359Smckusick { 1624359Smckusick register struct fs *fs; 1634651Smckusic int cg, minndir, mincg, avgifree; 1644359Smckusick 1654359Smckusick fs = getfs(dev); 166*4792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 1674651Smckusic minndir = fs->fs_ipg; 1684359Smckusick mincg = 0; 1694651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 1704651Smckusic if (fs->fs_cs(cg).cs_ndir < minndir && 1714651Smckusic fs->fs_cs(cg).cs_nifree >= avgifree) { 1724359Smckusick mincg = cg; 1734651Smckusic minndir = fs->fs_cs(cg).cs_ndir; 1744359Smckusick } 1754359Smckusick return (fs->fs_ipg * mincg); 1764359Smckusick } 1774359Smckusick 1784651Smckusic /* 1794651Smckusic * select a cylinder to place a large block of data 1804651Smckusic */ 1814651Smckusic blkpref(dev) 1824651Smckusic dev_t dev; 1834651Smckusic { 1844651Smckusic register struct fs *fs; 1854651Smckusic int cg, avgbfree; 1864651Smckusic 1874651Smckusic fs = getfs(dev); 188*4792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 1894651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 1904651Smckusic if (fs->fs_cs(cg).cs_nbfree >= avgbfree) { 1914651Smckusic fs->fs_cgrotor = cg; 1924651Smckusic return (fs->fs_fpg * cg + FRAG); 1934651Smckusic } 1944651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 1954651Smckusic if (fs->fs_cs(cg).cs_nbfree >= avgbfree) { 1964651Smckusic fs->fs_cgrotor = cg; 1974651Smckusic return (fs->fs_fpg * cg + FRAG); 1984651Smckusic } 1994651Smckusic return (0); 2004651Smckusic } 2014651Smckusic 2024359Smckusick long 2034359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 2044359Smckusick dev_t dev; 2054359Smckusick register struct fs *fs; 2064359Smckusick int cg; 2074359Smckusick long pref; 2084359Smckusick int size; /* size for data blocks, mode for inodes */ 2094359Smckusick long (*allocator)(); 2104359Smckusick { 2114359Smckusick long result; 2124359Smckusick int i, icg = cg; 2134359Smckusick 2144359Smckusick /* 2154359Smckusick * 1: preferred cylinder group 2164359Smckusick */ 2174359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 2184359Smckusick if (result) 2194359Smckusick return (result); 2204359Smckusick /* 2214359Smckusick * 2: quadratic rehash 2224359Smckusick */ 2234359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2244359Smckusick cg += i; 2254359Smckusick if (cg >= fs->fs_ncg) 2264359Smckusick cg -= fs->fs_ncg; 2274359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2284359Smckusick if (result) 2294359Smckusick return (result); 2304359Smckusick } 2314359Smckusick /* 2324359Smckusick * 3: brute force search 2334359Smckusick */ 2344359Smckusick cg = icg; 2354359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 2364359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2374359Smckusick if (result) 2384359Smckusick return (result); 2394359Smckusick cg++; 2404359Smckusick if (cg == fs->fs_ncg) 2414359Smckusick cg = 0; 2424359Smckusick } 2434359Smckusick return (0); 2444359Smckusick } 2454359Smckusick 2464359Smckusick daddr_t 2474463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize) 2484426Smckusic dev_t dev; 2494426Smckusic register struct fs *fs; 2504426Smckusic int cg; 2514463Smckusic long bprev; 2524426Smckusic int osize, nsize; 2534426Smckusic { 2544463Smckusic register struct buf *bp; 2554463Smckusic register struct cg *cgp; 2564463Smckusic long bno; 2574463Smckusic int frags, bbase; 2584426Smckusic int i; 2594426Smckusic 2604463Smckusic frags = nsize / FSIZE; 2614463Smckusic bbase = bprev % FRAG; 2624463Smckusic if (bbase > (bprev + frags - 1) % FRAG) { 2634463Smckusic /* cannot extend across a block boundry */ 2644463Smckusic return (0); 2654463Smckusic } 2664426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 2674426Smckusic if (bp->b_flags & B_ERROR) 2684426Smckusic return (0); 2694426Smckusic cgp = bp->b_un.b_cg; 2704463Smckusic bno = bprev % fs->fs_fpg; 2714463Smckusic for (i = osize / FSIZE; i < frags; i++) { 2724463Smckusic if (isclr(cgp->cg_free, bno + i)) 2734463Smckusic break; 2744463Smckusic } 2754463Smckusic if (i == frags) { 2764463Smckusic /* 2774463Smckusic * the current fragment can be extended 2784463Smckusic * deduct the count on fragment being extended into 2794463Smckusic * increase the count on the remaining fragment (if any) 2804463Smckusic * allocate the extended piece 2814463Smckusic */ 2824463Smckusic for (i = frags; i < FRAG - bbase; i++) 2834463Smckusic if (isclr(cgp->cg_free, bno + i)) 2844426Smckusic break; 2854463Smckusic cgp->cg_frsum[i - osize / FSIZE]--; 2864463Smckusic if (i != frags) 2874463Smckusic cgp->cg_frsum[i - frags]++; 2884463Smckusic for (i = osize / FSIZE; i < frags; i++) { 2894463Smckusic clrbit(cgp->cg_free, bno + i); 290*4792Smckusic cgp->cg_cs.cs_nffree--; 291*4792Smckusic fs->fs_cstotal.cs_nffree--; 292*4792Smckusic fs->fs_cs(cg).cs_nffree--; 2934426Smckusic } 2944463Smckusic fs->fs_fmod++; 2954463Smckusic bdwrite(bp); 2964463Smckusic return (bprev); 2974426Smckusic } 2984426Smckusic brelse(bp); 2994426Smckusic return (0); 3004426Smckusic } 3014426Smckusic 3024426Smckusic daddr_t 3034359Smckusick alloccg(dev, fs, cg, bpref, size) 3044359Smckusick dev_t dev; 3054463Smckusic register struct fs *fs; 3064359Smckusick int cg; 3074359Smckusick daddr_t bpref; 3084359Smckusick int size; 3094359Smckusick { 3104463Smckusic register struct buf *bp; 3114463Smckusic register struct cg *cgp; 3124463Smckusic int bno, frags; 3134463Smckusic int allocsiz; 3144463Smckusic register int i; 3154359Smckusick 316*4792Smckusic if (fs->fs_cs(cg).cs_nbfree == 0 && size == BSIZE) 317*4792Smckusic return (0); 3184426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 3194359Smckusick if (bp->b_flags & B_ERROR) 3204359Smckusick return (0); 3214359Smckusick cgp = bp->b_un.b_cg; 3224463Smckusic if (size == BSIZE) { 3234463Smckusic bno = alloccgblk(dev, fs, cgp, bpref); 3244463Smckusic bdwrite(bp); 3254463Smckusic return (bno); 3264463Smckusic } 3274463Smckusic /* 3284463Smckusic * check to see if any fragments are already available 3294463Smckusic * allocsiz is the size which will be allocated, hacking 3304463Smckusic * it down to a smaller size if necessary 3314463Smckusic */ 3324463Smckusic frags = size / FSIZE; 3334463Smckusic for (allocsiz = frags; allocsiz < FRAG; allocsiz++) 3344463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 3354463Smckusic break; 3364463Smckusic if (allocsiz == FRAG) { 3374463Smckusic /* 3384463Smckusic * no fragments were available, so a block will be 3394463Smckusic * allocated, and hacked up 3404463Smckusic */ 341*4792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 3424463Smckusic brelse(bp); 3434463Smckusic return (0); 3444463Smckusic } 3454463Smckusic bno = alloccgblk(dev, fs, cgp, bpref); 3464463Smckusic bpref = bno % fs->fs_fpg; 3474463Smckusic for (i = frags; i < FRAG; i++) 3484463Smckusic setbit(cgp->cg_free, bpref + i); 3494463Smckusic i = FRAG - frags; 350*4792Smckusic cgp->cg_cs.cs_nffree += i; 351*4792Smckusic fs->fs_cstotal.cs_nffree += i; 352*4792Smckusic fs->fs_cs(cg).cs_nffree += i; 3534463Smckusic cgp->cg_frsum[i]++; 3544463Smckusic bdwrite(bp); 3554463Smckusic return (bno); 3564463Smckusic } 3574651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 3584651Smckusic if (bno == 0) 3594651Smckusic return (0); 3604463Smckusic for (i = 0; i < frags; i++) 3614463Smckusic clrbit(cgp->cg_free, bno + i); 362*4792Smckusic cgp->cg_cs.cs_nffree -= frags; 363*4792Smckusic fs->fs_cstotal.cs_nffree -= frags; 364*4792Smckusic fs->fs_cs(cg).cs_nffree -= frags; 3654463Smckusic cgp->cg_frsum[allocsiz]--; 3664463Smckusic if (frags != allocsiz) 3674463Smckusic cgp->cg_frsum[allocsiz - frags]++; 3684463Smckusic bdwrite(bp); 3694463Smckusic return (cg * fs->fs_fpg + bno); 3704463Smckusic } 3714463Smckusic 3724463Smckusic daddr_t 3734463Smckusic alloccgblk(dev, fs, cgp, bpref) 3744463Smckusic dev_t dev; 3754463Smckusic struct fs *fs; 3764463Smckusic register struct cg *cgp; 3774463Smckusic daddr_t bpref; 3784463Smckusic { 3794651Smckusic daddr_t bno; 3804651Smckusic int cylno, pos; 3814651Smckusic short *cylbp; 3824651Smckusic int i, j; 3834463Smckusic 3844651Smckusic if (bpref == 0) { 3854651Smckusic bpref = cgp->cg_rotor; 3864651Smckusic } else { 3874463Smckusic bpref &= ~(FRAG - 1); 3884359Smckusick bpref %= fs->fs_fpg; 3894651Smckusic /* 3904651Smckusic * if the requested block is available, use it 3914651Smckusic */ 3924359Smckusick if (isblock(cgp->cg_free, bpref/FRAG)) { 3934651Smckusic bno = bpref; 3944359Smckusick goto gotit; 3954359Smckusick } 3964651Smckusic /* 3974651Smckusic * check for a block available on the same cylinder 3984651Smckusic * beginning with one which is rotationally optimal 3994651Smckusic */ 4004651Smckusic i = bpref * NSPF; 4014651Smckusic cylno = i / fs->fs_spc; 4024651Smckusic cylbp = cgp->cg_b[cylno]; 4034651Smckusic pos = (i + (ROTDELAY == 0) ? 4044651Smckusic 0 : 1 + ROTDELAY * HZ * fs->fs_nsect / (NSPF * 1000)) % 4054651Smckusic fs->fs_nsect * NRPOS / fs->fs_nsect; 4064651Smckusic for (i = pos; i < NRPOS; i++) 4074651Smckusic if (cylbp[i] > 0) 4084651Smckusic break; 4094651Smckusic if (i == NRPOS) 4104651Smckusic for (i = 0; i < pos; i++) 4114651Smckusic if (cylbp[i] > 0) 4124651Smckusic break; 4134651Smckusic if (cylbp[i] > 0) { 4144651Smckusic bpref = cylno * fs->fs_spc / (NSPF * FRAG); 4154651Smckusic for (j = fs->fs_postbl[i]; j > -1; j = fs->fs_rotbl[j]) { 4164651Smckusic if (isblock(cgp->cg_free, bpref + j)) { 4174651Smckusic bno = (bpref + j) * FRAG; 4184651Smckusic goto gotit; 4194651Smckusic } 4204651Smckusic } 4214651Smckusic panic("alloccgblk: can't find blk in cyl"); 4224651Smckusic } 4234359Smckusick } 4244651Smckusic bno = mapsearch(fs, cgp, bpref, FRAG); 4254651Smckusic if (bno == 0) 4264651Smckusic return (0); 4274651Smckusic cgp->cg_rotor = bno; 4284359Smckusick gotit: 4294651Smckusic clrblock(cgp->cg_free, bno/FRAG); 430*4792Smckusic cgp->cg_cs.cs_nbfree--; 431*4792Smckusic fs->fs_cstotal.cs_nbfree--; 4324651Smckusic fs->fs_cs(cgp->cg_cgx).cs_nbfree--; 4334651Smckusic i = bno * NSPF; 4344463Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--; 4354359Smckusick fs->fs_fmod++; 4364651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 4374359Smckusick } 4384359Smckusick 4394359Smckusick long 4404359Smckusick ialloccg(dev, fs, cg, ipref, mode) 4414359Smckusick dev_t dev; 4424463Smckusic register struct fs *fs; 4434359Smckusick int cg; 4444359Smckusick daddr_t ipref; 4454359Smckusick int mode; 4464359Smckusick { 4474463Smckusic register struct buf *bp; 4484463Smckusic register struct cg *cgp; 4494359Smckusick int i; 4504359Smckusick 451*4792Smckusic if (fs->fs_cs(cg).cs_nifree == 0) 452*4792Smckusic return (0); 4534426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 4544359Smckusick if (bp->b_flags & B_ERROR) 4554359Smckusick return (0); 4564359Smckusick cgp = bp->b_un.b_cg; 4574359Smckusick if (ipref) { 4584359Smckusick ipref %= fs->fs_ipg; 4594359Smckusick if (isclr(cgp->cg_iused, ipref)) 4604359Smckusick goto gotit; 4614359Smckusick } else 4624359Smckusick ipref = cgp->cg_irotor; 4634359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 4644359Smckusick ipref++; 4654359Smckusick if (ipref >= fs->fs_ipg) 4664359Smckusick ipref = 0; 4674359Smckusick if (isclr(cgp->cg_iused, ipref)) { 4684359Smckusick cgp->cg_irotor = ipref; 4694359Smckusick goto gotit; 4704359Smckusick } 4714359Smckusick } 4724359Smckusick brelse(bp); 4734359Smckusick return (0); 4744359Smckusick gotit: 4754359Smckusick setbit(cgp->cg_iused, ipref); 476*4792Smckusic cgp->cg_cs.cs_nifree--; 477*4792Smckusic fs->fs_cstotal.cs_nifree--; 4784651Smckusic fs->fs_cs(cg).cs_nifree--; 4794359Smckusick fs->fs_fmod++; 4804359Smckusick if ((mode & IFMT) == IFDIR) { 481*4792Smckusic cgp->cg_cs.cs_ndir++; 482*4792Smckusic fs->fs_cstotal.cs_ndir++; 4834651Smckusic fs->fs_cs(cg).cs_ndir++; 4844359Smckusick } 4854359Smckusick bdwrite(bp); 4864359Smckusick return (cg * fs->fs_ipg + ipref); 4874359Smckusick } 4884359Smckusick 4894359Smckusick fre(dev, bno, size) 4904359Smckusick dev_t dev; 4914359Smckusick daddr_t bno; 4924359Smckusick int size; 4934359Smckusick { 4944359Smckusick register struct fs *fs; 4954359Smckusick register struct cg *cgp; 4964359Smckusick register struct buf *bp; 4974463Smckusic int cg, blk, frags, bbase; 4984463Smckusic register int i; 4994359Smckusick 5004426Smckusic if ((unsigned)size > BSIZE || size % FSIZE != 0) 5014426Smckusic panic("free: bad size"); 5024359Smckusick fs = getfs(dev); 5034359Smckusick cg = dtog(bno, fs); 5044359Smckusick if (badblock(fs, bno)) 5054359Smckusick return; 5064426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 5074359Smckusick if (bp->b_flags & B_ERROR) 5084359Smckusick return; 5094359Smckusick cgp = bp->b_un.b_cg; 5104359Smckusick bno %= fs->fs_fpg; 5114426Smckusic if (size == BSIZE) { 5124426Smckusic if (isblock(cgp->cg_free, bno/FRAG)) 5134426Smckusic panic("free: freeing free block"); 5144426Smckusic setblock(cgp->cg_free, bno/FRAG); 515*4792Smckusic cgp->cg_cs.cs_nbfree++; 516*4792Smckusic fs->fs_cstotal.cs_nbfree++; 5174651Smckusic fs->fs_cs(cg).cs_nbfree++; 5184426Smckusic i = bno * NSPF; 5194426Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++; 5204426Smckusic } else { 5214463Smckusic bbase = bno - (bno % FRAG); 5224463Smckusic /* 5234463Smckusic * decrement the counts associated with the old frags 5244463Smckusic */ 5254463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5264463Smckusic (0xff >> (NBBY - FRAG))); 5274463Smckusic fragacct(blk, cgp->cg_frsum, -1); 5284463Smckusic /* 5294463Smckusic * deallocate the fragment 5304463Smckusic */ 5314463Smckusic frags = size / FSIZE; 5324463Smckusic for (i = 0; i < frags; i++) { 5334426Smckusic if (isset(cgp->cg_free, bno + i)) 5344426Smckusic panic("free: freeing free frag"); 5354426Smckusic setbit(cgp->cg_free, bno + i); 536*4792Smckusic cgp->cg_cs.cs_nffree++; 537*4792Smckusic fs->fs_cstotal.cs_nffree++; 538*4792Smckusic fs->fs_cs(cg).cs_nffree++; 5394426Smckusic } 5404463Smckusic /* 5414463Smckusic * add back in counts associated with the new frags 5424463Smckusic */ 5434463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5444463Smckusic (0xff >> (NBBY - FRAG))); 5454463Smckusic fragacct(blk, cgp->cg_frsum, 1); 5464463Smckusic /* 5474463Smckusic * if a complete block has been reassembled, account for it 5484463Smckusic */ 5494463Smckusic if (isblock(cgp->cg_free, bbase / FRAG)) { 550*4792Smckusic cgp->cg_cs.cs_nffree -= FRAG; 551*4792Smckusic fs->fs_cstotal.cs_nffree -= FRAG; 552*4792Smckusic fs->fs_cs(cg).cs_nffree -= FRAG; 553*4792Smckusic cgp->cg_cs.cs_nbfree++; 554*4792Smckusic fs->fs_cstotal.cs_nbfree++; 5554651Smckusic fs->fs_cs(cg).cs_nbfree++; 5564463Smckusic i = bbase * NSPF; 5574426Smckusic cgp->cg_b[i / fs->fs_spc] 5584426Smckusic [i % fs->fs_nsect * NRPOS / fs->fs_nsect]++; 5594426Smckusic } 5604426Smckusic } 5614359Smckusick fs->fs_fmod++; 5624359Smckusick bdwrite(bp); 5634359Smckusick } 5644359Smckusick 5654359Smckusick ifree(dev, ino, mode) 5664359Smckusick dev_t dev; 5674359Smckusick ino_t ino; 5684359Smckusick int mode; 5694359Smckusick { 5704359Smckusick register struct fs *fs; 5714359Smckusick register struct cg *cgp; 5724359Smckusick register struct buf *bp; 5734359Smckusick int i; 5744359Smckusick int cg; 5754359Smckusick 5764359Smckusick fs = getfs(dev); 5774359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 5784359Smckusick panic("ifree: range"); 5794359Smckusick cg = itog(ino, fs); 5804426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 5814359Smckusick if (bp->b_flags & B_ERROR) 5824359Smckusick return; 5834359Smckusick cgp = bp->b_un.b_cg; 5844359Smckusick ino %= fs->fs_ipg; 5854359Smckusick if (isclr(cgp->cg_iused, ino)) 5864359Smckusick panic("ifree: freeing free inode"); 5874359Smckusick clrbit(cgp->cg_iused, ino); 588*4792Smckusic cgp->cg_cs.cs_nifree++; 589*4792Smckusic fs->fs_cstotal.cs_nifree++; 5904651Smckusic fs->fs_cs(cg).cs_nifree++; 5914359Smckusick if ((mode & IFMT) == IFDIR) { 592*4792Smckusic cgp->cg_cs.cs_ndir--; 593*4792Smckusic fs->fs_cstotal.cs_ndir--; 5944651Smckusic fs->fs_cs(cg).cs_ndir--; 5954359Smckusick } 5964359Smckusick fs->fs_fmod++; 5974359Smckusick bdwrite(bp); 5984359Smckusick } 5994359Smckusick 6004463Smckusic /* 6014651Smckusic * find a block of the specified size in the specified cylinder group 6024651Smckusic * It is a panic if a request is made to find a block if none are 6034651Smckusic * available. 6044651Smckusic */ 6054651Smckusic daddr_t 6064651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 6074651Smckusic register struct fs *fs; 6084651Smckusic register struct cg *cgp; 6094651Smckusic daddr_t bpref; 6104651Smckusic int allocsiz; 6114651Smckusic { 6124651Smckusic daddr_t bno; 6134651Smckusic int start, len, loc, i; 6144651Smckusic int blk, field, subfield, pos; 6154651Smckusic 6164651Smckusic /* 6174651Smckusic * find the fragment by searching through the free block 6184651Smckusic * map for an appropriate bit pattern 6194651Smckusic */ 6204651Smckusic if (bpref) 6214651Smckusic start = bpref % fs->fs_fpg / NBBY; 6224651Smckusic else 6234651Smckusic start = cgp->cg_frotor / NBBY; 6244651Smckusic len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start; 6254651Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl, 1 << (allocsiz - 1)); 6264651Smckusic if (loc == 0) { 6274651Smckusic len = start - 1; 6284651Smckusic start = (cgdmin(cgp->cg_cgx, fs) - 6294651Smckusic cgbase(cgp->cg_cgx, fs)) / NBBY; 6304651Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl, 6314651Smckusic 1 << (allocsiz - 1)); 6324651Smckusic if (loc == 0) { 6334651Smckusic panic("alloccg: map corrupted"); 6344651Smckusic return (0); 6354651Smckusic } 6364651Smckusic } 6374651Smckusic bno = (start + len - loc) * NBBY; 6384651Smckusic cgp->cg_frotor = bno; 6394651Smckusic /* 6404651Smckusic * found the byte in the map 6414651Smckusic * sift through the bits to find the selected frag 6424651Smckusic */ 6434651Smckusic for (i = 0; i < NBBY; i += FRAG) { 6444651Smckusic blk = (cgp->cg_free[bno / NBBY] >> i) & (0xff >> NBBY - FRAG); 6454651Smckusic blk <<= 1; 6464651Smckusic field = around[allocsiz]; 6474651Smckusic subfield = inside[allocsiz]; 6484651Smckusic for (pos = 0; pos <= FRAG - allocsiz; pos++) { 6494651Smckusic if ((blk & field) == subfield) { 6504651Smckusic return (bno + i + pos); 6514651Smckusic } 6524651Smckusic field <<= 1; 6534651Smckusic subfield <<= 1; 6544651Smckusic } 6554651Smckusic } 6564651Smckusic panic("alloccg: block not in map"); 6574651Smckusic return (0); 6584651Smckusic } 6594651Smckusic 6604651Smckusic /* 6614463Smckusic * update the frsum fields to reflect addition or deletion 6624463Smckusic * of some frags 6634463Smckusic */ 6644463Smckusic fragacct(fragmap, fraglist, cnt) 6654472Smckusic int fragmap; 666*4792Smckusic long fraglist[]; 6674463Smckusic int cnt; 6684463Smckusic { 6694463Smckusic int inblk; 6704463Smckusic register int field, subfield; 6714463Smckusic register int siz, pos; 6724463Smckusic 6734472Smckusic inblk = (int)(fragtbl[fragmap]) << 1; 6744463Smckusic fragmap <<= 1; 6754463Smckusic for (siz = 1; siz < FRAG; siz++) { 6764463Smckusic if (((1 << siz) & inblk) == 0) 6774463Smckusic continue; 6784463Smckusic field = around[siz]; 6794463Smckusic subfield = inside[siz]; 6804463Smckusic for (pos = siz; pos <= FRAG; pos++) { 6814463Smckusic if ((fragmap & field) == subfield) { 6824463Smckusic fraglist[siz] += cnt; 6834463Smckusic pos += siz; 6844463Smckusic field <<= siz; 6854463Smckusic subfield <<= siz; 6864463Smckusic } 6874463Smckusic field <<= 1; 6884463Smckusic subfield <<= 1; 6894463Smckusic } 6904463Smckusic } 6914463Smckusic } 6924463Smckusic 6934359Smckusick badblock(fs, bn) 6944359Smckusick register struct fs *fs; 6954359Smckusick daddr_t bn; 6964359Smckusick { 6974359Smckusick 6984359Smckusick if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) { 6994359Smckusick fserr(fs, "bad block"); 7004359Smckusick return (1); 7014359Smckusick } 7024359Smckusick return (0); 7034359Smckusick } 7044359Smckusick 7054359Smckusick /* 7064359Smckusick * getfs maps a device number into 7074359Smckusick * a pointer to the incore super 7084359Smckusick * block. The algorithm is a linear 7094359Smckusick * search through the mount table. 7104359Smckusick * A consistency check of the 7114359Smckusick * in core free-block and i-node 7124359Smckusick * counts is performed. 7134359Smckusick * 7144359Smckusick * panic: no fs -- the device is not mounted. 7154359Smckusick * this "cannot happen" 7164359Smckusick */ 7174359Smckusick struct fs * 7184359Smckusick getfs(dev) 7194359Smckusick dev_t dev; 7204359Smckusick { 7214359Smckusick register struct mount *mp; 7224359Smckusick register struct fs *fs; 7234359Smckusick 7244359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7254359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 7264359Smckusick fs = mp->m_bufp->b_un.b_fs; 7274359Smckusick if (fs->fs_magic != FS_MAGIC) 7284359Smckusick panic("getfs: bad magic"); 7294359Smckusick return (fs); 7304359Smckusick } 7314359Smckusick panic("getfs: no fs"); 7324359Smckusick return (NULL); 7334359Smckusick } 7344359Smckusick 7354359Smckusick /* 7364359Smckusick * Fserr prints the name of a file system 7374359Smckusick * with an error diagnostic, in the form 7384359Smckusick * fs: error message 7394359Smckusick */ 7404359Smckusick fserr(fs, cp) 7414359Smckusick struct fs *fs; 7424359Smckusick char *cp; 7434359Smckusick { 7444359Smckusick 7454359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 7464359Smckusick } 7474359Smckusick 7484359Smckusick /* 7494359Smckusick * Getfsx returns the index in the file system 7504359Smckusick * table of the specified device. The swap device 7514359Smckusick * is also assigned a pseudo-index. The index may 7524359Smckusick * be used as a compressed indication of the location 7534359Smckusick * of a block, recording 7544359Smckusick * <getfsx(dev),blkno> 7554359Smckusick * rather than 7564359Smckusick * <dev, blkno> 7574359Smckusick * provided the information need remain valid only 7584359Smckusick * as long as the file system is mounted. 7594359Smckusick */ 7604359Smckusick getfsx(dev) 7614359Smckusick dev_t dev; 7624359Smckusick { 7634359Smckusick register struct mount *mp; 7644359Smckusick 7654359Smckusick if (dev == swapdev) 7664359Smckusick return (MSWAPX); 7674359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7684359Smckusick if (mp->m_dev == dev) 7694359Smckusick return (mp - &mount[0]); 7704359Smckusick return (-1); 7714359Smckusick } 7724359Smckusick 7734359Smckusick /* 7744359Smckusick * Update is the internal name of 'sync'. It goes through the disk 7754359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 7764359Smckusick * modified nodes; and it goes through the mount table to initiate modified 7774359Smckusick * super blocks. 7784359Smckusick */ 7794359Smckusick update() 7804359Smckusick { 7814359Smckusick register struct inode *ip; 7824359Smckusick register struct mount *mp; 7834359Smckusick register struct buf *bp; 7844359Smckusick struct fs *fs; 7854359Smckusick time_t tim; 7864651Smckusic int i, blks; 7874359Smckusick 7884359Smckusick if (updlock) 7894359Smckusick return; 7904359Smckusick updlock++; 7914359Smckusick /* 7924359Smckusick * Write back modified superblocks. 7934359Smckusick * Consistency check that the superblock 7944359Smckusick * of each file system is still in the buffer cache. 7954359Smckusick */ 7964359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7974359Smckusick if (mp->m_bufp != NULL) { 7984359Smckusick fs = mp->m_bufp->b_un.b_fs; 7994359Smckusick if (fs->fs_fmod == 0) 8004359Smckusick continue; 8014359Smckusick if (fs->fs_ronly != 0) 8024359Smckusick panic("update: rofs mod"); 8034426Smckusic bp = getblk(mp->m_dev, SBLOCK, BSIZE); 8044359Smckusick fs->fs_fmod = 0; 8054359Smckusick fs->fs_time = TIME; 8064359Smckusick if (bp->b_un.b_fs != fs) 8074359Smckusick panic("update: bad b_fs"); 8084359Smckusick bwrite(bp); 8094651Smckusic blks = howmany(cssize(fs), BSIZE); 8104651Smckusic for (i = 0; i < blks; i++) { 8114651Smckusic bp = getblk(mp->m_dev, csaddr(fs) + (i * FRAG), 8124426Smckusic BSIZE); 8134359Smckusick bwrite(bp); 8144359Smckusick } 8154359Smckusick } 8164359Smckusick /* 8174359Smckusick * Write back each (modified) inode. 8184359Smckusick */ 8194359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 8204359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 8214359Smckusick ip->i_flag |= ILOCK; 8224359Smckusick ip->i_count++; 8234359Smckusick tim = TIME; 8244359Smckusick iupdat(ip, &tim, &tim, 0); 8254359Smckusick iput(ip); 8264359Smckusick } 8274359Smckusick updlock = 0; 8284359Smckusick /* 8294359Smckusick * Force stale buffer cache information to be flushed, 8304359Smckusick * for all devices. 8314359Smckusick */ 8324359Smckusick bflush(NODEV); 8334359Smckusick } 834