14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*4651Smckusic static char vers[] = "@(#)lfs_alloc.c 1.7 10/29/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(); 19*4651Smckusic extern daddr_t alloccg(); 20*4651Smckusic extern daddr_t alloccgblk(); 21*4651Smckusic extern daddr_t fragextend(); 22*4651Smckusic extern daddr_t blkpref(); 23*4651Smckusic 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*4651Smckusic if (size == BSIZE && 43*4651Smckusic (fs->fs_nbfree == 0 || 44*4651Smckusic (!suser() && fs->fs_nbfree < fs->fs_nbfree * minfree / 100))) 454359Smckusick goto nospace; 464359Smckusick if (bpref == 0) 474359Smckusick cg = itog(ip->i_number, fs); 484359Smckusick else 494359Smckusick cg = dtog(bpref, fs); 504359Smckusick bno = hashalloc(dev, fs, cg, (long)bpref, size, alloccg); 514359Smckusick if (bno == 0) 524359Smckusick goto nospace; 534426Smckusic bp = getblk(dev, bno, size); 544359Smckusick clrbuf(bp); 554359Smckusick return (bp); 564359Smckusick nospace: 574359Smckusick fserr(fs, "file system full"); 584359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 594359Smckusick u.u_error = ENOSPC; 604359Smckusick return (NULL); 614359Smckusick } 624359Smckusick 634426Smckusic struct buf * 64*4651Smckusic realloccg(dev, ip, bprev, bpref, osize, nsize) 654426Smckusic dev_t dev; 664463Smckusic register struct inode *ip; 67*4651Smckusic daddr_t bprev, bpref; 684426Smckusic int osize, nsize; 694426Smckusic { 704426Smckusic daddr_t bno; 714426Smckusic register struct fs *fs; 724463Smckusic register struct buf *bp, *obp; 734463Smckusic caddr_t cp; 744426Smckusic int cg; 754426Smckusic 764463Smckusic if ((unsigned)osize > BSIZE || osize % FSIZE != 0 || 774463Smckusic (unsigned)nsize > BSIZE || nsize % FSIZE != 0) 784463Smckusic panic("realloccg: bad size"); 794426Smckusic fs = getfs(dev); 804463Smckusic if (bprev == 0) 814463Smckusic panic("realloccg: bad bprev"); 824426Smckusic else 834463Smckusic cg = dtog(bprev, fs); 844463Smckusic bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize); 854463Smckusic if (bno != 0) { 864463Smckusic bp = bread(dev, bno, osize); 874463Smckusic bp->b_bcount = nsize; 884463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 894463Smckusic return (bp); 904463Smckusic } 91*4651Smckusic bno = hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg); 924463Smckusic if (bno != 0) { 934463Smckusic /* 944463Smckusic * make a new copy 954463Smckusic */ 964463Smckusic obp = bread(dev, bprev, osize); 974463Smckusic bp = getblk(dev, bno, nsize); 984463Smckusic cp = bp->b_un.b_addr; 994463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1004463Smckusic obp->b_un.b_addr = cp; 1014463Smckusic obp->b_flags |= B_INVAL; 1024463Smckusic brelse(obp); 1034463Smckusic fre(dev, bprev, osize); 1044463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1054463Smckusic return(bp); 1064463Smckusic } 1074463Smckusic /* 1084463Smckusic * no space available 1094463Smckusic */ 1104426Smckusic fserr(fs, "file system full"); 1114426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1124426Smckusic u.u_error = ENOSPC; 1134426Smckusic return (NULL); 1144426Smckusic } 1154426Smckusic 1164359Smckusick struct inode * 1174359Smckusick ialloc(dev, ipref, mode) 1184359Smckusick dev_t dev; 1194359Smckusick ino_t ipref; 1204359Smckusick int mode; 1214359Smckusick { 1224359Smckusick daddr_t ino; 1234359Smckusick register struct fs *fs; 1244359Smckusick register struct inode *ip; 1254359Smckusick int cg; 1264359Smckusick 1274359Smckusick fs = getfs(dev); 1284359Smckusick if (fs->fs_nifree == 0) 1294359Smckusick goto noinodes; 1304359Smckusick cg = itog(ipref, fs); 1314359Smckusick ino = hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 1324359Smckusick if (ino == 0) 1334359Smckusick goto noinodes; 1344359Smckusick ip = iget(dev, ino); 1354359Smckusick if (ip == NULL) { 1364359Smckusick ifree(dev, ino); 1374359Smckusick return (NULL); 1384359Smckusick } 1394359Smckusick if (ip->i_mode) 1404359Smckusick panic("ialloc: dup alloc"); 1414359Smckusick return (ip); 1424359Smckusick noinodes: 1434359Smckusick fserr(fs, "out of inodes"); 1444359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 1454359Smckusick u.u_error = ENOSPC; 1464359Smckusick return (NULL); 1474359Smckusick } 1484359Smckusick 149*4651Smckusic /* 150*4651Smckusic * find a cylinder to place a directory 151*4651Smckusic */ 152*4651Smckusic dirpref(dev) 1534359Smckusick dev_t dev; 1544359Smckusick { 1554359Smckusick register struct fs *fs; 156*4651Smckusic int cg, minndir, mincg, avgifree; 1574359Smckusick 1584359Smckusick fs = getfs(dev); 159*4651Smckusic avgifree = fs->fs_nifree / fs->fs_ncg; 160*4651Smckusic minndir = fs->fs_ipg; 1614359Smckusick mincg = 0; 162*4651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 163*4651Smckusic if (fs->fs_cs(cg).cs_ndir < minndir && 164*4651Smckusic fs->fs_cs(cg).cs_nifree >= avgifree) { 1654359Smckusick mincg = cg; 166*4651Smckusic minndir = fs->fs_cs(cg).cs_ndir; 1674359Smckusick } 1684359Smckusick return (fs->fs_ipg * mincg); 1694359Smckusick } 1704359Smckusick 171*4651Smckusic /* 172*4651Smckusic * select a cylinder to place a large block of data 173*4651Smckusic */ 174*4651Smckusic blkpref(dev) 175*4651Smckusic dev_t dev; 176*4651Smckusic { 177*4651Smckusic register struct fs *fs; 178*4651Smckusic int cg, avgbfree; 179*4651Smckusic 180*4651Smckusic fs = getfs(dev); 181*4651Smckusic avgbfree = fs->fs_nbfree / fs->fs_ncg; 182*4651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 183*4651Smckusic if (fs->fs_cs(cg).cs_nbfree >= avgbfree) { 184*4651Smckusic fs->fs_cgrotor = cg; 185*4651Smckusic return (fs->fs_fpg * cg + FRAG); 186*4651Smckusic } 187*4651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 188*4651Smckusic if (fs->fs_cs(cg).cs_nbfree >= avgbfree) { 189*4651Smckusic fs->fs_cgrotor = cg; 190*4651Smckusic return (fs->fs_fpg * cg + FRAG); 191*4651Smckusic } 192*4651Smckusic return (0); 193*4651Smckusic } 194*4651Smckusic 1954359Smckusick long 1964359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 1974359Smckusick dev_t dev; 1984359Smckusick register struct fs *fs; 1994359Smckusick int cg; 2004359Smckusick long pref; 2014359Smckusick int size; /* size for data blocks, mode for inodes */ 2024359Smckusick long (*allocator)(); 2034359Smckusick { 2044359Smckusick long result; 2054359Smckusick int i, icg = cg; 2064359Smckusick 2074359Smckusick /* 2084359Smckusick * 1: preferred cylinder group 2094359Smckusick */ 2104359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 2114359Smckusick if (result) 2124359Smckusick return (result); 2134359Smckusick /* 2144359Smckusick * 2: quadratic rehash 2154359Smckusick */ 2164359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2174359Smckusick cg += i; 2184359Smckusick if (cg >= fs->fs_ncg) 2194359Smckusick cg -= fs->fs_ncg; 2204359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2214359Smckusick if (result) 2224359Smckusick return (result); 2234359Smckusick } 2244359Smckusick /* 2254359Smckusick * 3: brute force search 2264359Smckusick */ 2274359Smckusick cg = icg; 2284359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 2294359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2304359Smckusick if (result) 2314359Smckusick return (result); 2324359Smckusick cg++; 2334359Smckusick if (cg == fs->fs_ncg) 2344359Smckusick cg = 0; 2354359Smckusick } 2364359Smckusick return (0); 2374359Smckusick } 2384359Smckusick 2394359Smckusick daddr_t 2404463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize) 2414426Smckusic dev_t dev; 2424426Smckusic register struct fs *fs; 2434426Smckusic int cg; 2444463Smckusic long bprev; 2454426Smckusic int osize, nsize; 2464426Smckusic { 2474463Smckusic register struct buf *bp; 2484463Smckusic register struct cg *cgp; 2494463Smckusic long bno; 2504463Smckusic int frags, bbase; 2514426Smckusic int i; 2524426Smckusic 2534463Smckusic frags = nsize / FSIZE; 2544463Smckusic bbase = bprev % FRAG; 2554463Smckusic if (bbase > (bprev + frags - 1) % FRAG) { 2564463Smckusic /* cannot extend across a block boundry */ 2574463Smckusic return (0); 2584463Smckusic } 2594426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 2604426Smckusic if (bp->b_flags & B_ERROR) 2614426Smckusic return (0); 2624426Smckusic cgp = bp->b_un.b_cg; 2634463Smckusic bno = bprev % fs->fs_fpg; 2644463Smckusic for (i = osize / FSIZE; i < frags; i++) { 2654463Smckusic if (isclr(cgp->cg_free, bno + i)) 2664463Smckusic break; 2674463Smckusic } 2684463Smckusic if (i == frags) { 2694463Smckusic /* 2704463Smckusic * the current fragment can be extended 2714463Smckusic * deduct the count on fragment being extended into 2724463Smckusic * increase the count on the remaining fragment (if any) 2734463Smckusic * allocate the extended piece 2744463Smckusic */ 2754463Smckusic for (i = frags; i < FRAG - bbase; i++) 2764463Smckusic if (isclr(cgp->cg_free, bno + i)) 2774426Smckusic break; 2784463Smckusic cgp->cg_frsum[i - osize / FSIZE]--; 2794463Smckusic if (i != frags) 2804463Smckusic cgp->cg_frsum[i - frags]++; 2814463Smckusic for (i = osize / FSIZE; i < frags; i++) { 2824463Smckusic clrbit(cgp->cg_free, bno + i); 2834463Smckusic cgp->cg_nffree--; 2844463Smckusic fs->fs_nffree--; 2854426Smckusic } 2864463Smckusic fs->fs_fmod++; 2874463Smckusic bdwrite(bp); 2884463Smckusic return (bprev); 2894426Smckusic } 2904426Smckusic brelse(bp); 2914426Smckusic return (0); 2924426Smckusic } 2934426Smckusic 2944426Smckusic daddr_t 2954359Smckusick alloccg(dev, fs, cg, bpref, size) 2964359Smckusick dev_t dev; 2974463Smckusic register struct fs *fs; 2984359Smckusick int cg; 2994359Smckusick daddr_t bpref; 3004359Smckusick int size; 3014359Smckusick { 3024463Smckusic register struct buf *bp; 3034463Smckusic register struct cg *cgp; 3044463Smckusic int bno, frags; 3054463Smckusic int allocsiz; 3064463Smckusic register int i; 3074359Smckusick 3084426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 3094359Smckusick if (bp->b_flags & B_ERROR) 3104359Smckusick return (0); 3114359Smckusick cgp = bp->b_un.b_cg; 3124463Smckusic if (size == BSIZE) { 3134463Smckusic if (cgp->cg_nbfree == 0) { 3144463Smckusic brelse(bp); 3154463Smckusic return (0); 3164463Smckusic } 3174463Smckusic bno = alloccgblk(dev, fs, cgp, bpref); 3184463Smckusic bdwrite(bp); 3194463Smckusic return (bno); 3204463Smckusic } 3214463Smckusic /* 3224463Smckusic * check to see if any fragments are already available 3234463Smckusic * allocsiz is the size which will be allocated, hacking 3244463Smckusic * it down to a smaller size if necessary 3254463Smckusic */ 3264463Smckusic frags = size / FSIZE; 3274463Smckusic for (allocsiz = frags; allocsiz < FRAG; allocsiz++) 3284463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 3294463Smckusic break; 3304463Smckusic if (allocsiz == FRAG) { 3314463Smckusic /* 3324463Smckusic * no fragments were available, so a block will be 3334463Smckusic * allocated, and hacked up 3344463Smckusic */ 3354463Smckusic if (cgp->cg_nbfree == 0) { 3364463Smckusic brelse(bp); 3374463Smckusic return (0); 3384463Smckusic } 3394463Smckusic bno = alloccgblk(dev, fs, cgp, bpref); 3404463Smckusic bpref = bno % fs->fs_fpg; 3414463Smckusic for (i = frags; i < FRAG; i++) 3424463Smckusic setbit(cgp->cg_free, bpref + i); 3434463Smckusic i = FRAG - frags; 3444463Smckusic cgp->cg_nffree += i; 3454463Smckusic fs->fs_nffree += i; 3464463Smckusic cgp->cg_frsum[i]++; 3474463Smckusic bdwrite(bp); 3484463Smckusic return (bno); 3494463Smckusic } 350*4651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 351*4651Smckusic if (bno == 0) 352*4651Smckusic return (0); 3534463Smckusic for (i = 0; i < frags; i++) 3544463Smckusic clrbit(cgp->cg_free, bno + i); 3554463Smckusic cgp->cg_nffree -= frags; 3564463Smckusic fs->fs_nffree -= frags; 3574463Smckusic cgp->cg_frsum[allocsiz]--; 3584463Smckusic if (frags != allocsiz) 3594463Smckusic cgp->cg_frsum[allocsiz - frags]++; 3604463Smckusic bdwrite(bp); 3614463Smckusic return (cg * fs->fs_fpg + bno); 3624463Smckusic } 3634463Smckusic 3644463Smckusic daddr_t 3654463Smckusic alloccgblk(dev, fs, cgp, bpref) 3664463Smckusic dev_t dev; 3674463Smckusic struct fs *fs; 3684463Smckusic register struct cg *cgp; 3694463Smckusic daddr_t bpref; 3704463Smckusic { 371*4651Smckusic daddr_t bno; 372*4651Smckusic int cylno, pos; 373*4651Smckusic short *cylbp; 374*4651Smckusic int i, j; 3754463Smckusic 376*4651Smckusic if (bpref == 0) { 377*4651Smckusic bpref = cgp->cg_rotor; 378*4651Smckusic } else { 3794463Smckusic bpref &= ~(FRAG - 1); 3804359Smckusick bpref %= fs->fs_fpg; 381*4651Smckusic /* 382*4651Smckusic * if the requested block is available, use it 383*4651Smckusic */ 3844359Smckusick if (isblock(cgp->cg_free, bpref/FRAG)) { 385*4651Smckusic bno = bpref; 3864359Smckusick goto gotit; 3874359Smckusick } 388*4651Smckusic /* 389*4651Smckusic * check for a block available on the same cylinder 390*4651Smckusic * beginning with one which is rotationally optimal 391*4651Smckusic */ 392*4651Smckusic i = bpref * NSPF; 393*4651Smckusic cylno = i / fs->fs_spc; 394*4651Smckusic cylbp = cgp->cg_b[cylno]; 395*4651Smckusic pos = (i + (ROTDELAY == 0) ? 396*4651Smckusic 0 : 1 + ROTDELAY * HZ * fs->fs_nsect / (NSPF * 1000)) % 397*4651Smckusic fs->fs_nsect * NRPOS / fs->fs_nsect; 398*4651Smckusic for (i = pos; i < NRPOS; i++) 399*4651Smckusic if (cylbp[i] > 0) 400*4651Smckusic break; 401*4651Smckusic if (i == NRPOS) 402*4651Smckusic for (i = 0; i < pos; i++) 403*4651Smckusic if (cylbp[i] > 0) 404*4651Smckusic break; 405*4651Smckusic if (cylbp[i] > 0) { 406*4651Smckusic bpref = cylno * fs->fs_spc / (NSPF * FRAG); 407*4651Smckusic for (j = fs->fs_postbl[i]; j > -1; j = fs->fs_rotbl[j]) { 408*4651Smckusic if (isblock(cgp->cg_free, bpref + j)) { 409*4651Smckusic bno = (bpref + j) * FRAG; 410*4651Smckusic goto gotit; 411*4651Smckusic } 412*4651Smckusic } 413*4651Smckusic panic("alloccgblk: can't find blk in cyl"); 414*4651Smckusic } 4154359Smckusick } 416*4651Smckusic bno = mapsearch(fs, cgp, bpref, FRAG); 417*4651Smckusic if (bno == 0) 418*4651Smckusic return (0); 419*4651Smckusic cgp->cg_rotor = bno; 4204359Smckusick gotit: 421*4651Smckusic clrblock(cgp->cg_free, bno/FRAG); 4224463Smckusic cgp->cg_nbfree--; 4234463Smckusic fs->fs_nbfree--; 424*4651Smckusic fs->fs_cs(cgp->cg_cgx).cs_nbfree--; 425*4651Smckusic i = bno * NSPF; 4264463Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--; 4274359Smckusick fs->fs_fmod++; 428*4651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 4294359Smckusick } 4304359Smckusick 4314359Smckusick long 4324359Smckusick ialloccg(dev, fs, cg, ipref, mode) 4334359Smckusick dev_t dev; 4344463Smckusic register struct fs *fs; 4354359Smckusick int cg; 4364359Smckusick daddr_t ipref; 4374359Smckusick int mode; 4384359Smckusick { 4394463Smckusic register struct buf *bp; 4404463Smckusic register struct cg *cgp; 4414359Smckusick int i; 4424359Smckusick 4434426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 4444359Smckusick if (bp->b_flags & B_ERROR) 4454359Smckusick return (0); 4464359Smckusick cgp = bp->b_un.b_cg; 4474359Smckusick if (cgp->cg_nifree == 0) { 4484359Smckusick brelse(bp); 4494359Smckusick return (0); 4504359Smckusick } 4514359Smckusick if (ipref) { 4524359Smckusick ipref %= fs->fs_ipg; 4534359Smckusick if (isclr(cgp->cg_iused, ipref)) 4544359Smckusick goto gotit; 4554359Smckusick } else 4564359Smckusick ipref = cgp->cg_irotor; 4574359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 4584359Smckusick ipref++; 4594359Smckusick if (ipref >= fs->fs_ipg) 4604359Smckusick ipref = 0; 4614359Smckusick if (isclr(cgp->cg_iused, ipref)) { 4624359Smckusick cgp->cg_irotor = ipref; 4634359Smckusick goto gotit; 4644359Smckusick } 4654359Smckusick } 4664359Smckusick brelse(bp); 4674359Smckusick return (0); 4684359Smckusick gotit: 4694359Smckusick setbit(cgp->cg_iused, ipref); 4704359Smckusick cgp->cg_nifree--; 4714359Smckusick fs->fs_nifree--; 472*4651Smckusic fs->fs_cs(cg).cs_nifree--; 4734359Smckusick fs->fs_fmod++; 4744359Smckusick if ((mode & IFMT) == IFDIR) { 4754359Smckusick cgp->cg_ndir++; 476*4651Smckusic fs->fs_cs(cg).cs_ndir++; 4774359Smckusick } 4784359Smckusick bdwrite(bp); 4794359Smckusick return (cg * fs->fs_ipg + ipref); 4804359Smckusick } 4814359Smckusick 4824359Smckusick fre(dev, bno, size) 4834359Smckusick dev_t dev; 4844359Smckusick daddr_t bno; 4854359Smckusick int size; 4864359Smckusick { 4874359Smckusick register struct fs *fs; 4884359Smckusick register struct cg *cgp; 4894359Smckusick register struct buf *bp; 4904463Smckusic int cg, blk, frags, bbase; 4914463Smckusic register int i; 4924359Smckusick 4934426Smckusic if ((unsigned)size > BSIZE || size % FSIZE != 0) 4944426Smckusic panic("free: bad size"); 4954359Smckusick fs = getfs(dev); 4964359Smckusick cg = dtog(bno, fs); 4974359Smckusick if (badblock(fs, bno)) 4984359Smckusick return; 4994426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 5004359Smckusick if (bp->b_flags & B_ERROR) 5014359Smckusick return; 5024359Smckusick cgp = bp->b_un.b_cg; 5034359Smckusick bno %= fs->fs_fpg; 5044426Smckusic if (size == BSIZE) { 5054426Smckusic if (isblock(cgp->cg_free, bno/FRAG)) 5064426Smckusic panic("free: freeing free block"); 5074426Smckusic setblock(cgp->cg_free, bno/FRAG); 5084426Smckusic cgp->cg_nbfree++; 5094426Smckusic fs->fs_nbfree++; 510*4651Smckusic fs->fs_cs(cg).cs_nbfree++; 5114426Smckusic i = bno * NSPF; 5124426Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++; 5134426Smckusic } else { 5144463Smckusic bbase = bno - (bno % FRAG); 5154463Smckusic /* 5164463Smckusic * decrement the counts associated with the old frags 5174463Smckusic */ 5184463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5194463Smckusic (0xff >> (NBBY - FRAG))); 5204463Smckusic fragacct(blk, cgp->cg_frsum, -1); 5214463Smckusic /* 5224463Smckusic * deallocate the fragment 5234463Smckusic */ 5244463Smckusic frags = size / FSIZE; 5254463Smckusic for (i = 0; i < frags; i++) { 5264426Smckusic if (isset(cgp->cg_free, bno + i)) 5274426Smckusic panic("free: freeing free frag"); 5284426Smckusic setbit(cgp->cg_free, bno + i); 5294426Smckusic cgp->cg_nffree++; 5304426Smckusic fs->fs_nffree++; 5314426Smckusic } 5324463Smckusic /* 5334463Smckusic * add back in counts associated with the new frags 5344463Smckusic */ 5354463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5364463Smckusic (0xff >> (NBBY - FRAG))); 5374463Smckusic fragacct(blk, cgp->cg_frsum, 1); 5384463Smckusic /* 5394463Smckusic * if a complete block has been reassembled, account for it 5404463Smckusic */ 5414463Smckusic if (isblock(cgp->cg_free, bbase / FRAG)) { 5424426Smckusic cgp->cg_nffree -= FRAG; 5434426Smckusic fs->fs_nffree -= FRAG; 5444426Smckusic cgp->cg_nbfree++; 5454426Smckusic fs->fs_nbfree++; 546*4651Smckusic fs->fs_cs(cg).cs_nbfree++; 5474463Smckusic i = bbase * NSPF; 5484426Smckusic cgp->cg_b[i / fs->fs_spc] 5494426Smckusic [i % fs->fs_nsect * NRPOS / fs->fs_nsect]++; 5504426Smckusic } 5514426Smckusic } 5524359Smckusick fs->fs_fmod++; 5534359Smckusick bdwrite(bp); 5544359Smckusick } 5554359Smckusick 5564359Smckusick ifree(dev, ino, mode) 5574359Smckusick dev_t dev; 5584359Smckusick ino_t ino; 5594359Smckusick int mode; 5604359Smckusick { 5614359Smckusick register struct fs *fs; 5624359Smckusick register struct cg *cgp; 5634359Smckusick register struct buf *bp; 5644359Smckusick int i; 5654359Smckusick int cg; 5664359Smckusick 5674359Smckusick fs = getfs(dev); 5684359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 5694359Smckusick panic("ifree: range"); 5704359Smckusick cg = itog(ino, fs); 5714426Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 5724359Smckusick if (bp->b_flags & B_ERROR) 5734359Smckusick return; 5744359Smckusick cgp = bp->b_un.b_cg; 5754359Smckusick ino %= fs->fs_ipg; 5764359Smckusick if (isclr(cgp->cg_iused, ino)) 5774359Smckusick panic("ifree: freeing free inode"); 5784359Smckusick clrbit(cgp->cg_iused, ino); 5794359Smckusick cgp->cg_nifree++; 5804359Smckusick fs->fs_nifree++; 581*4651Smckusic fs->fs_cs(cg).cs_nifree++; 5824359Smckusick if ((mode & IFMT) == IFDIR) { 5834359Smckusick cgp->cg_ndir--; 584*4651Smckusic fs->fs_cs(cg).cs_ndir--; 5854359Smckusick } 5864359Smckusick fs->fs_fmod++; 5874359Smckusick bdwrite(bp); 5884359Smckusick } 5894359Smckusick 5904463Smckusic /* 591*4651Smckusic * find a block of the specified size in the specified cylinder group 592*4651Smckusic * It is a panic if a request is made to find a block if none are 593*4651Smckusic * available. 594*4651Smckusic */ 595*4651Smckusic daddr_t 596*4651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 597*4651Smckusic register struct fs *fs; 598*4651Smckusic register struct cg *cgp; 599*4651Smckusic daddr_t bpref; 600*4651Smckusic int allocsiz; 601*4651Smckusic { 602*4651Smckusic daddr_t bno; 603*4651Smckusic int start, len, loc, i; 604*4651Smckusic int blk, field, subfield, pos; 605*4651Smckusic 606*4651Smckusic /* 607*4651Smckusic * find the fragment by searching through the free block 608*4651Smckusic * map for an appropriate bit pattern 609*4651Smckusic */ 610*4651Smckusic if (bpref) 611*4651Smckusic start = bpref % fs->fs_fpg / NBBY; 612*4651Smckusic else 613*4651Smckusic start = cgp->cg_frotor / NBBY; 614*4651Smckusic len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start; 615*4651Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl, 1 << (allocsiz - 1)); 616*4651Smckusic if (loc == 0) { 617*4651Smckusic len = start - 1; 618*4651Smckusic start = (cgdmin(cgp->cg_cgx, fs) - 619*4651Smckusic cgbase(cgp->cg_cgx, fs)) / NBBY; 620*4651Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl, 621*4651Smckusic 1 << (allocsiz - 1)); 622*4651Smckusic if (loc == 0) { 623*4651Smckusic panic("alloccg: map corrupted"); 624*4651Smckusic return (0); 625*4651Smckusic } 626*4651Smckusic } 627*4651Smckusic bno = (start + len - loc) * NBBY; 628*4651Smckusic cgp->cg_frotor = bno; 629*4651Smckusic /* 630*4651Smckusic * found the byte in the map 631*4651Smckusic * sift through the bits to find the selected frag 632*4651Smckusic */ 633*4651Smckusic for (i = 0; i < NBBY; i += FRAG) { 634*4651Smckusic blk = (cgp->cg_free[bno / NBBY] >> i) & (0xff >> NBBY - FRAG); 635*4651Smckusic blk <<= 1; 636*4651Smckusic field = around[allocsiz]; 637*4651Smckusic subfield = inside[allocsiz]; 638*4651Smckusic for (pos = 0; pos <= FRAG - allocsiz; pos++) { 639*4651Smckusic if ((blk & field) == subfield) { 640*4651Smckusic return (bno + i + pos); 641*4651Smckusic } 642*4651Smckusic field <<= 1; 643*4651Smckusic subfield <<= 1; 644*4651Smckusic } 645*4651Smckusic } 646*4651Smckusic panic("alloccg: block not in map"); 647*4651Smckusic return (0); 648*4651Smckusic } 649*4651Smckusic 650*4651Smckusic /* 6514463Smckusic * update the frsum fields to reflect addition or deletion 6524463Smckusic * of some frags 6534463Smckusic */ 6544463Smckusic fragacct(fragmap, fraglist, cnt) 6554472Smckusic int fragmap; 6564463Smckusic short fraglist[]; 6574463Smckusic int cnt; 6584463Smckusic { 6594463Smckusic int inblk; 6604463Smckusic register int field, subfield; 6614463Smckusic register int siz, pos; 6624463Smckusic 6634472Smckusic inblk = (int)(fragtbl[fragmap]) << 1; 6644463Smckusic fragmap <<= 1; 6654463Smckusic for (siz = 1; siz < FRAG; siz++) { 6664463Smckusic if (((1 << siz) & inblk) == 0) 6674463Smckusic continue; 6684463Smckusic field = around[siz]; 6694463Smckusic subfield = inside[siz]; 6704463Smckusic for (pos = siz; pos <= FRAG; pos++) { 6714463Smckusic if ((fragmap & field) == subfield) { 6724463Smckusic fraglist[siz] += cnt; 6734463Smckusic pos += siz; 6744463Smckusic field <<= siz; 6754463Smckusic subfield <<= siz; 6764463Smckusic } 6774463Smckusic field <<= 1; 6784463Smckusic subfield <<= 1; 6794463Smckusic } 6804463Smckusic } 6814463Smckusic } 6824463Smckusic 6834359Smckusick badblock(fs, bn) 6844359Smckusick register struct fs *fs; 6854359Smckusick daddr_t bn; 6864359Smckusick { 6874359Smckusick 6884359Smckusick if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) { 6894359Smckusick fserr(fs, "bad block"); 6904359Smckusick return (1); 6914359Smckusick } 6924359Smckusick return (0); 6934359Smckusick } 6944359Smckusick 6954359Smckusick /* 6964359Smckusick * getfs maps a device number into 6974359Smckusick * a pointer to the incore super 6984359Smckusick * block. The algorithm is a linear 6994359Smckusick * search through the mount table. 7004359Smckusick * A consistency check of the 7014359Smckusick * in core free-block and i-node 7024359Smckusick * counts is performed. 7034359Smckusick * 7044359Smckusick * panic: no fs -- the device is not mounted. 7054359Smckusick * this "cannot happen" 7064359Smckusick */ 7074359Smckusick struct fs * 7084359Smckusick getfs(dev) 7094359Smckusick dev_t dev; 7104359Smckusick { 7114359Smckusick register struct mount *mp; 7124359Smckusick register struct fs *fs; 7134359Smckusick 7144359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7154359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 7164359Smckusick fs = mp->m_bufp->b_un.b_fs; 7174359Smckusick if (fs->fs_magic != FS_MAGIC) 7184359Smckusick panic("getfs: bad magic"); 7194359Smckusick return (fs); 7204359Smckusick } 7214359Smckusick panic("getfs: no fs"); 7224359Smckusick return (NULL); 7234359Smckusick } 7244359Smckusick 7254359Smckusick /* 7264359Smckusick * Fserr prints the name of a file system 7274359Smckusick * with an error diagnostic, in the form 7284359Smckusick * fs: error message 7294359Smckusick */ 7304359Smckusick fserr(fs, cp) 7314359Smckusick struct fs *fs; 7324359Smckusick char *cp; 7334359Smckusick { 7344359Smckusick 7354359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 7364359Smckusick } 7374359Smckusick 7384359Smckusick /* 7394359Smckusick * Getfsx returns the index in the file system 7404359Smckusick * table of the specified device. The swap device 7414359Smckusick * is also assigned a pseudo-index. The index may 7424359Smckusick * be used as a compressed indication of the location 7434359Smckusick * of a block, recording 7444359Smckusick * <getfsx(dev),blkno> 7454359Smckusick * rather than 7464359Smckusick * <dev, blkno> 7474359Smckusick * provided the information need remain valid only 7484359Smckusick * as long as the file system is mounted. 7494359Smckusick */ 7504359Smckusick getfsx(dev) 7514359Smckusick dev_t dev; 7524359Smckusick { 7534359Smckusick register struct mount *mp; 7544359Smckusick 7554359Smckusick if (dev == swapdev) 7564359Smckusick return (MSWAPX); 7574359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7584359Smckusick if (mp->m_dev == dev) 7594359Smckusick return (mp - &mount[0]); 7604359Smckusick return (-1); 7614359Smckusick } 7624359Smckusick 7634359Smckusick /* 7644359Smckusick * Update is the internal name of 'sync'. It goes through the disk 7654359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 7664359Smckusick * modified nodes; and it goes through the mount table to initiate modified 7674359Smckusick * super blocks. 7684359Smckusick */ 7694359Smckusick update() 7704359Smckusick { 7714359Smckusick register struct inode *ip; 7724359Smckusick register struct mount *mp; 7734359Smckusick register struct buf *bp; 7744359Smckusick struct fs *fs; 7754359Smckusick time_t tim; 776*4651Smckusic int i, blks; 7774359Smckusick 7784359Smckusick if (updlock) 7794359Smckusick return; 7804359Smckusick updlock++; 7814359Smckusick /* 7824359Smckusick * Write back modified superblocks. 7834359Smckusick * Consistency check that the superblock 7844359Smckusick * of each file system is still in the buffer cache. 7854359Smckusick */ 7864359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7874359Smckusick if (mp->m_bufp != NULL) { 7884359Smckusick fs = mp->m_bufp->b_un.b_fs; 7894359Smckusick if (fs->fs_fmod == 0) 7904359Smckusick continue; 7914359Smckusick if (fs->fs_ronly != 0) 7924359Smckusick panic("update: rofs mod"); 7934426Smckusic bp = getblk(mp->m_dev, SBLOCK, BSIZE); 7944359Smckusick fs->fs_fmod = 0; 7954359Smckusick fs->fs_time = TIME; 7964359Smckusick if (bp->b_un.b_fs != fs) 7974359Smckusick panic("update: bad b_fs"); 7984359Smckusick bwrite(bp); 799*4651Smckusic blks = howmany(cssize(fs), BSIZE); 800*4651Smckusic for (i = 0; i < blks; i++) { 801*4651Smckusic bp = getblk(mp->m_dev, csaddr(fs) + (i * FRAG), 8024426Smckusic BSIZE); 8034359Smckusick bwrite(bp); 8044359Smckusick } 8054359Smckusick } 8064359Smckusick /* 8074359Smckusick * Write back each (modified) inode. 8084359Smckusick */ 8094359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 8104359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 8114359Smckusick ip->i_flag |= ILOCK; 8124359Smckusick ip->i_count++; 8134359Smckusick tim = TIME; 8144359Smckusick iupdat(ip, &tim, &tim, 0); 8154359Smckusick iput(ip); 8164359Smckusick } 8174359Smckusick updlock = 0; 8184359Smckusick /* 8194359Smckusick * Force stale buffer cache information to be flushed, 8204359Smckusick * for all devices. 8214359Smckusick */ 8224359Smckusick bflush(NODEV); 8234359Smckusick } 824