|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)ufs_alloc.c 7.20 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "buf.h" ! 26: #include "user.h" ! 27: #include "vnode.h" ! 28: #include "kernel.h" ! 29: #include "syslog.h" ! 30: #include "cmap.h" ! 31: #include "../ufs/quota.h" ! 32: #include "../ufs/inode.h" ! 33: #include "../ufs/fs.h" ! 34: ! 35: extern u_long hashalloc(); ! 36: extern ino_t ialloccg(); ! 37: extern daddr_t alloccg(); ! 38: extern daddr_t alloccgblk(); ! 39: extern daddr_t fragextend(); ! 40: extern daddr_t blkpref(); ! 41: extern daddr_t mapsearch(); ! 42: extern int inside[], around[]; ! 43: extern unsigned char *fragtbl[]; ! 44: ! 45: /* ! 46: * Allocate a block in the file system. ! 47: * ! 48: * The size of the requested block is given, which must be some ! 49: * multiple of fs_fsize and <= fs_bsize. ! 50: * A preference may be optionally specified. If a preference is given ! 51: * the following hierarchy is used to allocate a block: ! 52: * 1) allocate the requested block. ! 53: * 2) allocate a rotationally optimal block in the same cylinder. ! 54: * 3) allocate a block in the same cylinder group. ! 55: * 4) quadradically rehash into other cylinder groups, until an ! 56: * available block is located. ! 57: * If no block preference is given the following heirarchy is used ! 58: * to allocate a block: ! 59: * 1) allocate a block in the cylinder group that contains the ! 60: * inode for the file. ! 61: * 2) quadradically rehash into other cylinder groups, until an ! 62: * available block is located. ! 63: */ ! 64: alloc(ip, lbn, bpref, size, bnp) ! 65: register struct inode *ip; ! 66: daddr_t lbn, bpref; ! 67: int size; ! 68: daddr_t *bnp; ! 69: { ! 70: daddr_t bno; ! 71: register struct fs *fs; ! 72: register struct buf *bp; ! 73: int cg, error; ! 74: struct ucred *cred = u.u_cred; /* XXX */ ! 75: ! 76: *bnp = 0; ! 77: fs = ip->i_fs; ! 78: if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { ! 79: printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", ! 80: ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); ! 81: panic("alloc: bad size"); ! 82: } ! 83: if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) ! 84: goto nospace; ! 85: if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) ! 86: goto nospace; ! 87: #ifdef QUOTA ! 88: if (error = chkdq(ip, (long)btodb(size), cred, 0)) ! 89: return (error); ! 90: #endif ! 91: if (bpref >= fs->fs_size) ! 92: bpref = 0; ! 93: if (bpref == 0) ! 94: cg = itog(fs, ip->i_number); ! 95: else ! 96: cg = dtog(fs, bpref); ! 97: bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, ! 98: (u_long (*)())alloccg); ! 99: if (bno > 0) { ! 100: ip->i_blocks += btodb(size); ! 101: ip->i_flag |= IUPD|ICHG; ! 102: *bnp = bno; ! 103: return (0); ! 104: } ! 105: nospace: ! 106: fserr(fs, cred->cr_uid, "file system full"); ! 107: uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); ! 108: return (ENOSPC); ! 109: } ! 110: ! 111: /* ! 112: * Reallocate a fragment to a bigger size ! 113: * ! 114: * The number and size of the old block is given, and a preference ! 115: * and new size is also specified. The allocator attempts to extend ! 116: * the original block. Failing that, the regular block allocator is ! 117: * invoked to get an appropriate block. ! 118: */ ! 119: realloccg(ip, lbprev, bpref, osize, nsize, bpp) ! 120: register struct inode *ip; ! 121: off_t lbprev; ! 122: daddr_t bpref; ! 123: int osize, nsize; ! 124: struct buf **bpp; ! 125: { ! 126: register struct fs *fs; ! 127: struct buf *bp, *obp; ! 128: int cg, request; ! 129: daddr_t bprev, bno, bn; ! 130: int i, error, count; ! 131: struct ucred *cred = u.u_cred; /* XXX */ ! 132: ! 133: *bpp = 0; ! 134: fs = ip->i_fs; ! 135: if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || ! 136: (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { ! 137: printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n", ! 138: ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt); ! 139: panic("realloccg: bad size"); ! 140: } ! 141: if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) ! 142: goto nospace; ! 143: if ((bprev = ip->i_db[lbprev]) == 0) { ! 144: printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n", ! 145: ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt); ! 146: panic("realloccg: bad bprev"); ! 147: } ! 148: #ifdef QUOTA ! 149: if (error = chkdq(ip, (long)btodb(nsize - osize), cred, 0)) ! 150: return (error); ! 151: #endif ! 152: /* ! 153: * Allocate the extra space in the buffer. ! 154: */ ! 155: if (error = bread(ITOV(ip), lbprev, osize, NOCRED, &bp)) { ! 156: brelse(bp); ! 157: return (error); ! 158: } ! 159: brealloc(bp, nsize); ! 160: bp->b_flags |= B_DONE; ! 161: bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize); ! 162: /* ! 163: * Check for extension in the existing location. ! 164: */ ! 165: cg = dtog(fs, bprev); ! 166: if (bno = fragextend(ip, cg, (long)bprev, osize, nsize)) { ! 167: if (bp->b_blkno != fsbtodb(fs, bno)) ! 168: panic("bad blockno"); ! 169: ip->i_blocks += btodb(nsize - osize); ! 170: ip->i_flag |= IUPD|ICHG; ! 171: *bpp = bp; ! 172: return (0); ! 173: } ! 174: /* ! 175: * Allocate a new disk location. ! 176: */ ! 177: if (bpref >= fs->fs_size) ! 178: bpref = 0; ! 179: switch ((int)fs->fs_optim) { ! 180: case FS_OPTSPACE: ! 181: /* ! 182: * Allocate an exact sized fragment. Although this makes ! 183: * best use of space, we will waste time relocating it if ! 184: * the file continues to grow. If the fragmentation is ! 185: * less than half of the minimum free reserve, we choose ! 186: * to begin optimizing for time. ! 187: */ ! 188: request = nsize; ! 189: if (fs->fs_minfree < 5 || ! 190: fs->fs_cstotal.cs_nffree > ! 191: fs->fs_dsize * fs->fs_minfree / (2 * 100)) ! 192: break; ! 193: log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n", ! 194: fs->fs_fsmnt); ! 195: fs->fs_optim = FS_OPTTIME; ! 196: break; ! 197: case FS_OPTTIME: ! 198: /* ! 199: * At this point we have discovered a file that is trying ! 200: * to grow a small fragment to a larger fragment. To save ! 201: * time, we allocate a full sized block, then free the ! 202: * unused portion. If the file continues to grow, the ! 203: * `fragextend' call above will be able to grow it in place ! 204: * without further copying. If aberrant programs cause ! 205: * disk fragmentation to grow within 2% of the free reserve, ! 206: * we choose to begin optimizing for space. ! 207: */ ! 208: request = fs->fs_bsize; ! 209: if (fs->fs_cstotal.cs_nffree < ! 210: fs->fs_dsize * (fs->fs_minfree - 2) / 100) ! 211: break; ! 212: log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n", ! 213: fs->fs_fsmnt); ! 214: fs->fs_optim = FS_OPTSPACE; ! 215: break; ! 216: default: ! 217: printf("dev = 0x%x, optim = %d, fs = %s\n", ! 218: ip->i_dev, fs->fs_optim, fs->fs_fsmnt); ! 219: panic("realloccg: bad optim"); ! 220: /* NOTREACHED */ ! 221: } ! 222: bno = (daddr_t)hashalloc(ip, cg, (long)bpref, request, ! 223: (u_long (*)())alloccg); ! 224: if (bno > 0) { ! 225: bp->b_blkno = bn = fsbtodb(fs, bno); ! 226: count = howmany(osize, CLBYTES); ! 227: for (i = 0; i < count; i++) ! 228: munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); ! 229: blkfree(ip, bprev, (off_t)osize); ! 230: if (nsize < request) ! 231: blkfree(ip, bno + numfrags(fs, nsize), ! 232: (off_t)(request - nsize)); ! 233: ip->i_blocks += btodb(nsize - osize); ! 234: ip->i_flag |= IUPD|ICHG; ! 235: *bpp = bp; ! 236: return (0); ! 237: } ! 238: brelse(bp); ! 239: nospace: ! 240: /* ! 241: * no space available ! 242: */ ! 243: fserr(fs, cred->cr_uid, "file system full"); ! 244: uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); ! 245: return (ENOSPC); ! 246: } ! 247: ! 248: /* ! 249: * Allocate an inode in the file system. ! 250: * ! 251: * A preference may be optionally specified. If a preference is given ! 252: * the following hierarchy is used to allocate an inode: ! 253: * 1) allocate the requested inode. ! 254: * 2) allocate an inode in the same cylinder group. ! 255: * 3) quadradically rehash into other cylinder groups, until an ! 256: * available inode is located. ! 257: * If no inode preference is given the following heirarchy is used ! 258: * to allocate an inode: ! 259: * 1) allocate an inode in cylinder group 0. ! 260: * 2) quadradically rehash into other cylinder groups, until an ! 261: * available inode is located. ! 262: */ ! 263: ialloc(pip, ipref, mode, cred, ipp) ! 264: register struct inode *pip; ! 265: ino_t ipref; ! 266: int mode; ! 267: struct ucred *cred; ! 268: struct inode **ipp; ! 269: { ! 270: ino_t ino; ! 271: register struct fs *fs; ! 272: register struct inode *ip; ! 273: int cg, error; ! 274: ! 275: *ipp = 0; ! 276: fs = pip->i_fs; ! 277: if (fs->fs_cstotal.cs_nifree == 0) ! 278: goto noinodes; ! 279: if (ipref >= fs->fs_ncg * fs->fs_ipg) ! 280: ipref = 0; ! 281: cg = itog(fs, ipref); ! 282: ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); ! 283: if (ino == 0) ! 284: goto noinodes; ! 285: error = iget(pip, ino, ipp); ! 286: if (error) { ! 287: ifree(pip, ino, mode); ! 288: return (error); ! 289: } ! 290: ip = *ipp; ! 291: if (ip->i_mode) { ! 292: printf("mode = 0%o, inum = %d, fs = %s\n", ! 293: ip->i_mode, ip->i_number, fs->fs_fsmnt); ! 294: panic("ialloc: dup alloc"); ! 295: } ! 296: if (ip->i_blocks) { /* XXX */ ! 297: printf("free inode %s/%d had %d blocks\n", ! 298: fs->fs_fsmnt, ino, ip->i_blocks); ! 299: ip->i_blocks = 0; ! 300: } ! 301: ip->i_flags = 0; ! 302: /* ! 303: * Set up a new generation number for this inode. ! 304: */ ! 305: if (++nextgennumber < (u_long)time.tv_sec) ! 306: nextgennumber = time.tv_sec; ! 307: ip->i_gen = nextgennumber; ! 308: return (0); ! 309: noinodes: ! 310: fserr(fs, cred->cr_uid, "out of inodes"); ! 311: uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); ! 312: return (ENOSPC); ! 313: } ! 314: ! 315: /* ! 316: * Find a cylinder to place a directory. ! 317: * ! 318: * The policy implemented by this algorithm is to select from ! 319: * among those cylinder groups with above the average number of ! 320: * free inodes, the one with the smallest number of directories. ! 321: */ ! 322: ino_t ! 323: dirpref(fs) ! 324: register struct fs *fs; ! 325: { ! 326: int cg, minndir, mincg, avgifree; ! 327: ! 328: avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; ! 329: minndir = fs->fs_ipg; ! 330: mincg = 0; ! 331: for (cg = 0; cg < fs->fs_ncg; cg++) ! 332: if (fs->fs_cs(fs, cg).cs_ndir < minndir && ! 333: fs->fs_cs(fs, cg).cs_nifree >= avgifree) { ! 334: mincg = cg; ! 335: minndir = fs->fs_cs(fs, cg).cs_ndir; ! 336: } ! 337: return ((ino_t)(fs->fs_ipg * mincg)); ! 338: } ! 339: ! 340: /* ! 341: * Select the desired position for the next block in a file. The file is ! 342: * logically divided into sections. The first section is composed of the ! 343: * direct blocks. Each additional section contains fs_maxbpg blocks. ! 344: * ! 345: * If no blocks have been allocated in the first section, the policy is to ! 346: * request a block in the same cylinder group as the inode that describes ! 347: * the file. If no blocks have been allocated in any other section, the ! 348: * policy is to place the section in a cylinder group with a greater than ! 349: * average number of free blocks. An appropriate cylinder group is found ! 350: * by using a rotor that sweeps the cylinder groups. When a new group of ! 351: * blocks is needed, the sweep begins in the cylinder group following the ! 352: * cylinder group from which the previous allocation was made. The sweep ! 353: * continues until a cylinder group with greater than the average number ! 354: * of free blocks is found. If the allocation is for the first block in an ! 355: * indirect block, the information on the previous allocation is unavailable; ! 356: * here a best guess is made based upon the logical block number being ! 357: * allocated. ! 358: * ! 359: * If a section is already partially allocated, the policy is to ! 360: * contiguously allocate fs_maxcontig blocks. The end of one of these ! 361: * contiguous blocks and the beginning of the next is physically separated ! 362: * so that the disk head will be in transit between them for at least ! 363: * fs_rotdelay milliseconds. This is to allow time for the processor to ! 364: * schedule another I/O transfer. ! 365: */ ! 366: daddr_t ! 367: blkpref(ip, lbn, indx, bap) ! 368: struct inode *ip; ! 369: daddr_t lbn; ! 370: int indx; ! 371: daddr_t *bap; ! 372: { ! 373: register struct fs *fs; ! 374: register int cg; ! 375: int avgbfree, startcg; ! 376: daddr_t nextblk; ! 377: ! 378: fs = ip->i_fs; ! 379: if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { ! 380: if (lbn < NDADDR) { ! 381: cg = itog(fs, ip->i_number); ! 382: return (fs->fs_fpg * cg + fs->fs_frag); ! 383: } ! 384: /* ! 385: * Find a cylinder with greater than average number of ! 386: * unused data blocks. ! 387: */ ! 388: if (indx == 0 || bap[indx - 1] == 0) ! 389: startcg = itog(fs, ip->i_number) + lbn / fs->fs_maxbpg; ! 390: else ! 391: startcg = dtog(fs, bap[indx - 1]) + 1; ! 392: startcg %= fs->fs_ncg; ! 393: avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; ! 394: for (cg = startcg; cg < fs->fs_ncg; cg++) ! 395: if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { ! 396: fs->fs_cgrotor = cg; ! 397: return (fs->fs_fpg * cg + fs->fs_frag); ! 398: } ! 399: for (cg = 0; cg <= startcg; cg++) ! 400: if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { ! 401: fs->fs_cgrotor = cg; ! 402: return (fs->fs_fpg * cg + fs->fs_frag); ! 403: } ! 404: return (NULL); ! 405: } ! 406: /* ! 407: * One or more previous blocks have been laid out. If less ! 408: * than fs_maxcontig previous blocks are contiguous, the ! 409: * next block is requested contiguously, otherwise it is ! 410: * requested rotationally delayed by fs_rotdelay milliseconds. ! 411: */ ! 412: nextblk = bap[indx - 1] + fs->fs_frag; ! 413: if (indx > fs->fs_maxcontig && ! 414: bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig) ! 415: != nextblk) ! 416: return (nextblk); ! 417: if (fs->fs_rotdelay != 0) ! 418: /* ! 419: * Here we convert ms of delay to frags as: ! 420: * (frags) = (ms) * (rev/sec) * (sect/rev) / ! 421: * ((sect/frag) * (ms/sec)) ! 422: * then round up to the next block. ! 423: */ ! 424: nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / ! 425: (NSPF(fs) * 1000), fs->fs_frag); ! 426: return (nextblk); ! 427: } ! 428: ! 429: /* ! 430: * Implement the cylinder overflow algorithm. ! 431: * ! 432: * The policy implemented by this algorithm is: ! 433: * 1) allocate the block in its requested cylinder group. ! 434: * 2) quadradically rehash on the cylinder group number. ! 435: * 3) brute force search for a free block. ! 436: */ ! 437: /*VARARGS5*/ ! 438: u_long ! 439: hashalloc(ip, cg, pref, size, allocator) ! 440: struct inode *ip; ! 441: int cg; ! 442: long pref; ! 443: int size; /* size for data blocks, mode for inodes */ ! 444: u_long (*allocator)(); ! 445: { ! 446: register struct fs *fs; ! 447: long result; ! 448: int i, icg = cg; ! 449: ! 450: fs = ip->i_fs; ! 451: /* ! 452: * 1: preferred cylinder group ! 453: */ ! 454: result = (*allocator)(ip, cg, pref, size); ! 455: if (result) ! 456: return (result); ! 457: /* ! 458: * 2: quadratic rehash ! 459: */ ! 460: for (i = 1; i < fs->fs_ncg; i *= 2) { ! 461: cg += i; ! 462: if (cg >= fs->fs_ncg) ! 463: cg -= fs->fs_ncg; ! 464: result = (*allocator)(ip, cg, 0, size); ! 465: if (result) ! 466: return (result); ! 467: } ! 468: /* ! 469: * 3: brute force search ! 470: * Note that we start at i == 2, since 0 was checked initially, ! 471: * and 1 is always checked in the quadratic rehash. ! 472: */ ! 473: cg = (icg + 2) % fs->fs_ncg; ! 474: for (i = 2; i < fs->fs_ncg; i++) { ! 475: result = (*allocator)(ip, cg, 0, size); ! 476: if (result) ! 477: return (result); ! 478: cg++; ! 479: if (cg == fs->fs_ncg) ! 480: cg = 0; ! 481: } ! 482: return (NULL); ! 483: } ! 484: ! 485: /* ! 486: * Determine whether a fragment can be extended. ! 487: * ! 488: * Check to see if the necessary fragments are available, and ! 489: * if they are, allocate them. ! 490: */ ! 491: daddr_t ! 492: fragextend(ip, cg, bprev, osize, nsize) ! 493: struct inode *ip; ! 494: int cg; ! 495: long bprev; ! 496: int osize, nsize; ! 497: { ! 498: register struct fs *fs; ! 499: register struct cg *cgp; ! 500: struct buf *bp; ! 501: long bno; ! 502: int frags, bbase; ! 503: int i, error; ! 504: ! 505: fs = ip->i_fs; ! 506: if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize)) ! 507: return (NULL); ! 508: frags = numfrags(fs, nsize); ! 509: bbase = fragnum(fs, bprev); ! 510: if (bbase > fragnum(fs, (bprev + frags - 1))) { ! 511: /* cannot extend across a block boundary */ ! 512: return (NULL); ! 513: } ! 514: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), ! 515: (int)fs->fs_cgsize, NOCRED, &bp); ! 516: if (error) { ! 517: brelse(bp); ! 518: return (NULL); ! 519: } ! 520: cgp = bp->b_un.b_cg; ! 521: if (!cg_chkmagic(cgp)) { ! 522: brelse(bp); ! 523: return (NULL); ! 524: } ! 525: cgp->cg_time = time.tv_sec; ! 526: bno = dtogd(fs, bprev); ! 527: for (i = numfrags(fs, osize); i < frags; i++) ! 528: if (isclr(cg_blksfree(cgp), bno + i)) { ! 529: brelse(bp); ! 530: return (NULL); ! 531: } ! 532: /* ! 533: * the current fragment can be extended ! 534: * deduct the count on fragment being extended into ! 535: * increase the count on the remaining fragment (if any) ! 536: * allocate the extended piece ! 537: */ ! 538: for (i = frags; i < fs->fs_frag - bbase; i++) ! 539: if (isclr(cg_blksfree(cgp), bno + i)) ! 540: break; ! 541: cgp->cg_frsum[i - numfrags(fs, osize)]--; ! 542: if (i != frags) ! 543: cgp->cg_frsum[i - frags]++; ! 544: for (i = numfrags(fs, osize); i < frags; i++) { ! 545: clrbit(cg_blksfree(cgp), bno + i); ! 546: cgp->cg_cs.cs_nffree--; ! 547: fs->fs_cstotal.cs_nffree--; ! 548: fs->fs_cs(fs, cg).cs_nffree--; ! 549: } ! 550: fs->fs_fmod++; ! 551: bdwrite(bp); ! 552: return (bprev); ! 553: } ! 554: ! 555: /* ! 556: * Determine whether a block can be allocated. ! 557: * ! 558: * Check to see if a block of the apprpriate size is available, ! 559: * and if it is, allocate it. ! 560: */ ! 561: daddr_t ! 562: alloccg(ip, cg, bpref, size) ! 563: struct inode *ip; ! 564: int cg; ! 565: daddr_t bpref; ! 566: int size; ! 567: { ! 568: register struct fs *fs; ! 569: register struct cg *cgp; ! 570: struct buf *bp; ! 571: register int i; ! 572: int error, bno, frags, allocsiz; ! 573: ! 574: fs = ip->i_fs; ! 575: if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) ! 576: return (NULL); ! 577: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), ! 578: (int)fs->fs_cgsize, NOCRED, &bp); ! 579: if (error) { ! 580: brelse(bp); ! 581: return (NULL); ! 582: } ! 583: cgp = bp->b_un.b_cg; ! 584: if (!cg_chkmagic(cgp) || ! 585: (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { ! 586: brelse(bp); ! 587: return (NULL); ! 588: } ! 589: cgp->cg_time = time.tv_sec; ! 590: if (size == fs->fs_bsize) { ! 591: bno = alloccgblk(fs, cgp, bpref); ! 592: bdwrite(bp); ! 593: return (bno); ! 594: } ! 595: /* ! 596: * check to see if any fragments are already available ! 597: * allocsiz is the size which will be allocated, hacking ! 598: * it down to a smaller size if necessary ! 599: */ ! 600: frags = numfrags(fs, size); ! 601: for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) ! 602: if (cgp->cg_frsum[allocsiz] != 0) ! 603: break; ! 604: if (allocsiz == fs->fs_frag) { ! 605: /* ! 606: * no fragments were available, so a block will be ! 607: * allocated, and hacked up ! 608: */ ! 609: if (cgp->cg_cs.cs_nbfree == 0) { ! 610: brelse(bp); ! 611: return (NULL); ! 612: } ! 613: bno = alloccgblk(fs, cgp, bpref); ! 614: bpref = dtogd(fs, bno); ! 615: for (i = frags; i < fs->fs_frag; i++) ! 616: setbit(cg_blksfree(cgp), bpref + i); ! 617: i = fs->fs_frag - frags; ! 618: cgp->cg_cs.cs_nffree += i; ! 619: fs->fs_cstotal.cs_nffree += i; ! 620: fs->fs_cs(fs, cg).cs_nffree += i; ! 621: fs->fs_fmod++; ! 622: cgp->cg_frsum[i]++; ! 623: bdwrite(bp); ! 624: return (bno); ! 625: } ! 626: bno = mapsearch(fs, cgp, bpref, allocsiz); ! 627: if (bno < 0) { ! 628: brelse(bp); ! 629: return (NULL); ! 630: } ! 631: for (i = 0; i < frags; i++) ! 632: clrbit(cg_blksfree(cgp), bno + i); ! 633: cgp->cg_cs.cs_nffree -= frags; ! 634: fs->fs_cstotal.cs_nffree -= frags; ! 635: fs->fs_cs(fs, cg).cs_nffree -= frags; ! 636: fs->fs_fmod++; ! 637: cgp->cg_frsum[allocsiz]--; ! 638: if (frags != allocsiz) ! 639: cgp->cg_frsum[allocsiz - frags]++; ! 640: bdwrite(bp); ! 641: return (cg * fs->fs_fpg + bno); ! 642: } ! 643: ! 644: /* ! 645: * Allocate a block in a cylinder group. ! 646: * ! 647: * This algorithm implements the following policy: ! 648: * 1) allocate the requested block. ! 649: * 2) allocate a rotationally optimal block in the same cylinder. ! 650: * 3) allocate the next available block on the block rotor for the ! 651: * specified cylinder group. ! 652: * Note that this routine only allocates fs_bsize blocks; these ! 653: * blocks may be fragmented by the routine that allocates them. ! 654: */ ! 655: daddr_t ! 656: alloccgblk(fs, cgp, bpref) ! 657: register struct fs *fs; ! 658: register struct cg *cgp; ! 659: daddr_t bpref; ! 660: { ! 661: daddr_t bno; ! 662: int cylno, pos, delta; ! 663: short *cylbp; ! 664: register int i; ! 665: ! 666: if (bpref == 0) { ! 667: bpref = cgp->cg_rotor; ! 668: goto norot; ! 669: } ! 670: bpref = blknum(fs, bpref); ! 671: bpref = dtogd(fs, bpref); ! 672: /* ! 673: * if the requested block is available, use it ! 674: */ ! 675: if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bpref))) { ! 676: bno = bpref; ! 677: goto gotit; ! 678: } ! 679: /* ! 680: * check for a block available on the same cylinder ! 681: */ ! 682: cylno = cbtocylno(fs, bpref); ! 683: if (cg_blktot(cgp)[cylno] == 0) ! 684: goto norot; ! 685: if (fs->fs_cpc == 0) { ! 686: /* ! 687: * block layout info is not available, so just have ! 688: * to take any block in this cylinder. ! 689: */ ! 690: bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); ! 691: goto norot; ! 692: } ! 693: /* ! 694: * check the summary information to see if a block is ! 695: * available in the requested cylinder starting at the ! 696: * requested rotational position and proceeding around. ! 697: */ ! 698: cylbp = cg_blks(fs, cgp, cylno); ! 699: pos = cbtorpos(fs, bpref); ! 700: for (i = pos; i < fs->fs_nrpos; i++) ! 701: if (cylbp[i] > 0) ! 702: break; ! 703: if (i == fs->fs_nrpos) ! 704: for (i = 0; i < pos; i++) ! 705: if (cylbp[i] > 0) ! 706: break; ! 707: if (cylbp[i] > 0) { ! 708: /* ! 709: * found a rotational position, now find the actual ! 710: * block. A panic if none is actually there. ! 711: */ ! 712: pos = cylno % fs->fs_cpc; ! 713: bno = (cylno - pos) * fs->fs_spc / NSPB(fs); ! 714: if (fs_postbl(fs, pos)[i] == -1) { ! 715: printf("pos = %d, i = %d, fs = %s\n", ! 716: pos, i, fs->fs_fsmnt); ! 717: panic("alloccgblk: cyl groups corrupted"); ! 718: } ! 719: for (i = fs_postbl(fs, pos)[i];; ) { ! 720: if (isblock(fs, cg_blksfree(cgp), bno + i)) { ! 721: bno = blkstofrags(fs, (bno + i)); ! 722: goto gotit; ! 723: } ! 724: delta = fs_rotbl(fs)[i]; ! 725: if (delta <= 0 || ! 726: delta + i > fragstoblks(fs, fs->fs_fpg)) ! 727: break; ! 728: i += delta; ! 729: } ! 730: printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt); ! 731: panic("alloccgblk: can't find blk in cyl"); ! 732: } ! 733: norot: ! 734: /* ! 735: * no blocks in the requested cylinder, so take next ! 736: * available one in this cylinder group. ! 737: */ ! 738: bno = mapsearch(fs, cgp, bpref, (int)fs->fs_frag); ! 739: if (bno < 0) ! 740: return (NULL); ! 741: cgp->cg_rotor = bno; ! 742: gotit: ! 743: clrblock(fs, cg_blksfree(cgp), (long)fragstoblks(fs, bno)); ! 744: cgp->cg_cs.cs_nbfree--; ! 745: fs->fs_cstotal.cs_nbfree--; ! 746: fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; ! 747: cylno = cbtocylno(fs, bno); ! 748: cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--; ! 749: cg_blktot(cgp)[cylno]--; ! 750: fs->fs_fmod++; ! 751: return (cgp->cg_cgx * fs->fs_fpg + bno); ! 752: } ! 753: ! 754: /* ! 755: * Determine whether an inode can be allocated. ! 756: * ! 757: * Check to see if an inode is available, and if it is, ! 758: * allocate it using the following policy: ! 759: * 1) allocate the requested inode. ! 760: * 2) allocate the next available inode after the requested ! 761: * inode in the specified cylinder group. ! 762: */ ! 763: ino_t ! 764: ialloccg(ip, cg, ipref, mode) ! 765: struct inode *ip; ! 766: int cg; ! 767: daddr_t ipref; ! 768: int mode; ! 769: { ! 770: register struct fs *fs; ! 771: register struct cg *cgp; ! 772: struct buf *bp; ! 773: int error, start, len, loc, map, i; ! 774: ! 775: fs = ip->i_fs; ! 776: if (fs->fs_cs(fs, cg).cs_nifree == 0) ! 777: return (NULL); ! 778: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), ! 779: (int)fs->fs_cgsize, NOCRED, &bp); ! 780: if (error) { ! 781: brelse(bp); ! 782: return (NULL); ! 783: } ! 784: cgp = bp->b_un.b_cg; ! 785: if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) { ! 786: brelse(bp); ! 787: return (NULL); ! 788: } ! 789: cgp->cg_time = time.tv_sec; ! 790: if (ipref) { ! 791: ipref %= fs->fs_ipg; ! 792: if (isclr(cg_inosused(cgp), ipref)) ! 793: goto gotit; ! 794: } ! 795: start = cgp->cg_irotor / NBBY; ! 796: len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY); ! 797: loc = skpc(0xff, len, &cg_inosused(cgp)[start]); ! 798: if (loc == 0) { ! 799: len = start + 1; ! 800: start = 0; ! 801: loc = skpc(0xff, len, &cg_inosused(cgp)[0]); ! 802: if (loc == 0) { ! 803: printf("cg = %s, irotor = %d, fs = %s\n", ! 804: cg, cgp->cg_irotor, fs->fs_fsmnt); ! 805: panic("ialloccg: map corrupted"); ! 806: /* NOTREACHED */ ! 807: } ! 808: } ! 809: i = start + len - loc; ! 810: map = cg_inosused(cgp)[i]; ! 811: ipref = i * NBBY; ! 812: for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) { ! 813: if ((map & i) == 0) { ! 814: cgp->cg_irotor = ipref; ! 815: goto gotit; ! 816: } ! 817: } ! 818: printf("fs = %s\n", fs->fs_fsmnt); ! 819: panic("ialloccg: block not in map"); ! 820: /* NOTREACHED */ ! 821: gotit: ! 822: setbit(cg_inosused(cgp), ipref); ! 823: cgp->cg_cs.cs_nifree--; ! 824: fs->fs_cstotal.cs_nifree--; ! 825: fs->fs_cs(fs, cg).cs_nifree--; ! 826: fs->fs_fmod++; ! 827: if ((mode & IFMT) == IFDIR) { ! 828: cgp->cg_cs.cs_ndir++; ! 829: fs->fs_cstotal.cs_ndir++; ! 830: fs->fs_cs(fs, cg).cs_ndir++; ! 831: } ! 832: bdwrite(bp); ! 833: return (cg * fs->fs_ipg + ipref); ! 834: } ! 835: ! 836: /* ! 837: * Free a block or fragment. ! 838: * ! 839: * The specified block or fragment is placed back in the ! 840: * free map. If a fragment is deallocated, a possible ! 841: * block reassembly is checked. ! 842: */ ! 843: blkfree(ip, bno, size) ! 844: register struct inode *ip; ! 845: daddr_t bno; ! 846: off_t size; ! 847: { ! 848: register struct fs *fs; ! 849: register struct cg *cgp; ! 850: struct buf *bp; ! 851: int error, cg, blk, frags, bbase; ! 852: register int i; ! 853: struct ucred *cred = u.u_cred; /* XXX */ ! 854: ! 855: fs = ip->i_fs; ! 856: if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { ! 857: printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", ! 858: ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); ! 859: panic("blkfree: bad size"); ! 860: } ! 861: cg = dtog(fs, bno); ! 862: if ((unsigned)bno >= fs->fs_size) { ! 863: printf("bad block %d, ino %d\n", bno, ip->i_number); ! 864: fserr(fs, cred->cr_uid, "bad block"); ! 865: return; ! 866: } ! 867: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), ! 868: (int)fs->fs_cgsize, NOCRED, &bp); ! 869: if (error) { ! 870: brelse(bp); ! 871: return; ! 872: } ! 873: cgp = bp->b_un.b_cg; ! 874: if (!cg_chkmagic(cgp)) { ! 875: brelse(bp); ! 876: return; ! 877: } ! 878: cgp->cg_time = time.tv_sec; ! 879: bno = dtogd(fs, bno); ! 880: if (size == fs->fs_bsize) { ! 881: if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno))) { ! 882: printf("dev = 0x%x, block = %d, fs = %s\n", ! 883: ip->i_dev, bno, fs->fs_fsmnt); ! 884: panic("blkfree: freeing free block"); ! 885: } ! 886: setblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno)); ! 887: cgp->cg_cs.cs_nbfree++; ! 888: fs->fs_cstotal.cs_nbfree++; ! 889: fs->fs_cs(fs, cg).cs_nbfree++; ! 890: i = cbtocylno(fs, bno); ! 891: cg_blks(fs, cgp, i)[cbtorpos(fs, bno)]++; ! 892: cg_blktot(cgp)[i]++; ! 893: } else { ! 894: bbase = bno - fragnum(fs, bno); ! 895: /* ! 896: * decrement the counts associated with the old frags ! 897: */ ! 898: blk = blkmap(fs, cg_blksfree(cgp), bbase); ! 899: fragacct(fs, blk, cgp->cg_frsum, -1); ! 900: /* ! 901: * deallocate the fragment ! 902: */ ! 903: frags = numfrags(fs, size); ! 904: for (i = 0; i < frags; i++) { ! 905: if (isset(cg_blksfree(cgp), bno + i)) { ! 906: printf("dev = 0x%x, block = %d, fs = %s\n", ! 907: ip->i_dev, bno + i, fs->fs_fsmnt); ! 908: panic("blkfree: freeing free frag"); ! 909: } ! 910: setbit(cg_blksfree(cgp), bno + i); ! 911: } ! 912: cgp->cg_cs.cs_nffree += i; ! 913: fs->fs_cstotal.cs_nffree += i; ! 914: fs->fs_cs(fs, cg).cs_nffree += i; ! 915: /* ! 916: * add back in counts associated with the new frags ! 917: */ ! 918: blk = blkmap(fs, cg_blksfree(cgp), bbase); ! 919: fragacct(fs, blk, cgp->cg_frsum, 1); ! 920: /* ! 921: * if a complete block has been reassembled, account for it ! 922: */ ! 923: if (isblock(fs, cg_blksfree(cgp), ! 924: (daddr_t)fragstoblks(fs, bbase))) { ! 925: cgp->cg_cs.cs_nffree -= fs->fs_frag; ! 926: fs->fs_cstotal.cs_nffree -= fs->fs_frag; ! 927: fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; ! 928: cgp->cg_cs.cs_nbfree++; ! 929: fs->fs_cstotal.cs_nbfree++; ! 930: fs->fs_cs(fs, cg).cs_nbfree++; ! 931: i = cbtocylno(fs, bbase); ! 932: cg_blks(fs, cgp, i)[cbtorpos(fs, bbase)]++; ! 933: cg_blktot(cgp)[i]++; ! 934: } ! 935: } ! 936: fs->fs_fmod++; ! 937: bdwrite(bp); ! 938: } ! 939: ! 940: /* ! 941: * Free an inode. ! 942: * ! 943: * The specified inode is placed back in the free map. ! 944: */ ! 945: ifree(ip, ino, mode) ! 946: struct inode *ip; ! 947: ino_t ino; ! 948: int mode; ! 949: { ! 950: register struct fs *fs; ! 951: register struct cg *cgp; ! 952: struct buf *bp; ! 953: int error, cg; ! 954: ! 955: fs = ip->i_fs; ! 956: if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) { ! 957: printf("dev = 0x%x, ino = %d, fs = %s\n", ! 958: ip->i_dev, ino, fs->fs_fsmnt); ! 959: panic("ifree: range"); ! 960: } ! 961: cg = itog(fs, ino); ! 962: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), ! 963: (int)fs->fs_cgsize, NOCRED, &bp); ! 964: if (error) { ! 965: brelse(bp); ! 966: return; ! 967: } ! 968: cgp = bp->b_un.b_cg; ! 969: if (!cg_chkmagic(cgp)) { ! 970: brelse(bp); ! 971: return; ! 972: } ! 973: cgp->cg_time = time.tv_sec; ! 974: ino %= fs->fs_ipg; ! 975: if (isclr(cg_inosused(cgp), ino)) { ! 976: printf("dev = 0x%x, ino = %d, fs = %s\n", ! 977: ip->i_dev, ino, fs->fs_fsmnt); ! 978: panic("ifree: freeing free inode"); ! 979: } ! 980: clrbit(cg_inosused(cgp), ino); ! 981: if (ino < cgp->cg_irotor) ! 982: cgp->cg_irotor = ino; ! 983: cgp->cg_cs.cs_nifree++; ! 984: fs->fs_cstotal.cs_nifree++; ! 985: fs->fs_cs(fs, cg).cs_nifree++; ! 986: if ((mode & IFMT) == IFDIR) { ! 987: cgp->cg_cs.cs_ndir--; ! 988: fs->fs_cstotal.cs_ndir--; ! 989: fs->fs_cs(fs, cg).cs_ndir--; ! 990: } ! 991: fs->fs_fmod++; ! 992: bdwrite(bp); ! 993: } ! 994: ! 995: /* ! 996: * Find a block of the specified size in the specified cylinder group. ! 997: * ! 998: * It is a panic if a request is made to find a block if none are ! 999: * available. ! 1000: */ ! 1001: daddr_t ! 1002: mapsearch(fs, cgp, bpref, allocsiz) ! 1003: register struct fs *fs; ! 1004: register struct cg *cgp; ! 1005: daddr_t bpref; ! 1006: int allocsiz; ! 1007: { ! 1008: daddr_t bno; ! 1009: int start, len, loc, i; ! 1010: int blk, field, subfield, pos; ! 1011: ! 1012: /* ! 1013: * find the fragment by searching through the free block ! 1014: * map for an appropriate bit pattern ! 1015: */ ! 1016: if (bpref) ! 1017: start = dtogd(fs, bpref) / NBBY; ! 1018: else ! 1019: start = cgp->cg_frotor / NBBY; ! 1020: len = howmany(fs->fs_fpg, NBBY) - start; ! 1021: loc = scanc((unsigned)len, (u_char *)&cg_blksfree(cgp)[start], ! 1022: (u_char *)fragtbl[fs->fs_frag], ! 1023: (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); ! 1024: if (loc == 0) { ! 1025: len = start + 1; ! 1026: start = 0; ! 1027: loc = scanc((unsigned)len, (u_char *)&cg_blksfree(cgp)[0], ! 1028: (u_char *)fragtbl[fs->fs_frag], ! 1029: (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); ! 1030: if (loc == 0) { ! 1031: printf("start = %d, len = %d, fs = %s\n", ! 1032: start, len, fs->fs_fsmnt); ! 1033: panic("alloccg: map corrupted"); ! 1034: /* NOTREACHED */ ! 1035: } ! 1036: } ! 1037: bno = (start + len - loc) * NBBY; ! 1038: cgp->cg_frotor = bno; ! 1039: /* ! 1040: * found the byte in the map ! 1041: * sift through the bits to find the selected frag ! 1042: */ ! 1043: for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { ! 1044: blk = blkmap(fs, cg_blksfree(cgp), bno); ! 1045: blk <<= 1; ! 1046: field = around[allocsiz]; ! 1047: subfield = inside[allocsiz]; ! 1048: for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { ! 1049: if ((blk & field) == subfield) ! 1050: return (bno + pos); ! 1051: field <<= 1; ! 1052: subfield <<= 1; ! 1053: } ! 1054: } ! 1055: printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt); ! 1056: panic("alloccg: block not in map"); ! 1057: return (-1); ! 1058: } ! 1059: ! 1060: /* ! 1061: * Fserr prints the name of a file system with an error diagnostic. ! 1062: * ! 1063: * The form of the error message is: ! 1064: * fs: error message ! 1065: */ ! 1066: fserr(fs, uid, cp) ! 1067: struct fs *fs; ! 1068: uid_t uid; ! 1069: char *cp; ! 1070: { ! 1071: ! 1072: log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp); ! 1073: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.