1*4359Smckusick /* Copyright (c) 1981 Regents of the University of California */ 2*4359Smckusick 3*4359Smckusick static char version[] = "@(#)lfs_alloc.c 1.1 09/09/81"; 4*4359Smckusick 5*4359Smckusick /* alloc.c 4.8 81/03/08 */ 6*4359Smckusick 7*4359Smckusick #include "../h/param.h" 8*4359Smckusick #include "../h/systm.h" 9*4359Smckusick #include "../h/mount.h" 10*4359Smckusick #include "../h/fs.h" 11*4359Smckusick #include "../h/conf.h" 12*4359Smckusick #include "../h/buf.h" 13*4359Smckusick #include "../h/inode.h" 14*4359Smckusick #include "../h/dir.h" 15*4359Smckusick #include "../h/user.h" 16*4359Smckusick 17*4359Smckusick long hashalloc(); 18*4359Smckusick long alloccg(); 19*4359Smckusick long ialloccg(); 20*4359Smckusick 21*4359Smckusick struct buf * 22*4359Smckusick alloc(dev, ip, bpref, size) 23*4359Smckusick dev_t dev; 24*4359Smckusick struct inode *ip; 25*4359Smckusick daddr_t bpref; 26*4359Smckusick int size; 27*4359Smckusick { 28*4359Smckusick daddr_t bno; 29*4359Smckusick register struct fs *fs; 30*4359Smckusick struct buf *bp; 31*4359Smckusick int cg; 32*4359Smckusick 33*4359Smckusick fs = getfs(dev); 34*4359Smckusick if (fs->fs_nbfree == 0 && size == BSIZE) 35*4359Smckusick goto nospace; 36*4359Smckusick if (bpref == 0) 37*4359Smckusick cg = itog(ip->i_number, fs); 38*4359Smckusick else 39*4359Smckusick cg = dtog(bpref, fs); 40*4359Smckusick bno = hashalloc(dev, fs, cg, (long)bpref, size, alloccg); 41*4359Smckusick if (bno == 0) 42*4359Smckusick goto nospace; 43*4359Smckusick bp = getblk(dev, bno); 44*4359Smckusick clrbuf(bp); 45*4359Smckusick return (bp); 46*4359Smckusick nospace: 47*4359Smckusick fserr(fs, "file system full"); 48*4359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 49*4359Smckusick u.u_error = ENOSPC; 50*4359Smckusick return (NULL); 51*4359Smckusick } 52*4359Smckusick 53*4359Smckusick struct inode * 54*4359Smckusick ialloc(dev, ipref, mode) 55*4359Smckusick dev_t dev; 56*4359Smckusick ino_t ipref; 57*4359Smckusick int mode; 58*4359Smckusick { 59*4359Smckusick daddr_t ino; 60*4359Smckusick register struct fs *fs; 61*4359Smckusick register struct inode *ip; 62*4359Smckusick int cg; 63*4359Smckusick 64*4359Smckusick fs = getfs(dev); 65*4359Smckusick if (fs->fs_nifree == 0) 66*4359Smckusick goto noinodes; 67*4359Smckusick cg = itog(ipref, fs); 68*4359Smckusick ino = hashalloc(dev, fs, cg, (long)ipref, mode, ialloccg); 69*4359Smckusick if (ino == 0) 70*4359Smckusick goto noinodes; 71*4359Smckusick ip = iget(dev, ino); 72*4359Smckusick if (ip == NULL) { 73*4359Smckusick ifree(dev, ino); 74*4359Smckusick return (NULL); 75*4359Smckusick } 76*4359Smckusick if (ip->i_mode) 77*4359Smckusick panic("ialloc: dup alloc"); 78*4359Smckusick return (ip); 79*4359Smckusick noinodes: 80*4359Smckusick fserr(fs, "out of inodes"); 81*4359Smckusick uprintf("\n%s: create failed, no inodes free\n", fs->fs_fsmnt); 82*4359Smckusick u.u_error = ENOSPC; 83*4359Smckusick return (NULL); 84*4359Smckusick } 85*4359Smckusick 86*4359Smckusick dipref(dev) 87*4359Smckusick dev_t dev; 88*4359Smckusick { 89*4359Smckusick register struct fs *fs; 90*4359Smckusick int cg, minndir, mincg; 91*4359Smckusick 92*4359Smckusick fs = getfs(dev); 93*4359Smckusick minndir = fs->fs_cs[0].cs_ndir; 94*4359Smckusick mincg = 0; 95*4359Smckusick for (cg = 1; cg < fs->fs_ncg; cg++) 96*4359Smckusick if (fs->fs_cs[cg].cs_ndir < minndir) { 97*4359Smckusick mincg = cg; 98*4359Smckusick minndir = fs->fs_cs[cg].cs_ndir; 99*4359Smckusick if (minndir == 0) 100*4359Smckusick break; 101*4359Smckusick } 102*4359Smckusick return (fs->fs_ipg * mincg); 103*4359Smckusick } 104*4359Smckusick 105*4359Smckusick long 106*4359Smckusick hashalloc(dev, fs, cg, pref, size, allocator) 107*4359Smckusick dev_t dev; 108*4359Smckusick register struct fs *fs; 109*4359Smckusick int cg; 110*4359Smckusick long pref; 111*4359Smckusick int size; /* size for data blocks, mode for inodes */ 112*4359Smckusick long (*allocator)(); 113*4359Smckusick { 114*4359Smckusick long result; 115*4359Smckusick int i, icg = cg; 116*4359Smckusick 117*4359Smckusick /* 118*4359Smckusick * 1: preferred cylinder group 119*4359Smckusick */ 120*4359Smckusick result = (*allocator)(dev, fs, cg, pref, size); 121*4359Smckusick if (result) 122*4359Smckusick return (result); 123*4359Smckusick /* 124*4359Smckusick * 2: quadratic rehash 125*4359Smckusick */ 126*4359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 127*4359Smckusick cg += i; 128*4359Smckusick if (cg >= fs->fs_ncg) 129*4359Smckusick cg -= fs->fs_ncg; 130*4359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 131*4359Smckusick if (result) 132*4359Smckusick return (result); 133*4359Smckusick } 134*4359Smckusick /* 135*4359Smckusick * 3: brute force search 136*4359Smckusick */ 137*4359Smckusick cg = icg; 138*4359Smckusick for (i = 0; i < fs->fs_ncg; i++) { 139*4359Smckusick result = (*allocator)(dev, fs, cg, 0, size); 140*4359Smckusick if (result) 141*4359Smckusick return (result); 142*4359Smckusick cg++; 143*4359Smckusick if (cg == fs->fs_ncg) 144*4359Smckusick cg = 0; 145*4359Smckusick } 146*4359Smckusick return (0); 147*4359Smckusick } 148*4359Smckusick 149*4359Smckusick daddr_t 150*4359Smckusick alloccg(dev, fs, cg, bpref, size) 151*4359Smckusick dev_t dev; 152*4359Smckusick struct fs *fs; 153*4359Smckusick int cg; 154*4359Smckusick daddr_t bpref; 155*4359Smckusick int size; 156*4359Smckusick { 157*4359Smckusick struct buf *bp; 158*4359Smckusick struct cg *cgp; 159*4359Smckusick int i; 160*4359Smckusick 161*4359Smckusick if (size != BSIZE) 162*4359Smckusick panic("alloccg: size != BSIZE is too hard!"); 163*4359Smckusick bp = bread(dev, cgtod(cg, fs)); 164*4359Smckusick if (bp->b_flags & B_ERROR) 165*4359Smckusick return (0); 166*4359Smckusick cgp = bp->b_un.b_cg; 167*4359Smckusick if (bpref) { 168*4359Smckusick bpref %= fs->fs_fpg; 169*4359Smckusick if (isblock(cgp->cg_free, bpref/FRAG)) 170*4359Smckusick goto gotit; 171*4359Smckusick } else 172*4359Smckusick bpref = cgp->cg_rotor; 173*4359Smckusick for (i = 0; i < cgp->cg_ndblk; i += FRAG) { 174*4359Smckusick bpref += FRAG; 175*4359Smckusick if (bpref >= cgp->cg_ndblk) 176*4359Smckusick bpref = 0; 177*4359Smckusick if (isblock(cgp->cg_free, bpref/FRAG)) { 178*4359Smckusick cgp->cg_rotor = bpref; 179*4359Smckusick goto gotit; 180*4359Smckusick } 181*4359Smckusick } 182*4359Smckusick brelse(bp); 183*4359Smckusick return (0); 184*4359Smckusick gotit: 185*4359Smckusick clrblock(cgp->cg_free, bpref/FRAG); 186*4359Smckusick cgp->cg_nbfree--; 187*4359Smckusick fs->fs_nbfree--; 188*4359Smckusick fs->fs_cs[cg].cs_nbfree--; 189*4359Smckusick fs->fs_fmod++; 190*4359Smckusick i = bpref * NSPF; 191*4359Smckusick cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]--; 192*4359Smckusick bdwrite(bp); 193*4359Smckusick return (cg * fs->fs_fpg + bpref); 194*4359Smckusick } 195*4359Smckusick 196*4359Smckusick long 197*4359Smckusick ialloccg(dev, fs, cg, ipref, mode) 198*4359Smckusick dev_t dev; 199*4359Smckusick struct fs *fs; 200*4359Smckusick int cg; 201*4359Smckusick daddr_t ipref; 202*4359Smckusick int mode; 203*4359Smckusick { 204*4359Smckusick struct buf *bp; 205*4359Smckusick struct cg *cgp; 206*4359Smckusick int i; 207*4359Smckusick 208*4359Smckusick bp = bread(dev, cgtod(cg, fs)); 209*4359Smckusick if (bp->b_flags & B_ERROR) 210*4359Smckusick return (0); 211*4359Smckusick cgp = bp->b_un.b_cg; 212*4359Smckusick if (cgp->cg_nifree == 0) { 213*4359Smckusick brelse(bp); 214*4359Smckusick return (0); 215*4359Smckusick } 216*4359Smckusick if (ipref) { 217*4359Smckusick ipref %= fs->fs_ipg; 218*4359Smckusick if (isclr(cgp->cg_iused, ipref)) 219*4359Smckusick goto gotit; 220*4359Smckusick } else 221*4359Smckusick ipref = cgp->cg_irotor; 222*4359Smckusick for (i = 0; i < fs->fs_ipg; i++) { 223*4359Smckusick ipref++; 224*4359Smckusick if (ipref >= fs->fs_ipg) 225*4359Smckusick ipref = 0; 226*4359Smckusick if (isclr(cgp->cg_iused, ipref)) { 227*4359Smckusick cgp->cg_irotor = ipref; 228*4359Smckusick goto gotit; 229*4359Smckusick } 230*4359Smckusick } 231*4359Smckusick brelse(bp); 232*4359Smckusick return (0); 233*4359Smckusick gotit: 234*4359Smckusick setbit(cgp->cg_iused, ipref); 235*4359Smckusick cgp->cg_nifree--; 236*4359Smckusick fs->fs_nifree--; 237*4359Smckusick fs->fs_cs[cg].cs_nifree--; 238*4359Smckusick fs->fs_fmod++; 239*4359Smckusick if ((mode & IFMT) == IFDIR) { 240*4359Smckusick cgp->cg_ndir++; 241*4359Smckusick fs->fs_cs[cg].cs_ndir++; 242*4359Smckusick } 243*4359Smckusick bdwrite(bp); 244*4359Smckusick return (cg * fs->fs_ipg + ipref); 245*4359Smckusick } 246*4359Smckusick 247*4359Smckusick fre(dev, bno, size) 248*4359Smckusick dev_t dev; 249*4359Smckusick daddr_t bno; 250*4359Smckusick int size; 251*4359Smckusick { 252*4359Smckusick register struct fs *fs; 253*4359Smckusick register struct cg *cgp; 254*4359Smckusick register struct buf *bp; 255*4359Smckusick int i; 256*4359Smckusick int cg; 257*4359Smckusick 258*4359Smckusick if (size != BSIZE) 259*4359Smckusick panic("free: size != BSIZE is too hard!"); 260*4359Smckusick fs = getfs(dev); 261*4359Smckusick cg = dtog(bno, fs); 262*4359Smckusick if (badblock(fs, bno)) 263*4359Smckusick return; 264*4359Smckusick bp = bread(dev, cgtod(cg, fs)); 265*4359Smckusick if (bp->b_flags & B_ERROR) 266*4359Smckusick return; 267*4359Smckusick cgp = bp->b_un.b_cg; 268*4359Smckusick bno %= fs->fs_fpg; 269*4359Smckusick if (isblock(cgp->cg_free, bno/FRAG)) 270*4359Smckusick panic("free: freeing free block"); 271*4359Smckusick setblock(cgp->cg_free, bno/FRAG); 272*4359Smckusick cgp->cg_nbfree++; 273*4359Smckusick fs->fs_nbfree++; 274*4359Smckusick fs->fs_cs[cg].cs_nbfree++; 275*4359Smckusick fs->fs_fmod++; 276*4359Smckusick i = bno * NSPF; 277*4359Smckusick cgp->cg_b[i/fs->fs_spc][i%fs->fs_nsect*NRPOS/fs->fs_nsect]++; 278*4359Smckusick bdwrite(bp); 279*4359Smckusick } 280*4359Smckusick 281*4359Smckusick ifree(dev, ino, mode) 282*4359Smckusick dev_t dev; 283*4359Smckusick ino_t ino; 284*4359Smckusick int mode; 285*4359Smckusick { 286*4359Smckusick register struct fs *fs; 287*4359Smckusick register struct cg *cgp; 288*4359Smckusick register struct buf *bp; 289*4359Smckusick int i; 290*4359Smckusick int cg; 291*4359Smckusick 292*4359Smckusick fs = getfs(dev); 293*4359Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 294*4359Smckusick panic("ifree: range"); 295*4359Smckusick cg = itog(ino, fs); 296*4359Smckusick bp = bread(dev, cgtod(cg, fs)); 297*4359Smckusick if (bp->b_flags & B_ERROR) 298*4359Smckusick return; 299*4359Smckusick cgp = bp->b_un.b_cg; 300*4359Smckusick ino %= fs->fs_ipg; 301*4359Smckusick if (isclr(cgp->cg_iused, ino)) 302*4359Smckusick panic("ifree: freeing free inode"); 303*4359Smckusick clrbit(cgp->cg_iused, ino); 304*4359Smckusick cgp->cg_nifree++; 305*4359Smckusick fs->fs_nifree++; 306*4359Smckusick fs->fs_cs[cg].cs_nifree++; 307*4359Smckusick if ((mode & IFMT) == IFDIR) { 308*4359Smckusick cgp->cg_ndir--; 309*4359Smckusick fs->fs_cs[cg].cs_ndir--; 310*4359Smckusick } 311*4359Smckusick fs->fs_fmod++; 312*4359Smckusick bdwrite(bp); 313*4359Smckusick } 314*4359Smckusick 315*4359Smckusick badblock(fs, bn) 316*4359Smckusick register struct fs *fs; 317*4359Smckusick daddr_t bn; 318*4359Smckusick { 319*4359Smckusick 320*4359Smckusick if ((unsigned)bn >= fs->fs_size || bn < cgdmin(dtog(bn, fs), fs)) { 321*4359Smckusick fserr(fs, "bad block"); 322*4359Smckusick return (1); 323*4359Smckusick } 324*4359Smckusick return (0); 325*4359Smckusick } 326*4359Smckusick 327*4359Smckusick /* 328*4359Smckusick * getfs maps a device number into 329*4359Smckusick * a pointer to the incore super 330*4359Smckusick * block. The algorithm is a linear 331*4359Smckusick * search through the mount table. 332*4359Smckusick * A consistency check of the 333*4359Smckusick * in core free-block and i-node 334*4359Smckusick * counts is performed. 335*4359Smckusick * 336*4359Smckusick * panic: no fs -- the device is not mounted. 337*4359Smckusick * this "cannot happen" 338*4359Smckusick */ 339*4359Smckusick struct fs * 340*4359Smckusick getfs(dev) 341*4359Smckusick dev_t dev; 342*4359Smckusick { 343*4359Smckusick register struct mount *mp; 344*4359Smckusick register struct fs *fs; 345*4359Smckusick 346*4359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 347*4359Smckusick if (mp->m_bufp != NULL && mp->m_dev == dev) { 348*4359Smckusick fs = mp->m_bufp->b_un.b_fs; 349*4359Smckusick if (fs->fs_magic != FS_MAGIC) 350*4359Smckusick panic("getfs: bad magic"); 351*4359Smckusick return (fs); 352*4359Smckusick } 353*4359Smckusick panic("getfs: no fs"); 354*4359Smckusick return (NULL); 355*4359Smckusick } 356*4359Smckusick 357*4359Smckusick /* 358*4359Smckusick * Fserr prints the name of a file system 359*4359Smckusick * with an error diagnostic, in the form 360*4359Smckusick * fs: error message 361*4359Smckusick */ 362*4359Smckusick fserr(fs, cp) 363*4359Smckusick struct fs *fs; 364*4359Smckusick char *cp; 365*4359Smckusick { 366*4359Smckusick 367*4359Smckusick printf("%s: %s\n", fs->fs_fsmnt, cp); 368*4359Smckusick } 369*4359Smckusick 370*4359Smckusick /* 371*4359Smckusick * Getfsx returns the index in the file system 372*4359Smckusick * table of the specified device. The swap device 373*4359Smckusick * is also assigned a pseudo-index. The index may 374*4359Smckusick * be used as a compressed indication of the location 375*4359Smckusick * of a block, recording 376*4359Smckusick * <getfsx(dev),blkno> 377*4359Smckusick * rather than 378*4359Smckusick * <dev, blkno> 379*4359Smckusick * provided the information need remain valid only 380*4359Smckusick * as long as the file system is mounted. 381*4359Smckusick */ 382*4359Smckusick getfsx(dev) 383*4359Smckusick dev_t dev; 384*4359Smckusick { 385*4359Smckusick register struct mount *mp; 386*4359Smckusick 387*4359Smckusick if (dev == swapdev) 388*4359Smckusick return (MSWAPX); 389*4359Smckusick for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 390*4359Smckusick if (mp->m_dev == dev) 391*4359Smckusick return (mp - &mount[0]); 392*4359Smckusick return (-1); 393*4359Smckusick } 394*4359Smckusick 395*4359Smckusick /* 396*4359Smckusick * Update is the internal name of 'sync'. It goes through the disk 397*4359Smckusick * queues to initiate sandbagged IO; goes through the inodes to write 398*4359Smckusick * modified nodes; and it goes through the mount table to initiate modified 399*4359Smckusick * super blocks. 400*4359Smckusick */ 401*4359Smckusick update() 402*4359Smckusick { 403*4359Smckusick register struct inode *ip; 404*4359Smckusick register struct mount *mp; 405*4359Smckusick register struct buf *bp; 406*4359Smckusick struct fs *fs; 407*4359Smckusick time_t tim; 408*4359Smckusick int i; 409*4359Smckusick 410*4359Smckusick if (updlock) 411*4359Smckusick return; 412*4359Smckusick updlock++; 413*4359Smckusick /* 414*4359Smckusick * Write back modified superblocks. 415*4359Smckusick * Consistency check that the superblock 416*4359Smckusick * of each file system is still in the buffer cache. 417*4359Smckusick */ 418*4359Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 419*4359Smckusick if (mp->m_bufp != NULL) { 420*4359Smckusick fs = mp->m_bufp->b_un.b_fs; 421*4359Smckusick if (fs->fs_fmod == 0) 422*4359Smckusick continue; 423*4359Smckusick if (fs->fs_ronly != 0) 424*4359Smckusick panic("update: rofs mod"); 425*4359Smckusick bp = getblk(mp->m_dev, SBLOCK); 426*4359Smckusick fs->fs_fmod = 0; 427*4359Smckusick fs->fs_time = TIME; 428*4359Smckusick if (bp->b_un.b_fs != fs) 429*4359Smckusick panic("update: bad b_fs"); 430*4359Smckusick bwrite(bp); 431*4359Smckusick for (i = 0; i < cssize(fs); i += BSIZE) { 432*4359Smckusick bp = getblk(mp->m_dev, csaddr(fs) + i / FSIZE); 433*4359Smckusick bcopy(fs->fs_cs + i, bp->b_un.b_addr, BSIZE); 434*4359Smckusick bwrite(bp); 435*4359Smckusick } 436*4359Smckusick } 437*4359Smckusick /* 438*4359Smckusick * Write back each (modified) inode. 439*4359Smckusick */ 440*4359Smckusick for (ip = inode; ip < inodeNINODE; ip++) 441*4359Smckusick if((ip->i_flag&ILOCK)==0 && ip->i_count) { 442*4359Smckusick ip->i_flag |= ILOCK; 443*4359Smckusick ip->i_count++; 444*4359Smckusick tim = TIME; 445*4359Smckusick iupdat(ip, &tim, &tim, 0); 446*4359Smckusick iput(ip); 447*4359Smckusick } 448*4359Smckusick updlock = 0; 449*4359Smckusick /* 450*4359Smckusick * Force stale buffer cache information to be flushed, 451*4359Smckusick * for all devices. 452*4359Smckusick */ 453*4359Smckusick bflush(NODEV); 454*4359Smckusick } 455