14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*5361Smckusic static char vers[] = "@(#)lfs_alloc.c 1.13 01/10/82"; 44359Smckusick 54359Smckusick /* alloc.c 4.8 81/03/08 */ 64359Smckusick 74359Smckusick #include "../h/param.h" 84359Smckusick #include "../h/systm.h" 94359Smckusick #include "../h/mount.h" 104359Smckusick #include "../h/fs.h" 114359Smckusick #include "../h/conf.h" 124359Smckusick #include "../h/buf.h" 134359Smckusick #include "../h/inode.h" 144359Smckusick #include "../h/dir.h" 154359Smckusick #include "../h/user.h" 164359Smckusick 175212Smckusic extern u_long hashalloc(); 185212Smckusic extern ino_t ialloccg(); 194651Smckusic extern daddr_t alloccg(); 204651Smckusic extern daddr_t alloccgblk(); 214651Smckusic extern daddr_t fragextend(); 224651Smckusic extern daddr_t blkpref(); 234651Smckusic extern daddr_t mapsearch(); 244607Smckusic extern int inside[], around[]; 255322Smckusic extern unsigned char *fragtbl[]; 264359Smckusick 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 395322Smckusic fs = getfs(dev); 405322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 414463Smckusic panic("alloc: bad size"); 425322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 434359Smckusick goto nospace; 444792Smckusic if (u.u_uid != 0 && 455322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 465322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 474792Smckusic goto nospace; 484948Smckusic if (bpref >= fs->fs_size) 494948Smckusic bpref = 0; 504359Smckusick if (bpref == 0) 514359Smckusick cg = itog(ip->i_number, fs); 524359Smckusick else 534359Smckusick cg = dtog(bpref, fs); 545212Smckusic bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, size, alloccg); 554359Smckusick if (bno == 0) 564359Smckusick goto nospace; 575322Smckusic bp = getblk(dev, fsbtodb(fs, bno), size); 584359Smckusick clrbuf(bp); 594359Smckusick return (bp); 604359Smckusick nospace: 614359Smckusick fserr(fs, "file system full"); 624359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 634359Smckusick u.u_error = ENOSPC; 644359Smckusick return (NULL); 654359Smckusick } 664359Smckusick 674426Smckusic struct buf * 685212Smckusic realloccg(dev, bprev, bpref, osize, nsize) 694426Smckusic dev_t dev; 704651Smckusic daddr_t bprev, bpref; 714426Smckusic int osize, nsize; 724426Smckusic { 734426Smckusic daddr_t bno; 744426Smckusic register struct fs *fs; 754463Smckusic register struct buf *bp, *obp; 764463Smckusic caddr_t cp; 774426Smckusic int cg; 784426Smckusic 795322Smckusic fs = getfs(dev); 805322Smckusic if ((unsigned)osize > fs->fs_bsize || osize % fs->fs_fsize != 0 || 815322Smckusic (unsigned)nsize > fs->fs_bsize || nsize % fs->fs_fsize != 0) 824463Smckusic panic("realloccg: bad size"); 834792Smckusic if (u.u_uid != 0 && 845322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 855322Smckusic fs->fs_dsize * fs->fs_minfree / 100) 864792Smckusic goto nospace; 874463Smckusic if (bprev == 0) 884463Smckusic panic("realloccg: bad bprev"); 894426Smckusic else 904463Smckusic cg = dtog(bprev, fs); 914463Smckusic bno = fragextend(dev, fs, cg, (long)bprev, osize, nsize); 924463Smckusic if (bno != 0) { 935322Smckusic bp = bread(dev, fsbtodb(fs, bno), osize); 94*5361Smckusic if (bp->b_flags & B_ERROR) 95*5361Smckusic return (0); 964463Smckusic bp->b_bcount = nsize; 974463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 984463Smckusic return (bp); 994463Smckusic } 1004948Smckusic if (bpref >= fs->fs_size) 1014948Smckusic bpref = 0; 1025212Smckusic bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg); 1034463Smckusic if (bno != 0) { 1044463Smckusic /* 1054463Smckusic * make a new copy 1064463Smckusic */ 1075322Smckusic obp = bread(dev, fsbtodb(fs, bprev), osize); 108*5361Smckusic if (obp->b_flags & B_ERROR) 109*5361Smckusic return (0); 1105322Smckusic bp = getblk(dev, fsbtodb(fs, bno), nsize); 1114463Smckusic cp = bp->b_un.b_addr; 1124463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1134463Smckusic obp->b_un.b_addr = cp; 1144463Smckusic obp->b_flags |= B_INVAL; 1154463Smckusic brelse(obp); 1165212Smckusic fre(dev, bprev, (off_t)osize); 1174463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1184463Smckusic return(bp); 1194463Smckusic } 1204792Smckusic nospace: 1214463Smckusic /* 1224463Smckusic * no space available 1234463Smckusic */ 1244426Smckusic fserr(fs, "file system full"); 1254426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1264426Smckusic u.u_error = ENOSPC; 1274426Smckusic return (NULL); 1284426Smckusic } 1294426Smckusic 1304359Smckusick struct inode * 1314359Smckusick ialloc(dev, ipref, mode) 1324359Smckusick dev_t dev; 1334359Smckusick ino_t ipref; 1344359Smckusick int mode; 1354359Smckusick { 1365212Smckusic ino_t ino; 1374359Smckusick register struct fs *fs; 1384359Smckusick register struct inode *ip; 1394359Smckusick int cg; 1404359Smckusick 1414359Smckusick fs = getfs(dev); 1424792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1434359Smckusick goto noinodes; 1444948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 1454948Smckusic ipref = 0; 1464359Smckusick cg = itog(ipref, fs); 1475212Smckusic ino = (ino_t)hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 1484359Smckusick if (ino == 0) 1494359Smckusick goto noinodes; 1504359Smckusick ip = iget(dev, ino); 1514359Smckusick if (ip == NULL) { 1525212Smckusic ifree(dev, ino, 0); 1534359Smckusick return (NULL); 1544359Smckusick } 1554359Smckusick if (ip->i_mode) 1564359Smckusick panic("ialloc: dup alloc"); 1574359Smckusick return (ip); 1584359Smckusick noinodes: 1594359Smckusick fserr(fs, "out of inodes"); 1604359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 1614359Smckusick u.u_error = ENOSPC; 1624359Smckusick return (NULL); 1634359Smckusick } 1644359Smckusick 1654651Smckusic /* 1664651Smckusic * find a cylinder to place a directory 1674651Smckusic */ 1684651Smckusic dirpref(dev) 1694359Smckusick dev_t dev; 1704359Smckusick { 1714359Smckusick register struct fs *fs; 1724651Smckusic int cg, minndir, mincg, avgifree; 1734359Smckusick 1744359Smckusick fs = getfs(dev); 1754792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 1764651Smckusic minndir = fs->fs_ipg; 1774359Smckusick mincg = 0; 1784651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 1795322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 1805322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 1814359Smckusick mincg = cg; 1825322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 1834359Smckusick } 1844359Smckusick return (fs->fs_ipg * mincg); 1854359Smckusick } 1864359Smckusick 1874651Smckusic /* 1884651Smckusic * select a cylinder to place a large block of data 1894651Smckusic */ 1905212Smckusic daddr_t 1914651Smckusic blkpref(dev) 1924651Smckusic dev_t dev; 1934651Smckusic { 1944651Smckusic register struct fs *fs; 1954651Smckusic int cg, avgbfree; 1964651Smckusic 1974651Smckusic fs = getfs(dev); 1984792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 1994651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 2005322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2014651Smckusic fs->fs_cgrotor = cg; 2025322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2034651Smckusic } 2044651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 2055322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2064651Smckusic fs->fs_cgrotor = cg; 2075322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2084651Smckusic } 2094651Smckusic return (0); 2104651Smckusic } 2114651Smckusic 2125212Smckusic /*VARARGS5*/ 2135212Smckusic u_long 2144359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 2154359Smckusick dev_t dev; 2164359Smckusick register struct fs *fs; 2174359Smckusick int cg; 2184359Smckusick long pref; 2194359Smckusick int size; /* size for data blocks, mode for inodes */ 2205212Smckusic u_long (*allocator)(); 2214359Smckusick { 2224359Smckusick long result; 2234359Smckusick int i, icg = cg; 2244359Smckusick 2254359Smckusick /* 2264359Smckusick * 1: preferred cylinder group 2274359Smckusick */ 2284359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 2294359Smckusick if (result) 2304359Smckusick return (result); 2314359Smckusick /* 2324359Smckusick * 2: quadratic rehash 2334359Smckusick */ 2344359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2354359Smckusick cg += i; 2364359Smckusick if (cg >= fs->fs_ncg) 2374359Smckusick cg -= fs->fs_ncg; 2384359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2394359Smckusick if (result) 2404359Smckusick return (result); 2414359Smckusick } 2424359Smckusick /* 2434359Smckusick * 3: brute force search 2444359Smckusick */ 2454359Smckusick cg = icg; 2464359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 2474359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2484359Smckusick if (result) 2494359Smckusick return (result); 2504359Smckusick cg++; 2514359Smckusick if (cg == fs->fs_ncg) 2524359Smckusick cg = 0; 2534359Smckusick } 2544359Smckusick return (0); 2554359Smckusick } 2564359Smckusick 2574359Smckusick daddr_t 2584463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize) 2594426Smckusic dev_t dev; 2604426Smckusic register struct fs *fs; 2614426Smckusic int cg; 2624463Smckusic long bprev; 2634426Smckusic int osize, nsize; 2644426Smckusic { 2654463Smckusic register struct buf *bp; 2664463Smckusic register struct cg *cgp; 2674463Smckusic long bno; 2684463Smckusic int frags, bbase; 2694426Smckusic int i; 2704426Smckusic 2715322Smckusic frags = nsize / fs->fs_fsize; 2725322Smckusic bbase = bprev % fs->fs_frag; 2735322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 2744463Smckusic /* cannot extend across a block boundry */ 2754463Smckusic return (0); 2764463Smckusic } 2775322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 2784426Smckusic if (bp->b_flags & B_ERROR) 2794426Smckusic return (0); 2804426Smckusic cgp = bp->b_un.b_cg; 2814463Smckusic bno = bprev % fs->fs_fpg; 282*5361Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) 283*5361Smckusic if (isclr(cgp->cg_free, bno + i)) { 284*5361Smckusic brelse(bp); 285*5361Smckusic return (0); 286*5361Smckusic } 287*5361Smckusic /* 288*5361Smckusic * the current fragment can be extended 289*5361Smckusic * deduct the count on fragment being extended into 290*5361Smckusic * increase the count on the remaining fragment (if any) 291*5361Smckusic * allocate the extended piece 292*5361Smckusic */ 293*5361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 2944463Smckusic if (isclr(cgp->cg_free, bno + i)) 2954463Smckusic break; 296*5361Smckusic cgp->cg_frsum[i - osize / fs->fs_fsize]--; 297*5361Smckusic if (i != frags) 298*5361Smckusic cgp->cg_frsum[i - frags]++; 299*5361Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) { 300*5361Smckusic clrbit(cgp->cg_free, bno + i); 301*5361Smckusic cgp->cg_cs.cs_nffree--; 302*5361Smckusic fs->fs_cstotal.cs_nffree--; 303*5361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3044463Smckusic } 305*5361Smckusic fs->fs_fmod++; 306*5361Smckusic bdwrite(bp); 307*5361Smckusic return (bprev); 3084426Smckusic } 3094426Smckusic 3104426Smckusic daddr_t 3114359Smckusick alloccg(dev, fs, cg, bpref, size) 3124359Smckusick dev_t dev; 3134463Smckusic register struct fs *fs; 3144359Smckusick int cg; 3154359Smckusick daddr_t bpref; 3164359Smckusick int size; 3174359Smckusick { 3184463Smckusic register struct buf *bp; 3194463Smckusic register struct cg *cgp; 3204463Smckusic int bno, frags; 3214463Smckusic int allocsiz; 3224463Smckusic register int i; 3234359Smckusick 3245322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 3254792Smckusic return (0); 3265322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 3274359Smckusick if (bp->b_flags & B_ERROR) 3284359Smckusick return (0); 3294359Smckusick cgp = bp->b_un.b_cg; 3305322Smckusic if (size == fs->fs_bsize) { 3315212Smckusic bno = alloccgblk(fs, cgp, bpref); 3324463Smckusic bdwrite(bp); 3334463Smckusic return (bno); 3344463Smckusic } 3354463Smckusic /* 3364463Smckusic * check to see if any fragments are already available 3374463Smckusic * allocsiz is the size which will be allocated, hacking 3384463Smckusic * it down to a smaller size if necessary 3394463Smckusic */ 3405322Smckusic frags = size / fs->fs_fsize; 3415322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 3424463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 3434463Smckusic break; 3445322Smckusic if (allocsiz == fs->fs_frag) { 3454463Smckusic /* 3464463Smckusic * no fragments were available, so a block will be 3474463Smckusic * allocated, and hacked up 3484463Smckusic */ 3494792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 3504463Smckusic brelse(bp); 3514463Smckusic return (0); 3524463Smckusic } 3535212Smckusic bno = alloccgblk(fs, cgp, bpref); 3544463Smckusic bpref = bno % fs->fs_fpg; 3555322Smckusic for (i = frags; i < fs->fs_frag; i++) 3564463Smckusic setbit(cgp->cg_free, bpref + i); 3575322Smckusic i = fs->fs_frag - frags; 3584792Smckusic cgp->cg_cs.cs_nffree += i; 3594792Smckusic fs->fs_cstotal.cs_nffree += i; 3605322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 3614463Smckusic cgp->cg_frsum[i]++; 3624463Smckusic bdwrite(bp); 3634463Smckusic return (bno); 3644463Smckusic } 3654651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 3664651Smckusic if (bno == 0) 3674651Smckusic return (0); 3684463Smckusic for (i = 0; i < frags; i++) 3694463Smckusic clrbit(cgp->cg_free, bno + i); 3704792Smckusic cgp->cg_cs.cs_nffree -= frags; 3714792Smckusic fs->fs_cstotal.cs_nffree -= frags; 3725322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 3734463Smckusic cgp->cg_frsum[allocsiz]--; 3744463Smckusic if (frags != allocsiz) 3754463Smckusic cgp->cg_frsum[allocsiz - frags]++; 3764463Smckusic bdwrite(bp); 3774463Smckusic return (cg * fs->fs_fpg + bno); 3784463Smckusic } 3794463Smckusic 3804463Smckusic daddr_t 3815212Smckusic alloccgblk(fs, cgp, bpref) 3824463Smckusic struct fs *fs; 3834463Smckusic register struct cg *cgp; 3844463Smckusic daddr_t bpref; 3854463Smckusic { 3864651Smckusic daddr_t bno; 3874651Smckusic int cylno, pos; 3884651Smckusic short *cylbp; 389*5361Smckusic register int i; 3904463Smckusic 3914651Smckusic if (bpref == 0) { 3924651Smckusic bpref = cgp->cg_rotor; 393*5361Smckusic goto norot; 394*5361Smckusic } 395*5361Smckusic bpref &= ~(fs->fs_frag - 1); 396*5361Smckusic bpref %= fs->fs_fpg; 397*5361Smckusic /* 398*5361Smckusic * if the requested block is available, use it 399*5361Smckusic */ 400*5361Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 401*5361Smckusic bno = bpref; 402*5361Smckusic goto gotit; 403*5361Smckusic } 404*5361Smckusic if (fs->fs_cpc == 0) 405*5361Smckusic goto norot; 406*5361Smckusic /* 407*5361Smckusic * check for a block available on the same cylinder 408*5361Smckusic * beginning with one which is rotationally optimal 409*5361Smckusic */ 410*5361Smckusic cylno = cbtocylno(fs, bpref); 411*5361Smckusic cylbp = cgp->cg_b[cylno]; 412*5361Smckusic if (fs->fs_rotdelay == 0) { 413*5361Smckusic pos = cbtorpos(fs, bpref); 4144651Smckusic } else { 4154651Smckusic /* 416*5361Smckusic * here we convert ms of delay to frags as: 417*5361Smckusic * (frags) = (ms) * (rev/sec) * (sect/rev) / 418*5361Smckusic * ((sect/frag) * (ms/sec)) 419*5361Smckusic * then round up to the next rotational position 4204651Smckusic */ 421*5361Smckusic bpref += fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 422*5361Smckusic (NSPF(fs) * 1000); 423*5361Smckusic pos = cbtorpos(fs, bpref); 424*5361Smckusic pos = (pos + 1) % NRPOS; 425*5361Smckusic } 426*5361Smckusic /* 427*5361Smckusic * check the summary information to see if a block is 428*5361Smckusic * available in the requested cylinder starting at the 429*5361Smckusic * optimal rotational position and proceeding around. 430*5361Smckusic */ 431*5361Smckusic for (i = pos; i < NRPOS; i++) 432*5361Smckusic if (cylbp[i] > 0) 433*5361Smckusic break; 434*5361Smckusic if (i == NRPOS) 435*5361Smckusic for (i = 0; i < pos; i++) 436*5361Smckusic if (cylbp[i] > 0) 437*5361Smckusic break; 438*5361Smckusic if (cylbp[i] > 0) { 4394651Smckusic /* 440*5361Smckusic * found a rotational position, now find the actual 441*5361Smckusic * block. A panic if none is actually there. 4424651Smckusic */ 443*5361Smckusic pos = cylno % fs->fs_cpc; 444*5361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 445*5361Smckusic if (fs->fs_postbl[pos][i] == -1) 446*5361Smckusic panic("alloccgblk: cyl groups corrupted"); 447*5361Smckusic for (i = fs->fs_postbl[pos][i]; ; i += fs->fs_rotbl[i]) { 448*5361Smckusic if (isblock(fs, cgp->cg_free, bno + i)) { 449*5361Smckusic bno = (bno + i) * fs->fs_frag; 450*5361Smckusic goto gotit; 451*5361Smckusic } 452*5361Smckusic if (fs->fs_rotbl[i] == 0) 4534651Smckusic break; 4544651Smckusic } 455*5361Smckusic panic("alloccgblk: can't find blk in cyl"); 4564359Smckusick } 457*5361Smckusic norot: 458*5361Smckusic /* 459*5361Smckusic * no blocks in the requested cylinder, so take next 460*5361Smckusic * available one in this cylinder group. 461*5361Smckusic */ 4625322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 4634651Smckusic if (bno == 0) 4644651Smckusic return (0); 4654651Smckusic cgp->cg_rotor = bno; 4664359Smckusick gotit: 4675322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 4684792Smckusic cgp->cg_cs.cs_nbfree--; 4694792Smckusic fs->fs_cstotal.cs_nbfree--; 4705322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 471*5361Smckusic cgp->cg_b[cbtocylno(fs, bno)][cbtorpos(fs, bno)]--; 4724359Smckusick fs->fs_fmod++; 4734651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 4744359Smckusick } 4754359Smckusick 4765212Smckusic ino_t 4774359Smckusick ialloccg(dev, fs, cg, ipref, mode) 4784359Smckusick dev_t dev; 4794463Smckusic register struct fs *fs; 4804359Smckusick int cg; 4814359Smckusick daddr_t ipref; 4824359Smckusick int mode; 4834359Smckusick { 4844463Smckusic register struct buf *bp; 4854463Smckusic register struct cg *cgp; 4864359Smckusick int i; 4874359Smckusick 4885322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 4894792Smckusic return (0); 4905322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 4914359Smckusick if (bp->b_flags & B_ERROR) 4924359Smckusick return (0); 4934359Smckusick cgp = bp->b_un.b_cg; 4944359Smckusick if (ipref) { 4954359Smckusick ipref %= fs->fs_ipg; 4964359Smckusick if (isclr(cgp->cg_iused, ipref)) 4974359Smckusick goto gotit; 4984359Smckusick } else 4994359Smckusick ipref = cgp->cg_irotor; 5004359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 5014359Smckusick ipref++; 5024359Smckusick if (ipref >= fs->fs_ipg) 5034359Smckusick ipref = 0; 5044359Smckusick if (isclr(cgp->cg_iused, ipref)) { 5054359Smckusick cgp->cg_irotor = ipref; 5064359Smckusick goto gotit; 5074359Smckusick } 5084359Smckusick } 5094359Smckusick brelse(bp); 5104359Smckusick return (0); 5114359Smckusick gotit: 5124359Smckusick setbit(cgp->cg_iused, ipref); 5134792Smckusic cgp->cg_cs.cs_nifree--; 5144792Smckusic fs->fs_cstotal.cs_nifree--; 5155322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 5164359Smckusick fs->fs_fmod++; 5174359Smckusick if ((mode & IFMT) == IFDIR) { 5184792Smckusic cgp->cg_cs.cs_ndir++; 5194792Smckusic fs->fs_cstotal.cs_ndir++; 5205322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 5214359Smckusick } 5224359Smckusick bdwrite(bp); 5234359Smckusick return (cg * fs->fs_ipg + ipref); 5244359Smckusick } 5254359Smckusick 5264359Smckusick fre(dev, bno, size) 5274359Smckusick dev_t dev; 5284359Smckusick daddr_t bno; 5295212Smckusic off_t size; 5304359Smckusick { 5314359Smckusick register struct fs *fs; 5324359Smckusick register struct cg *cgp; 5334359Smckusick register struct buf *bp; 5344463Smckusic int cg, blk, frags, bbase; 5354463Smckusic register int i; 5364359Smckusick 5375322Smckusic fs = getfs(dev); 5385322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 5394426Smckusic panic("free: bad size"); 5404359Smckusick cg = dtog(bno, fs); 5414359Smckusick if (badblock(fs, bno)) 5424359Smckusick return; 5435322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 5444359Smckusick if (bp->b_flags & B_ERROR) 5454359Smckusick return; 5464359Smckusick cgp = bp->b_un.b_cg; 5474359Smckusick bno %= fs->fs_fpg; 5485322Smckusic if (size == fs->fs_bsize) { 5495322Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) 5504426Smckusic panic("free: freeing free block"); 5515322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 5524792Smckusic cgp->cg_cs.cs_nbfree++; 5534792Smckusic fs->fs_cstotal.cs_nbfree++; 5545322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 555*5361Smckusic cgp->cg_b[cbtocylno(fs, bno)][cbtorpos(fs, bno)]++; 5564426Smckusic } else { 5575322Smckusic bbase = bno - (bno % fs->fs_frag); 5584463Smckusic /* 5594463Smckusic * decrement the counts associated with the old frags 5604463Smckusic */ 5614463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5625322Smckusic (0xff >> (NBBY - fs->fs_frag))); 5635322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 5644463Smckusic /* 5654463Smckusic * deallocate the fragment 5664463Smckusic */ 5675322Smckusic frags = size / fs->fs_fsize; 5684463Smckusic for (i = 0; i < frags; i++) { 5694426Smckusic if (isset(cgp->cg_free, bno + i)) 5704426Smckusic panic("free: freeing free frag"); 5714426Smckusic setbit(cgp->cg_free, bno + i); 5724792Smckusic cgp->cg_cs.cs_nffree++; 5734792Smckusic fs->fs_cstotal.cs_nffree++; 5745322Smckusic fs->fs_cs(fs, cg).cs_nffree++; 5754426Smckusic } 5764463Smckusic /* 5774463Smckusic * add back in counts associated with the new frags 5784463Smckusic */ 5794463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 5805322Smckusic (0xff >> (NBBY - fs->fs_frag))); 5815322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 5824463Smckusic /* 5834463Smckusic * if a complete block has been reassembled, account for it 5844463Smckusic */ 5855322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 5865322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 5875322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 5885322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 5894792Smckusic cgp->cg_cs.cs_nbfree++; 5904792Smckusic fs->fs_cstotal.cs_nbfree++; 5915322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 592*5361Smckusic cgp->cg_b[cbtocylno(fs, bbase)][cbtorpos(fs, bbase)]++; 5934426Smckusic } 5944426Smckusic } 5954359Smckusick fs->fs_fmod++; 5964359Smckusick bdwrite(bp); 5974359Smckusick } 5984359Smckusick 5994359Smckusick ifree(dev, ino, mode) 6004359Smckusick dev_t dev; 6014359Smckusick ino_t ino; 6024359Smckusick int mode; 6034359Smckusick { 6044359Smckusick register struct fs *fs; 6054359Smckusick register struct cg *cgp; 6064359Smckusick register struct buf *bp; 6074359Smckusick int cg; 6084359Smckusick 6094359Smckusick fs = getfs(dev); 6104359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 6114359Smckusick panic("ifree: range"); 6124359Smckusick cg = itog(ino, fs); 6135322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 6144359Smckusick if (bp->b_flags & B_ERROR) 6154359Smckusick return; 6164359Smckusick cgp = bp->b_un.b_cg; 6174359Smckusick ino %= fs->fs_ipg; 6184359Smckusick if (isclr(cgp->cg_iused, ino)) 6194359Smckusick panic("ifree: freeing free inode"); 6204359Smckusick clrbit(cgp->cg_iused, ino); 6214792Smckusic cgp->cg_cs.cs_nifree++; 6224792Smckusic fs->fs_cstotal.cs_nifree++; 6235322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 6244359Smckusick if ((mode & IFMT) == IFDIR) { 6254792Smckusic cgp->cg_cs.cs_ndir--; 6264792Smckusic fs->fs_cstotal.cs_ndir--; 6275322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 6284359Smckusick } 6294359Smckusick fs->fs_fmod++; 6304359Smckusick bdwrite(bp); 6314359Smckusick } 6324359Smckusick 6334463Smckusic /* 6344651Smckusic * find a block of the specified size in the specified cylinder group 6354651Smckusic * It is a panic if a request is made to find a block if none are 6364651Smckusic * available. 6374651Smckusic */ 6384651Smckusic daddr_t 6394651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 6404651Smckusic register struct fs *fs; 6414651Smckusic register struct cg *cgp; 6424651Smckusic daddr_t bpref; 6434651Smckusic int allocsiz; 6444651Smckusic { 6454651Smckusic daddr_t bno; 6464651Smckusic int start, len, loc, i; 6474651Smckusic int blk, field, subfield, pos; 6484651Smckusic 6494651Smckusic /* 6504651Smckusic * find the fragment by searching through the free block 6514651Smckusic * map for an appropriate bit pattern 6524651Smckusic */ 6534651Smckusic if (bpref) 6544651Smckusic start = bpref % fs->fs_fpg / NBBY; 6554651Smckusic else 6564651Smckusic start = cgp->cg_frotor / NBBY; 6574651Smckusic len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start; 6585322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 6595322Smckusic 1 << (allocsiz - 1)); 6604651Smckusic if (loc == 0) { 6614651Smckusic len = start - 1; 6624651Smckusic start = (cgdmin(cgp->cg_cgx, fs) - 6634651Smckusic cgbase(cgp->cg_cgx, fs)) / NBBY; 6645322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 6654651Smckusic 1 << (allocsiz - 1)); 6664651Smckusic if (loc == 0) { 6674651Smckusic panic("alloccg: map corrupted"); 6684651Smckusic return (0); 6694651Smckusic } 6704651Smckusic } 6714651Smckusic bno = (start + len - loc) * NBBY; 6724651Smckusic cgp->cg_frotor = bno; 6734651Smckusic /* 6744651Smckusic * found the byte in the map 6754651Smckusic * sift through the bits to find the selected frag 6764651Smckusic */ 6775322Smckusic for (i = 0; i < NBBY; i += fs->fs_frag) { 6785322Smckusic blk = (cgp->cg_free[bno / NBBY] >> i) & 6795322Smckusic (0xff >> NBBY - fs->fs_frag); 6804651Smckusic blk <<= 1; 6814651Smckusic field = around[allocsiz]; 6824651Smckusic subfield = inside[allocsiz]; 6835322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 6844651Smckusic if ((blk & field) == subfield) { 6854651Smckusic return (bno + i + pos); 6864651Smckusic } 6874651Smckusic field <<= 1; 6884651Smckusic subfield <<= 1; 6894651Smckusic } 6904651Smckusic } 6914651Smckusic panic("alloccg: block not in map"); 6924651Smckusic return (0); 6934651Smckusic } 6944651Smckusic 6954651Smckusic /* 6964463Smckusic * update the frsum fields to reflect addition or deletion 6974463Smckusic * of some frags 6984463Smckusic */ 6995322Smckusic fragacct(fs, fragmap, fraglist, cnt) 7005322Smckusic struct fs *fs; 7014472Smckusic int fragmap; 7024792Smckusic long fraglist[]; 7034463Smckusic int cnt; 7044463Smckusic { 7054463Smckusic int inblk; 7064463Smckusic register int field, subfield; 7074463Smckusic register int siz, pos; 7084463Smckusic 7095322Smckusic inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 7104463Smckusic fragmap <<= 1; 7115322Smckusic for (siz = 1; siz < fs->fs_frag; siz++) { 7124463Smckusic if (((1 << siz) & inblk) == 0) 7134463Smckusic continue; 7144463Smckusic field = around[siz]; 7154463Smckusic subfield = inside[siz]; 7165322Smckusic for (pos = siz; pos <= fs->fs_frag; pos++) { 7174463Smckusic if ((fragmap & field) == subfield) { 7184463Smckusic fraglist[siz] += cnt; 7194463Smckusic pos += siz; 7204463Smckusic field <<= siz; 7214463Smckusic subfield <<= siz; 7224463Smckusic } 7234463Smckusic field <<= 1; 7244463Smckusic subfield <<= 1; 7254463Smckusic } 7264463Smckusic } 7274463Smckusic } 7284463Smckusic 7294359Smckusick badblock(fs, bn) 7304359Smckusick register struct fs *fs; 7314359Smckusick daddr_t bn; 7324359Smckusick { 7334359Smckusick 7344359Smckusick if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) { 7354359Smckusick fserr(fs, "bad block"); 7364359Smckusick return (1); 7374359Smckusick } 7384359Smckusick return (0); 7394359Smckusick } 7404359Smckusick 7414359Smckusick /* 7424359Smckusick * getfs maps a device number into 7434359Smckusick * a pointer to the incore super 7444359Smckusick * block. The algorithm is a linear 7454359Smckusick * search through the mount table. 7464359Smckusick * A consistency check of the 7474359Smckusick * in core free-block and i-node 7484359Smckusick * counts is performed. 7494359Smckusick * 7504359Smckusick * panic: no fs -- the device is not mounted. 7514359Smckusick * this "cannot happen" 7524359Smckusick */ 7534359Smckusick struct fs * 7544359Smckusick getfs(dev) 7554359Smckusick dev_t dev; 7564359Smckusick { 7574359Smckusick register struct mount *mp; 7584359Smckusick register struct fs *fs; 7594359Smckusick 7604359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7614359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 7624359Smckusick fs = mp->m_bufp->b_un.b_fs; 7634359Smckusick if (fs->fs_magic != FS_MAGIC) 7644359Smckusick panic("getfs: bad magic"); 7654359Smckusick return (fs); 7664359Smckusick } 7674359Smckusick panic("getfs: no fs"); 7684359Smckusick return (NULL); 7694359Smckusick } 7704359Smckusick 7714359Smckusick /* 7724359Smckusick * Fserr prints the name of a file system 7734359Smckusick * with an error diagnostic, in the form 7744359Smckusick * fs: error message 7754359Smckusick */ 7764359Smckusick fserr(fs, cp) 7774359Smckusick struct fs *fs; 7784359Smckusick char *cp; 7794359Smckusick { 7804359Smckusick 7814359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 7824359Smckusick } 7834359Smckusick 7844359Smckusick /* 7854359Smckusick * Getfsx returns the index in the file system 7864359Smckusick * table of the specified device. The swap device 7874359Smckusick * is also assigned a pseudo-index. The index may 7884359Smckusick * be used as a compressed indication of the location 7894359Smckusick * of a block, recording 7904359Smckusick * <getfsx(dev),blkno> 7914359Smckusick * rather than 7924359Smckusick * <dev, blkno> 7934359Smckusick * provided the information need remain valid only 7944359Smckusick * as long as the file system is mounted. 7954359Smckusick */ 7964359Smckusick getfsx(dev) 7974359Smckusick dev_t dev; 7984359Smckusick { 7994359Smckusick register struct mount *mp; 8004359Smckusick 8014359Smckusick if (dev == swapdev) 8024359Smckusick return (MSWAPX); 8034359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8044359Smckusick if (mp->m_dev == dev) 8054359Smckusick return (mp - &mount[0]); 8064359Smckusick return (-1); 8074359Smckusick } 8084359Smckusick 8094359Smckusick /* 8104359Smckusick * Update is the internal name of 'sync'. It goes through the disk 8114359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 8124359Smckusick * modified nodes; and it goes through the mount table to initiate modified 8134359Smckusick * super blocks. 8144359Smckusick */ 8154359Smckusick update() 8164359Smckusick { 8174359Smckusick register struct inode *ip; 8184359Smckusick register struct mount *mp; 8194359Smckusick register struct buf *bp; 8204359Smckusick struct fs *fs; 8214359Smckusick time_t tim; 8224651Smckusic int i, blks; 8234359Smckusick 8244359Smckusick if (updlock) 8254359Smckusick return; 8264359Smckusick updlock++; 8274359Smckusick /* 8284359Smckusick * Write back modified superblocks. 8294359Smckusick * Consistency check that the superblock 8304359Smckusick * of each file system is still in the buffer cache. 8314359Smckusick */ 8324359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8334359Smckusick if (mp->m_bufp != NULL) { 8344359Smckusick fs = mp->m_bufp->b_un.b_fs; 8354359Smckusick if (fs->fs_fmod == 0) 8364359Smckusick continue; 8374359Smckusick if (fs->fs_ronly != 0) 8384359Smckusick panic("update: rofs mod"); 8395344Smckusic bp = getblk(mp->m_dev, SBLOCK, SBSIZE); 8404359Smckusick fs->fs_fmod = 0; 8414359Smckusick fs->fs_time = TIME; 8424359Smckusick if (bp->b_un.b_fs != fs) 8434359Smckusick panic("update: bad b_fs"); 8444359Smckusick bwrite(bp); 8455322Smckusic blks = howmany(fs->fs_cssize, fs->fs_bsize); 8464651Smckusic for (i = 0; i < blks; i++) { 8475322Smckusic bp = getblk(mp->m_dev, 8485322Smckusic fsbtodb(fs, fs->fs_csaddr + (i * fs->fs_frag)), 8495322Smckusic fs->fs_bsize); 8504359Smckusick bwrite(bp); 8514359Smckusick } 8524359Smckusick } 8534359Smckusick /* 8544359Smckusick * Write back each (modified) inode. 8554359Smckusick */ 8564359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 8574359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 8584359Smckusick ip->i_flag |= ILOCK; 8594359Smckusick ip->i_count++; 8604359Smckusick tim = TIME; 8614359Smckusick iupdat(ip, &tim, &tim, 0); 8624359Smckusick iput(ip); 8634359Smckusick } 8644359Smckusick updlock = 0; 8654359Smckusick /* 8664359Smckusick * Force stale buffer cache information to be flushed, 8674359Smckusick * for all devices. 8684359Smckusick */ 8694359Smckusick bflush(NODEV); 8704359Smckusick } 8715322Smckusic 8725322Smckusic /* 8735322Smckusic * block macros 8745322Smckusic */ 8755322Smckusic 8765322Smckusic isblock(fs, cp, h) 8775322Smckusic struct fs *fs; 8785322Smckusic unsigned char *cp; 8795322Smckusic int h; 8805322Smckusic { 8815322Smckusic unsigned char mask; 8825322Smckusic 8835322Smckusic switch (fs->fs_frag) { 8845322Smckusic case 8: 8855322Smckusic return (cp[h] == 0xff); 8865322Smckusic case 4: 8875322Smckusic mask = 0x0f << ((h & 0x1) << 2); 8885322Smckusic return ((cp[h >> 1] & mask) == mask); 8895322Smckusic case 2: 8905322Smckusic mask = 0x03 << ((h & 0x3) << 1); 8915322Smckusic return ((cp[h >> 2] & mask) == mask); 8925322Smckusic case 1: 8935322Smckusic mask = 0x01 << (h & 0x7); 8945322Smckusic return ((cp[h >> 3] & mask) == mask); 8955322Smckusic default: 8965322Smckusic panic("isblock bad fs_frag"); 8975322Smckusic return; 8985322Smckusic } 8995322Smckusic } 9005322Smckusic clrblock(fs, cp, h) 9015322Smckusic struct fs *fs; 9025322Smckusic unsigned char *cp; 9035322Smckusic int h; 9045322Smckusic { 9055322Smckusic switch ((fs)->fs_frag) { 9065322Smckusic case 8: 9075322Smckusic cp[h] = 0; 9085322Smckusic return; 9095322Smckusic case 4: 9105322Smckusic cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 9115322Smckusic return; 9125322Smckusic case 2: 9135322Smckusic cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 9145322Smckusic return; 9155322Smckusic case 1: 9165322Smckusic cp[h >> 3] &= ~(0x01 << (h & 0x7)); 9175322Smckusic return; 9185322Smckusic default: 9195322Smckusic panic("clrblock bad fs_frag"); 9205322Smckusic return; 9215322Smckusic } 9225322Smckusic } 9235322Smckusic setblock(fs, cp, h) 9245322Smckusic struct fs *fs; 9255322Smckusic unsigned char *cp; 9265322Smckusic int h; 9275322Smckusic { 9285322Smckusic switch (fs->fs_frag) { 9295322Smckusic case 8: 9305322Smckusic cp[h] = 0xff; 9315322Smckusic return; 9325322Smckusic case 4: 9335322Smckusic cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 9345322Smckusic return; 9355322Smckusic case 2: 9365322Smckusic cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 9375322Smckusic return; 9385322Smckusic case 1: 9395322Smckusic cp[h >> 3] |= (0x01 << (h & 0x7)); 9405322Smckusic return; 9415322Smckusic default: 9425322Smckusic panic("setblock bad fs_frag"); 9435322Smckusic return; 9445322Smckusic } 9455322Smckusic } 946