14359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24359Smckusick 3*5322Smckusic static char vers[] = "@(#)lfs_alloc.c 1.11 01/05/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[]; 25*5322Smckusic 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 39*5322Smckusic fs = getfs(dev); 40*5322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 414463Smckusic panic("alloc: bad size"); 42*5322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 434359Smckusick goto nospace; 444792Smckusic if (u.u_uid != 0 && 45*5322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 46*5322Smckusic 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; 57*5322Smckusic 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 79*5322Smckusic fs = getfs(dev); 80*5322Smckusic if ((unsigned)osize > fs->fs_bsize || osize % fs->fs_fsize != 0 || 81*5322Smckusic (unsigned)nsize > fs->fs_bsize || nsize % fs->fs_fsize != 0) 824463Smckusic panic("realloccg: bad size"); 834792Smckusic if (u.u_uid != 0 && 84*5322Smckusic fs->fs_cstotal.cs_nbfree * fs->fs_frag + fs->fs_cstotal.cs_nffree < 85*5322Smckusic 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) { 93*5322Smckusic bp = bread(dev, fsbtodb(fs, bno), osize); 944463Smckusic bp->b_bcount = nsize; 954463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 964463Smckusic return (bp); 974463Smckusic } 984948Smckusic if (bpref >= fs->fs_size) 994948Smckusic bpref = 0; 1005212Smckusic bno = (daddr_t)hashalloc(dev, fs, cg, (long)bpref, nsize, alloccg); 1014463Smckusic if (bno != 0) { 1024463Smckusic /* 1034463Smckusic * make a new copy 1044463Smckusic */ 105*5322Smckusic obp = bread(dev, fsbtodb(fs, bprev), osize); 106*5322Smckusic bp = getblk(dev, fsbtodb(fs, bno), nsize); 1074463Smckusic cp = bp->b_un.b_addr; 1084463Smckusic bp->b_un.b_addr = obp->b_un.b_addr; 1094463Smckusic obp->b_un.b_addr = cp; 1104463Smckusic obp->b_flags |= B_INVAL; 1114463Smckusic brelse(obp); 1125212Smckusic fre(dev, bprev, (off_t)osize); 1134463Smckusic blkclr(bp->b_un.b_addr + osize, nsize - osize); 1144463Smckusic return(bp); 1154463Smckusic } 1164792Smckusic nospace: 1174463Smckusic /* 1184463Smckusic * no space available 1194463Smckusic */ 1204426Smckusic fserr(fs, "file system full"); 1214426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1224426Smckusic u.u_error = ENOSPC; 1234426Smckusic return (NULL); 1244426Smckusic } 1254426Smckusic 1264359Smckusick struct inode * 1274359Smckusick ialloc(dev, ipref, mode) 1284359Smckusick dev_t dev; 1294359Smckusick ino_t ipref; 1304359Smckusick int mode; 1314359Smckusick { 1325212Smckusic ino_t ino; 1334359Smckusick register struct fs *fs; 1344359Smckusick register struct inode *ip; 1354359Smckusick int cg; 1364359Smckusick 1374359Smckusick fs = getfs(dev); 1384792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 1394359Smckusick goto noinodes; 1404948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 1414948Smckusic ipref = 0; 1424359Smckusick cg = itog(ipref, fs); 1435212Smckusic ino = (ino_t)hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 1444359Smckusick if (ino == 0) 1454359Smckusick goto noinodes; 1464359Smckusick ip = iget(dev, ino); 1474359Smckusick if (ip == NULL) { 1485212Smckusic ifree(dev, ino, 0); 1494359Smckusick return (NULL); 1504359Smckusick } 1514359Smckusick if (ip->i_mode) 1524359Smckusick panic("ialloc: dup alloc"); 1534359Smckusick return (ip); 1544359Smckusick noinodes: 1554359Smckusick fserr(fs, "out of inodes"); 1564359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 1574359Smckusick u.u_error = ENOSPC; 1584359Smckusick return (NULL); 1594359Smckusick } 1604359Smckusick 1614651Smckusic /* 1624651Smckusic * find a cylinder to place a directory 1634651Smckusic */ 1644651Smckusic dirpref(dev) 1654359Smckusick dev_t dev; 1664359Smckusick { 1674359Smckusick register struct fs *fs; 1684651Smckusic int cg, minndir, mincg, avgifree; 1694359Smckusick 1704359Smckusick fs = getfs(dev); 1714792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 1724651Smckusic minndir = fs->fs_ipg; 1734359Smckusick mincg = 0; 1744651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 175*5322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 176*5322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 1774359Smckusick mincg = cg; 178*5322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 1794359Smckusick } 1804359Smckusick return (fs->fs_ipg * mincg); 1814359Smckusick } 1824359Smckusick 1834651Smckusic /* 1844651Smckusic * select a cylinder to place a large block of data 1854651Smckusic */ 1865212Smckusic daddr_t 1874651Smckusic blkpref(dev) 1884651Smckusic dev_t dev; 1894651Smckusic { 1904651Smckusic register struct fs *fs; 1914651Smckusic int cg, avgbfree; 1924651Smckusic 1934651Smckusic fs = getfs(dev); 1944792Smckusic avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 1954651Smckusic for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) 196*5322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 1974651Smckusic fs->fs_cgrotor = cg; 198*5322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 1994651Smckusic } 2004651Smckusic for (cg = 0; cg <= fs->fs_cgrotor; cg++) 201*5322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 2024651Smckusic fs->fs_cgrotor = cg; 203*5322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 2044651Smckusic } 2054651Smckusic return (0); 2064651Smckusic } 2074651Smckusic 2085212Smckusic /*VARARGS5*/ 2095212Smckusic u_long 2104359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 2114359Smckusick dev_t dev; 2124359Smckusick register struct fs *fs; 2134359Smckusick int cg; 2144359Smckusick long pref; 2154359Smckusick int size; /* size for data blocks, mode for inodes */ 2165212Smckusic u_long (*allocator)(); 2174359Smckusick { 2184359Smckusick long result; 2194359Smckusick int i, icg = cg; 2204359Smckusick 2214359Smckusick /* 2224359Smckusick * 1: preferred cylinder group 2234359Smckusick */ 2244359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 2254359Smckusick if (result) 2264359Smckusick return (result); 2274359Smckusick /* 2284359Smckusick * 2: quadratic rehash 2294359Smckusick */ 2304359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 2314359Smckusick cg += i; 2324359Smckusick if (cg >= fs->fs_ncg) 2334359Smckusick cg -= fs->fs_ncg; 2344359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2354359Smckusick if (result) 2364359Smckusick return (result); 2374359Smckusick } 2384359Smckusick /* 2394359Smckusick * 3: brute force search 2404359Smckusick */ 2414359Smckusick cg = icg; 2424359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 2434359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 2444359Smckusick if (result) 2454359Smckusick return (result); 2464359Smckusick cg++; 2474359Smckusick if (cg == fs->fs_ncg) 2484359Smckusick cg = 0; 2494359Smckusick } 2504359Smckusick return (0); 2514359Smckusick } 2524359Smckusick 2534359Smckusick daddr_t 2544463Smckusic fragextend(dev, fs, cg, bprev, osize, nsize) 2554426Smckusic dev_t dev; 2564426Smckusic register struct fs *fs; 2574426Smckusic int cg; 2584463Smckusic long bprev; 2594426Smckusic int osize, nsize; 2604426Smckusic { 2614463Smckusic register struct buf *bp; 2624463Smckusic register struct cg *cgp; 2634463Smckusic long bno; 2644463Smckusic int frags, bbase; 2654426Smckusic int i; 2664426Smckusic 267*5322Smckusic frags = nsize / fs->fs_fsize; 268*5322Smckusic bbase = bprev % fs->fs_frag; 269*5322Smckusic if (bbase > (bprev + frags - 1) % fs->fs_frag) { 2704463Smckusic /* cannot extend across a block boundry */ 2714463Smckusic return (0); 2724463Smckusic } 273*5322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 2744426Smckusic if (bp->b_flags & B_ERROR) 2754426Smckusic return (0); 2764426Smckusic cgp = bp->b_un.b_cg; 2774463Smckusic bno = bprev % fs->fs_fpg; 278*5322Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) { 2794463Smckusic if (isclr(cgp->cg_free, bno + i)) 2804463Smckusic break; 2814463Smckusic } 2824463Smckusic if (i == frags) { 2834463Smckusic /* 2844463Smckusic * the current fragment can be extended 2854463Smckusic * deduct the count on fragment being extended into 2864463Smckusic * increase the count on the remaining fragment (if any) 2874463Smckusic * allocate the extended piece 2884463Smckusic */ 289*5322Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 2904463Smckusic if (isclr(cgp->cg_free, bno + i)) 2914426Smckusic break; 292*5322Smckusic cgp->cg_frsum[i - osize / fs->fs_fsize]--; 2934463Smckusic if (i != frags) 2944463Smckusic cgp->cg_frsum[i - frags]++; 295*5322Smckusic for (i = osize / fs->fs_fsize; i < frags; i++) { 2964463Smckusic clrbit(cgp->cg_free, bno + i); 2974792Smckusic cgp->cg_cs.cs_nffree--; 2984792Smckusic fs->fs_cstotal.cs_nffree--; 299*5322Smckusic fs->fs_cs(fs, cg).cs_nffree--; 3004426Smckusic } 3014463Smckusic fs->fs_fmod++; 3024463Smckusic bdwrite(bp); 3034463Smckusic return (bprev); 3044426Smckusic } 3054426Smckusic brelse(bp); 3064426Smckusic return (0); 3074426Smckusic } 3084426Smckusic 3094426Smckusic daddr_t 3104359Smckusick alloccg(dev, fs, cg, bpref, size) 3114359Smckusick dev_t dev; 3124463Smckusic register struct fs *fs; 3134359Smckusick int cg; 3144359Smckusick daddr_t bpref; 3154359Smckusick int size; 3164359Smckusick { 3174463Smckusic register struct buf *bp; 3184463Smckusic register struct cg *cgp; 3194463Smckusic int bno, frags; 3204463Smckusic int allocsiz; 3214463Smckusic register int i; 3224359Smckusick 323*5322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 3244792Smckusic return (0); 325*5322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 3264359Smckusick if (bp->b_flags & B_ERROR) 3274359Smckusick return (0); 3284359Smckusick cgp = bp->b_un.b_cg; 329*5322Smckusic if (size == fs->fs_bsize) { 3305212Smckusic bno = alloccgblk(fs, cgp, bpref); 3314463Smckusic bdwrite(bp); 3324463Smckusic return (bno); 3334463Smckusic } 3344463Smckusic /* 3354463Smckusic * check to see if any fragments are already available 3364463Smckusic * allocsiz is the size which will be allocated, hacking 3374463Smckusic * it down to a smaller size if necessary 3384463Smckusic */ 339*5322Smckusic frags = size / fs->fs_fsize; 340*5322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 3414463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 3424463Smckusic break; 343*5322Smckusic if (allocsiz == fs->fs_frag) { 3444463Smckusic /* 3454463Smckusic * no fragments were available, so a block will be 3464463Smckusic * allocated, and hacked up 3474463Smckusic */ 3484792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 3494463Smckusic brelse(bp); 3504463Smckusic return (0); 3514463Smckusic } 3525212Smckusic bno = alloccgblk(fs, cgp, bpref); 3534463Smckusic bpref = bno % fs->fs_fpg; 354*5322Smckusic for (i = frags; i < fs->fs_frag; i++) 3554463Smckusic setbit(cgp->cg_free, bpref + i); 356*5322Smckusic i = fs->fs_frag - frags; 3574792Smckusic cgp->cg_cs.cs_nffree += i; 3584792Smckusic fs->fs_cstotal.cs_nffree += i; 359*5322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 3604463Smckusic cgp->cg_frsum[i]++; 3614463Smckusic bdwrite(bp); 3624463Smckusic return (bno); 3634463Smckusic } 3644651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 3654651Smckusic if (bno == 0) 3664651Smckusic return (0); 3674463Smckusic for (i = 0; i < frags; i++) 3684463Smckusic clrbit(cgp->cg_free, bno + i); 3694792Smckusic cgp->cg_cs.cs_nffree -= frags; 3704792Smckusic fs->fs_cstotal.cs_nffree -= frags; 371*5322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 3724463Smckusic cgp->cg_frsum[allocsiz]--; 3734463Smckusic if (frags != allocsiz) 3744463Smckusic cgp->cg_frsum[allocsiz - frags]++; 3754463Smckusic bdwrite(bp); 3764463Smckusic return (cg * fs->fs_fpg + bno); 3774463Smckusic } 3784463Smckusic 3794463Smckusic daddr_t 3805212Smckusic alloccgblk(fs, cgp, bpref) 3814463Smckusic struct fs *fs; 3824463Smckusic register struct cg *cgp; 3834463Smckusic daddr_t bpref; 3844463Smckusic { 3854651Smckusic daddr_t bno; 3864651Smckusic int cylno, pos; 3874651Smckusic short *cylbp; 3884651Smckusic int i, j; 3894463Smckusic 3904651Smckusic if (bpref == 0) { 3914651Smckusic bpref = cgp->cg_rotor; 3924651Smckusic } else { 393*5322Smckusic bpref &= ~(fs->fs_frag - 1); 3944359Smckusick bpref %= fs->fs_fpg; 3954651Smckusic /* 3964651Smckusic * if the requested block is available, use it 3974651Smckusic */ 398*5322Smckusic if (isblock(fs, cgp->cg_free, bpref/fs->fs_frag)) { 3994651Smckusic bno = bpref; 4004359Smckusick goto gotit; 4014359Smckusick } 4024651Smckusic /* 4034651Smckusic * check for a block available on the same cylinder 4044651Smckusic * beginning with one which is rotationally optimal 4054651Smckusic */ 406*5322Smckusic i = bpref * NSPF(fs); 4074651Smckusic cylno = i / fs->fs_spc; 4084651Smckusic cylbp = cgp->cg_b[cylno]; 409*5322Smckusic pos = (i + (fs->fs_rotdelay == 0) ? 0 : 410*5322Smckusic 1 + fs->fs_rotdelay * HZ * fs->fs_nsect / 411*5322Smckusic (NSPF(fs) * 1000)) % fs->fs_nsect * NRPOS / fs->fs_nsect; 4124651Smckusic for (i = pos; i < NRPOS; i++) 4134651Smckusic if (cylbp[i] > 0) 4144651Smckusic break; 4154651Smckusic if (i == NRPOS) 4164651Smckusic for (i = 0; i < pos; i++) 4174651Smckusic if (cylbp[i] > 0) 4184651Smckusic break; 4194651Smckusic if (cylbp[i] > 0) { 420*5322Smckusic bpref = cylno * fs->fs_spc / NSPB(fs); 4214651Smckusic for (j = fs->fs_postbl[i]; j > -1; j = fs->fs_rotbl[j]) { 422*5322Smckusic if (isblock(fs, cgp->cg_free, bpref + j)) { 423*5322Smckusic bno = (bpref + j) * fs->fs_frag; 4244651Smckusic goto gotit; 4254651Smckusic } 4264651Smckusic } 4274651Smckusic panic("alloccgblk: can't find blk in cyl"); 4284651Smckusic } 4294359Smckusick } 430*5322Smckusic bno = mapsearch(fs, cgp, bpref, fs->fs_frag); 4314651Smckusic if (bno == 0) 4324651Smckusic return (0); 4334651Smckusic cgp->cg_rotor = bno; 4344359Smckusick gotit: 435*5322Smckusic clrblock(fs, cgp->cg_free, bno/fs->fs_frag); 4364792Smckusic cgp->cg_cs.cs_nbfree--; 4374792Smckusic fs->fs_cstotal.cs_nbfree--; 438*5322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 439*5322Smckusic i = bno * NSPF(fs); 4404463Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--; 4414359Smckusick fs->fs_fmod++; 4424651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 4434359Smckusick } 4444359Smckusick 4455212Smckusic ino_t 4464359Smckusick ialloccg(dev, fs, cg, ipref, mode) 4474359Smckusick dev_t dev; 4484463Smckusic register struct fs *fs; 4494359Smckusick int cg; 4504359Smckusick daddr_t ipref; 4514359Smckusick int mode; 4524359Smckusick { 4534463Smckusic register struct buf *bp; 4544463Smckusic register struct cg *cgp; 4554359Smckusick int i; 4564359Smckusick 457*5322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 4584792Smckusic return (0); 459*5322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 4604359Smckusick if (bp->b_flags & B_ERROR) 4614359Smckusick return (0); 4624359Smckusick cgp = bp->b_un.b_cg; 4634359Smckusick if (ipref) { 4644359Smckusick ipref %= fs->fs_ipg; 4654359Smckusick if (isclr(cgp->cg_iused, ipref)) 4664359Smckusick goto gotit; 4674359Smckusick } else 4684359Smckusick ipref = cgp->cg_irotor; 4694359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 4704359Smckusick ipref++; 4714359Smckusick if (ipref >= fs->fs_ipg) 4724359Smckusick ipref = 0; 4734359Smckusick if (isclr(cgp->cg_iused, ipref)) { 4744359Smckusick cgp->cg_irotor = ipref; 4754359Smckusick goto gotit; 4764359Smckusick } 4774359Smckusick } 4784359Smckusick brelse(bp); 4794359Smckusick return (0); 4804359Smckusick gotit: 4814359Smckusick setbit(cgp->cg_iused, ipref); 4824792Smckusic cgp->cg_cs.cs_nifree--; 4834792Smckusic fs->fs_cstotal.cs_nifree--; 484*5322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 4854359Smckusick fs->fs_fmod++; 4864359Smckusick if ((mode & IFMT) == IFDIR) { 4874792Smckusic cgp->cg_cs.cs_ndir++; 4884792Smckusic fs->fs_cstotal.cs_ndir++; 489*5322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 4904359Smckusick } 4914359Smckusick bdwrite(bp); 4924359Smckusick return (cg * fs->fs_ipg + ipref); 4934359Smckusick } 4944359Smckusick 4954359Smckusick fre(dev, bno, size) 4964359Smckusick dev_t dev; 4974359Smckusick daddr_t bno; 4985212Smckusic off_t size; 4994359Smckusick { 5004359Smckusick register struct fs *fs; 5014359Smckusick register struct cg *cgp; 5024359Smckusick register struct buf *bp; 5034463Smckusic int cg, blk, frags, bbase; 5044463Smckusic register int i; 5054359Smckusick 506*5322Smckusic fs = getfs(dev); 507*5322Smckusic if ((unsigned)size > fs->fs_bsize || size % fs->fs_fsize != 0) 5084426Smckusic panic("free: bad size"); 5094359Smckusick cg = dtog(bno, fs); 5104359Smckusick if (badblock(fs, bno)) 5114359Smckusick return; 512*5322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 5134359Smckusick if (bp->b_flags & B_ERROR) 5144359Smckusick return; 5154359Smckusick cgp = bp->b_un.b_cg; 5164359Smckusick bno %= fs->fs_fpg; 517*5322Smckusic if (size == fs->fs_bsize) { 518*5322Smckusic if (isblock(fs, cgp->cg_free, bno/fs->fs_frag)) 5194426Smckusic panic("free: freeing free block"); 520*5322Smckusic setblock(fs, cgp->cg_free, bno/fs->fs_frag); 5214792Smckusic cgp->cg_cs.cs_nbfree++; 5224792Smckusic fs->fs_cstotal.cs_nbfree++; 523*5322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 524*5322Smckusic i = bno * NSPF(fs); 5254426Smckusic cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++; 5264426Smckusic } else { 527*5322Smckusic bbase = bno - (bno % fs->fs_frag); 5284463Smckusic /* 5294463Smckusic * decrement the counts associated with the old frags 5304463Smckusic */ 5314463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 532*5322Smckusic (0xff >> (NBBY - fs->fs_frag))); 533*5322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 5344463Smckusic /* 5354463Smckusic * deallocate the fragment 5364463Smckusic */ 537*5322Smckusic frags = size / fs->fs_fsize; 5384463Smckusic for (i = 0; i < frags; i++) { 5394426Smckusic if (isset(cgp->cg_free, bno + i)) 5404426Smckusic panic("free: freeing free frag"); 5414426Smckusic setbit(cgp->cg_free, bno + i); 5424792Smckusic cgp->cg_cs.cs_nffree++; 5434792Smckusic fs->fs_cstotal.cs_nffree++; 544*5322Smckusic fs->fs_cs(fs, cg).cs_nffree++; 5454426Smckusic } 5464463Smckusic /* 5474463Smckusic * add back in counts associated with the new frags 5484463Smckusic */ 5494463Smckusic blk = ((cgp->cg_free[bbase / NBBY] >> (bbase % NBBY)) & 550*5322Smckusic (0xff >> (NBBY - fs->fs_frag))); 551*5322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 5524463Smckusic /* 5534463Smckusic * if a complete block has been reassembled, account for it 5544463Smckusic */ 555*5322Smckusic if (isblock(fs, cgp->cg_free, bbase / fs->fs_frag)) { 556*5322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 557*5322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 558*5322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 5594792Smckusic cgp->cg_cs.cs_nbfree++; 5604792Smckusic fs->fs_cstotal.cs_nbfree++; 561*5322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 562*5322Smckusic i = bbase * NSPF(fs); 5634426Smckusic cgp->cg_b[i / fs->fs_spc] 5644426Smckusic [i % fs->fs_nsect * NRPOS / fs->fs_nsect]++; 5654426Smckusic } 5664426Smckusic } 5674359Smckusick fs->fs_fmod++; 5684359Smckusick bdwrite(bp); 5694359Smckusick } 5704359Smckusick 5714359Smckusick ifree(dev, ino, mode) 5724359Smckusick dev_t dev; 5734359Smckusick ino_t ino; 5744359Smckusick int mode; 5754359Smckusick { 5764359Smckusick register struct fs *fs; 5774359Smckusick register struct cg *cgp; 5784359Smckusick register struct buf *bp; 5794359Smckusick int cg; 5804359Smckusick 5814359Smckusick fs = getfs(dev); 5824359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 5834359Smckusick panic("ifree: range"); 5844359Smckusick cg = itog(ino, fs); 585*5322Smckusic bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize); 5864359Smckusick if (bp->b_flags & B_ERROR) 5874359Smckusick return; 5884359Smckusick cgp = bp->b_un.b_cg; 5894359Smckusick ino %= fs->fs_ipg; 5904359Smckusick if (isclr(cgp->cg_iused, ino)) 5914359Smckusick panic("ifree: freeing free inode"); 5924359Smckusick clrbit(cgp->cg_iused, ino); 5934792Smckusic cgp->cg_cs.cs_nifree++; 5944792Smckusic fs->fs_cstotal.cs_nifree++; 595*5322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 5964359Smckusick if ((mode & IFMT) == IFDIR) { 5974792Smckusic cgp->cg_cs.cs_ndir--; 5984792Smckusic fs->fs_cstotal.cs_ndir--; 599*5322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 6004359Smckusick } 6014359Smckusick fs->fs_fmod++; 6024359Smckusick bdwrite(bp); 6034359Smckusick } 6044359Smckusick 6054463Smckusic /* 6064651Smckusic * find a block of the specified size in the specified cylinder group 6074651Smckusic * It is a panic if a request is made to find a block if none are 6084651Smckusic * available. 6094651Smckusic */ 6104651Smckusic daddr_t 6114651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 6124651Smckusic register struct fs *fs; 6134651Smckusic register struct cg *cgp; 6144651Smckusic daddr_t bpref; 6154651Smckusic int allocsiz; 6164651Smckusic { 6174651Smckusic daddr_t bno; 6184651Smckusic int start, len, loc, i; 6194651Smckusic int blk, field, subfield, pos; 6204651Smckusic 6214651Smckusic /* 6224651Smckusic * find the fragment by searching through the free block 6234651Smckusic * map for an appropriate bit pattern 6244651Smckusic */ 6254651Smckusic if (bpref) 6264651Smckusic start = bpref % fs->fs_fpg / NBBY; 6274651Smckusic else 6284651Smckusic start = cgp->cg_frotor / NBBY; 6294651Smckusic len = roundup(fs->fs_fpg - 1, NBBY) / NBBY - start; 630*5322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 631*5322Smckusic 1 << (allocsiz - 1)); 6324651Smckusic if (loc == 0) { 6334651Smckusic len = start - 1; 6344651Smckusic start = (cgdmin(cgp->cg_cgx, fs) - 6354651Smckusic cgbase(cgp->cg_cgx, fs)) / NBBY; 636*5322Smckusic loc = scanc(len, &cgp->cg_free[start], fragtbl[fs->fs_frag], 6374651Smckusic 1 << (allocsiz - 1)); 6384651Smckusic if (loc == 0) { 6394651Smckusic panic("alloccg: map corrupted"); 6404651Smckusic return (0); 6414651Smckusic } 6424651Smckusic } 6434651Smckusic bno = (start + len - loc) * NBBY; 6444651Smckusic cgp->cg_frotor = bno; 6454651Smckusic /* 6464651Smckusic * found the byte in the map 6474651Smckusic * sift through the bits to find the selected frag 6484651Smckusic */ 649*5322Smckusic for (i = 0; i < NBBY; i += fs->fs_frag) { 650*5322Smckusic blk = (cgp->cg_free[bno / NBBY] >> i) & 651*5322Smckusic (0xff >> NBBY - fs->fs_frag); 6524651Smckusic blk <<= 1; 6534651Smckusic field = around[allocsiz]; 6544651Smckusic subfield = inside[allocsiz]; 655*5322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 6564651Smckusic if ((blk & field) == subfield) { 6574651Smckusic return (bno + i + pos); 6584651Smckusic } 6594651Smckusic field <<= 1; 6604651Smckusic subfield <<= 1; 6614651Smckusic } 6624651Smckusic } 6634651Smckusic panic("alloccg: block not in map"); 6644651Smckusic return (0); 6654651Smckusic } 6664651Smckusic 6674651Smckusic /* 6684463Smckusic * update the frsum fields to reflect addition or deletion 6694463Smckusic * of some frags 6704463Smckusic */ 671*5322Smckusic fragacct(fs, fragmap, fraglist, cnt) 672*5322Smckusic struct fs *fs; 6734472Smckusic int fragmap; 6744792Smckusic long fraglist[]; 6754463Smckusic int cnt; 6764463Smckusic { 6774463Smckusic int inblk; 6784463Smckusic register int field, subfield; 6794463Smckusic register int siz, pos; 6804463Smckusic 681*5322Smckusic inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 6824463Smckusic fragmap <<= 1; 683*5322Smckusic for (siz = 1; siz < fs->fs_frag; siz++) { 6844463Smckusic if (((1 << siz) & inblk) == 0) 6854463Smckusic continue; 6864463Smckusic field = around[siz]; 6874463Smckusic subfield = inside[siz]; 688*5322Smckusic for (pos = siz; pos <= fs->fs_frag; pos++) { 6894463Smckusic if ((fragmap & field) == subfield) { 6904463Smckusic fraglist[siz] += cnt; 6914463Smckusic pos += siz; 6924463Smckusic field <<= siz; 6934463Smckusic subfield <<= siz; 6944463Smckusic } 6954463Smckusic field <<= 1; 6964463Smckusic subfield <<= 1; 6974463Smckusic } 6984463Smckusic } 6994463Smckusic } 7004463Smckusic 7014359Smckusick badblock(fs, bn) 7024359Smckusick register struct fs *fs; 7034359Smckusick daddr_t bn; 7044359Smckusick { 7054359Smckusick 7064359Smckusick if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) { 7074359Smckusick fserr(fs, "bad block"); 7084359Smckusick return (1); 7094359Smckusick } 7104359Smckusick return (0); 7114359Smckusick } 7124359Smckusick 7134359Smckusick /* 7144359Smckusick * getfs maps a device number into 7154359Smckusick * a pointer to the incore super 7164359Smckusick * block. The algorithm is a linear 7174359Smckusick * search through the mount table. 7184359Smckusick * A consistency check of the 7194359Smckusick * in core free-block and i-node 7204359Smckusick * counts is performed. 7214359Smckusick * 7224359Smckusick * panic: no fs -- the device is not mounted. 7234359Smckusick * this "cannot happen" 7244359Smckusick */ 7254359Smckusick struct fs * 7264359Smckusick getfs(dev) 7274359Smckusick dev_t dev; 7284359Smckusick { 7294359Smckusick register struct mount *mp; 7304359Smckusick register struct fs *fs; 7314359Smckusick 7324359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7334359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 7344359Smckusick fs = mp->m_bufp->b_un.b_fs; 7354359Smckusick if (fs->fs_magic != FS_MAGIC) 7364359Smckusick panic("getfs: bad magic"); 7374359Smckusick return (fs); 7384359Smckusick } 7394359Smckusick panic("getfs: no fs"); 7404359Smckusick return (NULL); 7414359Smckusick } 7424359Smckusick 7434359Smckusick /* 7444359Smckusick * Fserr prints the name of a file system 7454359Smckusick * with an error diagnostic, in the form 7464359Smckusick * fs: error message 7474359Smckusick */ 7484359Smckusick fserr(fs, cp) 7494359Smckusick struct fs *fs; 7504359Smckusick char *cp; 7514359Smckusick { 7524359Smckusick 7534359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 7544359Smckusick } 7554359Smckusick 7564359Smckusick /* 7574359Smckusick * Getfsx returns the index in the file system 7584359Smckusick * table of the specified device. The swap device 7594359Smckusick * is also assigned a pseudo-index. The index may 7604359Smckusick * be used as a compressed indication of the location 7614359Smckusick * of a block, recording 7624359Smckusick * <getfsx(dev),blkno> 7634359Smckusick * rather than 7644359Smckusick * <dev, blkno> 7654359Smckusick * provided the information need remain valid only 7664359Smckusick * as long as the file system is mounted. 7674359Smckusick */ 7684359Smckusick getfsx(dev) 7694359Smckusick dev_t dev; 7704359Smckusick { 7714359Smckusick register struct mount *mp; 7724359Smckusick 7734359Smckusick if (dev == swapdev) 7744359Smckusick return (MSWAPX); 7754359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7764359Smckusick if (mp->m_dev == dev) 7774359Smckusick return (mp - &mount[0]); 7784359Smckusick return (-1); 7794359Smckusick } 7804359Smckusick 7814359Smckusick /* 7824359Smckusick * Update is the internal name of 'sync'. It goes through the disk 7834359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 7844359Smckusick * modified nodes; and it goes through the mount table to initiate modified 7854359Smckusick * super blocks. 7864359Smckusick */ 7874359Smckusick update() 7884359Smckusick { 7894359Smckusick register struct inode *ip; 7904359Smckusick register struct mount *mp; 7914359Smckusick register struct buf *bp; 7924359Smckusick struct fs *fs; 7934359Smckusick time_t tim; 7944651Smckusic int i, blks; 7954359Smckusick 7964359Smckusick if (updlock) 7974359Smckusick return; 7984359Smckusick updlock++; 7994359Smckusick /* 8004359Smckusick * Write back modified superblocks. 8014359Smckusick * Consistency check that the superblock 8024359Smckusick * of each file system is still in the buffer cache. 8034359Smckusick */ 8044359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8054359Smckusick if (mp->m_bufp != NULL) { 8064359Smckusick fs = mp->m_bufp->b_un.b_fs; 8074359Smckusick if (fs->fs_fmod == 0) 8084359Smckusick continue; 8094359Smckusick if (fs->fs_ronly != 0) 8104359Smckusick panic("update: rofs mod"); 811*5322Smckusic bp = getblk(mp->m_dev, SBLOCK, MAXBSIZE); 8124359Smckusick fs->fs_fmod = 0; 8134359Smckusick fs->fs_time = TIME; 8144359Smckusick if (bp->b_un.b_fs != fs) 8154359Smckusick panic("update: bad b_fs"); 8164359Smckusick bwrite(bp); 817*5322Smckusic blks = howmany(fs->fs_cssize, fs->fs_bsize); 8184651Smckusic for (i = 0; i < blks; i++) { 819*5322Smckusic bp = getblk(mp->m_dev, 820*5322Smckusic fsbtodb(fs, fs->fs_csaddr + (i * fs->fs_frag)), 821*5322Smckusic fs->fs_bsize); 8224359Smckusick bwrite(bp); 8234359Smckusick } 8244359Smckusick } 8254359Smckusick /* 8264359Smckusick * Write back each (modified) inode. 8274359Smckusick */ 8284359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 8294359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 8304359Smckusick ip->i_flag |= ILOCK; 8314359Smckusick ip->i_count++; 8324359Smckusick tim = TIME; 8334359Smckusick iupdat(ip, &tim, &tim, 0); 8344359Smckusick iput(ip); 8354359Smckusick } 8364359Smckusick updlock = 0; 8374359Smckusick /* 8384359Smckusick * Force stale buffer cache information to be flushed, 8394359Smckusick * for all devices. 8404359Smckusick */ 8414359Smckusick bflush(NODEV); 8424359Smckusick } 843*5322Smckusic 844*5322Smckusic /* 845*5322Smckusic * block macros 846*5322Smckusic */ 847*5322Smckusic 848*5322Smckusic isblock(fs, cp, h) 849*5322Smckusic struct fs *fs; 850*5322Smckusic unsigned char *cp; 851*5322Smckusic int h; 852*5322Smckusic { 853*5322Smckusic unsigned char mask; 854*5322Smckusic 855*5322Smckusic switch (fs->fs_frag) { 856*5322Smckusic case 8: 857*5322Smckusic return (cp[h] == 0xff); 858*5322Smckusic case 4: 859*5322Smckusic mask = 0x0f << ((h & 0x1) << 2); 860*5322Smckusic return ((cp[h >> 1] & mask) == mask); 861*5322Smckusic case 2: 862*5322Smckusic mask = 0x03 << ((h & 0x3) << 1); 863*5322Smckusic return ((cp[h >> 2] & mask) == mask); 864*5322Smckusic case 1: 865*5322Smckusic mask = 0x01 << (h & 0x7); 866*5322Smckusic return ((cp[h >> 3] & mask) == mask); 867*5322Smckusic default: 868*5322Smckusic panic("isblock bad fs_frag"); 869*5322Smckusic return; 870*5322Smckusic } 871*5322Smckusic } 872*5322Smckusic clrblock(fs, cp, h) 873*5322Smckusic struct fs *fs; 874*5322Smckusic unsigned char *cp; 875*5322Smckusic int h; 876*5322Smckusic { 877*5322Smckusic switch ((fs)->fs_frag) { 878*5322Smckusic case 8: 879*5322Smckusic cp[h] = 0; 880*5322Smckusic return; 881*5322Smckusic case 4: 882*5322Smckusic cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 883*5322Smckusic return; 884*5322Smckusic case 2: 885*5322Smckusic cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 886*5322Smckusic return; 887*5322Smckusic case 1: 888*5322Smckusic cp[h >> 3] &= ~(0x01 << (h & 0x7)); 889*5322Smckusic return; 890*5322Smckusic default: 891*5322Smckusic panic("clrblock bad fs_frag"); 892*5322Smckusic return; 893*5322Smckusic } 894*5322Smckusic } 895*5322Smckusic setblock(fs, cp, h) 896*5322Smckusic struct fs *fs; 897*5322Smckusic unsigned char *cp; 898*5322Smckusic int h; 899*5322Smckusic { 900*5322Smckusic switch (fs->fs_frag) { 901*5322Smckusic case 8: 902*5322Smckusic cp[h] = 0xff; 903*5322Smckusic return; 904*5322Smckusic case 4: 905*5322Smckusic cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 906*5322Smckusic return; 907*5322Smckusic case 2: 908*5322Smckusic cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 909*5322Smckusic return; 910*5322Smckusic case 1: 911*5322Smckusic cp[h >> 3] |= (0x01 << (h & 0x7)); 912*5322Smckusic return; 913*5322Smckusic default: 914*5322Smckusic panic("setblock bad fs_frag"); 915*5322Smckusic return; 916*5322Smckusic } 917*5322Smckusic } 918