|
|
1.1 ! root 1: /* alloc.c 4.8 81/03/08 */ ! 2: ! 3: #include "../h/param.h" ! 4: #include "../h/systm.h" ! 5: #include "../h/mount.h" ! 6: #include "../h/filsys.h" ! 7: #include "../h/fblk.h" ! 8: #include "../h/conf.h" ! 9: #include "../h/buf.h" ! 10: #include "../h/inode.h" ! 11: #include "../h/ino.h" ! 12: #include "../h/dir.h" ! 13: #include "../h/user.h" ! 14: #include "../h/trace.h" ! 15: typedef struct fblk *FP; ! 16: ! 17: /* ! 18: * alloc will obtain the next available ! 19: * free disk block from the free list of ! 20: * the specified filsys. ! 21: * The super block has up to NICFREE remembered ! 22: * free blocks; the last of these is read to ! 23: * obtain NICFREE more . . . ! 24: */ ! 25: struct buf * ! 26: alloc(fip, prev) ! 27: struct inode *fip; ! 28: daddr_t prev; ! 29: { ! 30: daddr_t bno; ! 31: register struct filsys *fp; ! 32: register struct buf *bp; ! 33: register int i, j; ! 34: register long *p; ! 35: ! 36: fp = getfs(fip); ! 37: while (fp->s_flock) ! 38: sleep((caddr_t)&fp->s_flock, PINOD); ! 39: if(BITFS(fip->i_dev)) { /* unfortunately device dependent */ ! 40: /* this code is UGLY, fix it */ ! 41: if(prev < fp->s_isize) ! 42: goto scan; ! 43: /* try for an acceptable free block in next ! 44: * three cylinders, then start over at the beginning */ ! 45: bno = 0; ! 46: j = prev/(4*10); ! 47: j *= 4 * 10; ! 48: if(j < fp->s_isize) ! 49: j = fp->s_isize; ! 50: j -= fp->s_isize; ! 51: for(i = 0; i < 3 * 4 * 10; i++, j++) { ! 52: if(j >= fp->s_fsize - fp->s_isize) ! 53: break; ! 54: if(!(fp->s_bfree[j>>5] & (1 << (j&31)))) ! 55: continue; ! 56: /* same cylinder? */ ! 57: if((j+fp->s_isize)/(4*10) != prev/(4*10)) { /* take best */ ! 58: if(bno == 0) ! 59: bno = j; ! 60: fp->s_bfree[bno>>5] &= ~(1 << (bno&31)); ! 61: bno += fp->s_isize; ! 62: goto found; ! 63: } ! 64: bno = j; ! 65: p = fp->s_bfree + (j>>5); ! 66: /* same sector or next, continue */ ! 67: if((j+fp->s_isize)%4 != prev%4 && (j+fp->s_isize)%4 != (prev+1)%4) { ! 68: *p &= ~(1 << (j&31)); ! 69: bno += fp->s_isize; ! 70: goto found; ! 71: } ! 72: } ! 73: /* did we find anything? */ ! 74: if(bno != 0) { ! 75: fp->s_bfree[bno>>5] &= ~(1 << (bno&31)); ! 76: bno += fp->s_isize; ! 77: goto found; ! 78: } ! 79: scan: ! 80: p = fp->s_bfree; ! 81: for(i = 0; i < BITMAP && !*p; i++, p++) ! 82: ; ! 83: if(i >= BITMAP) ! 84: goto nospace; ! 85: bno = fp->s_isize + 32 * i; ! 86: for(j = 0; j < 32; j++) /* BITS PER LONG */ ! 87: if(*p & (1 << j)) ! 88: break; ! 89: if(j >= 32) ! 90: panic("alloc bitmap"); ! 91: bno += j; ! 92: if(bno >= fp->s_fsize) ! 93: goto nospace; ! 94: *p &= ~(1 << j); ! 95: if(fp->s_valid) { /* was valid, isn't anymore */ ! 96: fp->s_valid = 0; ! 97: update(); /* GROSS, but safe */ ! 98: } ! 99: } ! 100: else { ! 101: do { ! 102: if (fp->s_nfree <= 0) ! 103: goto nospace; ! 104: if (fp->s_nfree > NICFREE) { ! 105: fserr(fp, "bad free count"); ! 106: goto nospace; ! 107: } ! 108: bno = fp->s_free[--fp->s_nfree]; ! 109: if (bno == 0) ! 110: goto nospace; ! 111: } while (badblock(fp, bno)); ! 112: if (fp->s_nfree <= 0) { ! 113: fp->s_flock++; ! 114: bp = bread(fip->i_dev, bno); ! 115: if ((bp->b_flags&B_ERROR) == 0) { ! 116: fp->s_nfree = ((FP)(bp->b_un.b_addr))->df_nfree; ! 117: bcopy((caddr_t)((FP)(bp->b_un.b_addr))->df_free, ! 118: (caddr_t)fp->s_free, sizeof(fp->s_free)); ! 119: } ! 120: brelse(bp); ! 121: fp->s_flock = 0; ! 122: wakeup((caddr_t)&fp->s_flock); ! 123: if (fp->s_nfree <= 0) ! 124: goto nospace; ! 125: } ! 126: } ! 127: found: ! 128: bp = getblk(fip->i_dev, bno); ! 129: clrbuf(bp); ! 130: fp->s_fmod = 1; ! 131: fp->s_tfree--; ! 132: return (bp); ! 133: ! 134: nospace: ! 135: fp->s_nfree = 0; ! 136: fp->s_tfree = 0; ! 137: fserr(fp, "file system full"); ! 138: /* THIS IS A KLUDGE... */ ! 139: /* SHOULD RATHER SEND A SIGNAL AND SUSPEND THE PROCESS IN A */ ! 140: /* STATE FROM WHICH THE SYSTEM CALL WILL RESTART */ ! 141: uprintf("\n%s: write failed, file system is full\n", fp->s_fsmnt); ! 142: for (i = 0; i < 5; i++) ! 143: sleep((caddr_t)&lbolt, PRIBIO); ! 144: /* END KLUDGE */ ! 145: u.u_error = ENOSPC; ! 146: return (NULL); ! 147: } ! 148: ! 149: /* ! 150: * place the specified disk block ! 151: * back on the free list of the ! 152: * specified device. ! 153: */ ! 154: free(fip, bno) ! 155: struct inode *fip; ! 156: daddr_t bno; ! 157: { ! 158: register struct filsys *fp; ! 159: register struct buf *bp; ! 160: ! 161: fp = getfs(fip); ! 162: fp->s_fmod = 1; ! 163: while (fp->s_flock) ! 164: sleep((caddr_t)&fp->s_flock, PINOD); ! 165: if (badblock(fp, bno)) ! 166: return; ! 167: if(BITFS(fip->i_dev)) { ! 168: bno -= fp->s_isize; ! 169: fp->s_bfree[bno/32] |= (1 << (bno % 32)); ! 170: if(fp->s_valid) { /* not any more */ ! 171: fp->s_valid = 0; ! 172: update(); /* even GROSSER */ ! 173: } ! 174: } ! 175: else { ! 176: if (fp->s_nfree <= 0) { ! 177: fp->s_nfree = 1; ! 178: fp->s_free[0] = 0; ! 179: } ! 180: if (fp->s_nfree >= NICFREE) { ! 181: fp->s_flock++; ! 182: bp = getblk(fip->i_dev, bno); ! 183: ((FP)(bp->b_un.b_addr))->df_nfree = fp->s_nfree; ! 184: bcopy((caddr_t)fp->s_free, ! 185: (caddr_t)((FP)(bp->b_un.b_addr))->df_free, ! 186: sizeof(fp->s_free)); ! 187: fp->s_nfree = 0; ! 188: bwrite(bp); ! 189: fp->s_flock = 0; ! 190: wakeup((caddr_t)&fp->s_flock); ! 191: } ! 192: fp->s_free[fp->s_nfree++] = bno; ! 193: } ! 194: fp->s_tfree++; ! 195: fp->s_fmod = 1; ! 196: } ! 197: ! 198: /* ! 199: * Check that a block number is in the ! 200: * range between the I list and the size ! 201: * of the device. ! 202: * This is used mainly to check that a ! 203: * garbage file system has not been mounted. ! 204: */ ! 205: badblock(fp, bn) ! 206: register struct filsys *fp; ! 207: daddr_t bn; ! 208: { ! 209: ! 210: if (bn < fp->s_isize || bn >= fp->s_fsize) { ! 211: fserr(fp, "bad block"); ! 212: return(1); ! 213: } ! 214: return(0); ! 215: } ! 216: ! 217: /* ! 218: * Allocate an unused inode on the specified device. ! 219: * Used with file creation. The algorithm keeps up to ! 220: * NICINOD spare inodes in the super block. When this runs out, ! 221: * the inodes are searched to pick up more. We keep searching ! 222: * foreward on the device, remembering the number of inodes ! 223: * which are freed behind our search point for which there is no ! 224: * room in the in-core table. When this number passes a threshold ! 225: * (or if we search to the end of the ilist without finding any inodes) ! 226: * we restart the search from the beginning. ! 227: */ ! 228: ! 229: struct inode * ! 230: ialloc(fip) ! 231: struct inode *fip; ! 232: { ! 233: register struct filsys *fp; ! 234: register struct buf *bp; ! 235: register struct inode *ip; ! 236: register int i; ! 237: struct dinode *dp; ! 238: ino_t ino, inobas; ! 239: int first; ! 240: daddr_t adr; ! 241: ! 242: fp = getfs(fip); ! 243: while (fp->s_ilock) ! 244: sleep((caddr_t)&fp->s_ilock, PINOD); ! 245: fp->s_ilock++; ! 246: loop: ! 247: if (fp->s_ninode > 0) { ! 248: ino = fp->s_inode[--fp->s_ninode]; ! 249: ip = iget(fip, fip->i_dev, ino); ! 250: if (ip == NULL) { ! 251: fp->s_ilock = 0; ! 252: wakeup((caddr_t)&fp->s_ilock); ! 253: return(NULL); ! 254: } ! 255: if (ip->i_mode == 0 && ip->i_number > ROOTINO) { ! 256: for (i=0; i<NADDR; i++) ! 257: ip->i_un.i_addr[i] = 0; ! 258: fp->s_tinode--; ! 259: fp->s_fmod = 1; ! 260: fp->s_ilock = 0; ! 261: wakeup((caddr_t)&fp->s_ilock); ! 262: return(ip); ! 263: } ! 264: /* ! 265: * Inode was allocated after all. ! 266: * Look some more. ! 267: */ ! 268: iput(ip); ! 269: goto loop; ! 270: } ! 271: /* ! 272: * If less than 4*NICINOD inodes are known ! 273: * to be free behind the current search point, ! 274: * then search forward; else search from beginning. ! 275: */ ! 276: if (fp->s_nbehind < 4 * NICINOD) { ! 277: first = 1; ! 278: ino = fp->s_lasti; ! 279: if(ino <= ROOTINO) ! 280: goto fromtop; ! 281: if (itod(fip->i_dev, ino) >= fp->s_isize) ! 282: panic("ialloc"); ! 283: adr = itod(fip->i_dev, ino); ! 284: } else { ! 285: fromtop: ! 286: first = 0; ! 287: ino = 1; ! 288: adr = SUPERB+1; ! 289: fp->s_nbehind = 0; ! 290: } ! 291: /* ! 292: * This is the search for free inodes. ! 293: */ ! 294: for(; adr < fp->s_isize; adr++) { ! 295: inobas = ino; ! 296: bp = bread(fip->i_dev, adr); ! 297: if ((bp->b_flags&B_CACHE) == 0) ! 298: u.u_vm.vm_inblk--; /* no charge! */ ! 299: if (bp->b_flags & B_ERROR) { ! 300: brelse(bp); ! 301: ino += INOPB(fip->i_dev); ! 302: continue; ! 303: } ! 304: dp = bp->b_un.b_dino; ! 305: for (i=0; i<INOPB(fip->i_dev); i++, ino++, dp++) { ! 306: if (dp->di_mode != 0 || ifind(fip, ino)) ! 307: continue; ! 308: if (ino > ROOTINO) ! 309: fp->s_inode[fp->s_ninode++] = ino; ! 310: if (fp->s_ninode >= NICINOD) ! 311: break; ! 312: } ! 313: brelse(bp); ! 314: if (fp->s_ninode >= NICINOD) ! 315: break; ! 316: } ! 317: /* ! 318: * If the search didn't net a full superblock of inodes, ! 319: * then try it again from the beginning of the ilist. ! 320: */ ! 321: if (fp->s_ninode < NICINOD && first) ! 322: goto fromtop; ! 323: fp->s_lasti = inobas; ! 324: fp->s_ilock = 0; ! 325: wakeup((caddr_t)&fp->s_ilock); ! 326: if (fp->s_ninode > 0) ! 327: goto loop; ! 328: fserr(fp, "out of inodes"); ! 329: uprintf("\n%s: create failed, no inodes free\n", fp->s_fsmnt); ! 330: u.u_error = ENOSPC; ! 331: return (NULL); ! 332: } ! 333: ! 334: /* ! 335: * Free the specified inode on the specified device. ! 336: * The algorithm stores up to NICINOD inodes in the super ! 337: * block and throws away any more. It keeps track of the ! 338: * number of inodes thrown away which preceded the current ! 339: * search point in the file system. This lets us rescan ! 340: * for more inodes from the beginning only when there ! 341: * are a reasonable number of inodes back there to reallocate. ! 342: */ ! 343: ! 344: ifree(fip, ino) ! 345: struct inode *fip; ! 346: ino_t ino; ! 347: { ! 348: register struct filsys *fp; ! 349: ! 350: if(ino <= ROOTINO) ! 351: return; ! 352: fp = getfs(fip); ! 353: fp->s_tinode++; ! 354: if (fp->s_ilock) ! 355: return; ! 356: if (fp->s_ninode >= NICINOD) { ! 357: if (fp->s_lasti > ino) ! 358: fp->s_nbehind++; ! 359: return; ! 360: } ! 361: fp->s_inode[fp->s_ninode++] = ino; ! 362: fp->s_fmod = 1; ! 363: } ! 364: ! 365: /* ! 366: * getfs maps an inode into ! 367: * a pointer to the incore super ! 368: * block. ! 369: * A consistency check of the ! 370: * in core free-block and i-node ! 371: * counts is performed. ! 372: * ! 373: * panic: no fs -- the device is not mounted. ! 374: * this "cannot happen" ! 375: */ ! 376: struct filsys * ! 377: getfs(fip) ! 378: register struct inode *fip; ! 379: { ! 380: register struct filsys *fp; ! 381: ! 382: if (fip->i_fstyp != 0 || fip->i_un.i_bufp == NULL) ! 383: panic("no fs"); ! 384: fp = fip->i_un.i_bufp->b_un.b_filsys; ! 385: if (fp->s_nfree > NICFREE || fp->s_ninode > NICINOD) { ! 386: fserr(fp, "bad count"); ! 387: fp->s_nfree = 0; ! 388: fp->s_ninode = 0; ! 389: } ! 390: return(fp); ! 391: } ! 392: ! 393: /* ! 394: * Fserr prints the name of a file system ! 395: * with an error diagnostic, in the form ! 396: * filsys: error message ! 397: */ ! 398: fserr(fp, cp) ! 399: struct filsys *fp; ! 400: char *cp; ! 401: { ! 402: ! 403: printf("%s: %s\n", fp->s_fsmnt, cp); ! 404: } ! 405: ! 406: /* ! 407: * Getfsx returns the index in the file system ! 408: * table of the specified device. The swap device ! 409: * is also assigned a pseudo-index. The index may ! 410: * be used as a compressed indication of the location ! 411: * of a block, recording ! 412: * <getfsx(dev),blkno> ! 413: * rather than ! 414: * <dev, blkno> ! 415: * provided the information need remain valid only ! 416: * as long as the file system is mounted. ! 417: * ! 418: * only the vm code calls this. ! 419: */ ! 420: getfsx(dev) ! 421: dev_t dev; ! 422: { ! 423: register struct mount *mp; ! 424: ! 425: if (dev == swapdev) ! 426: return (MSWAPX); ! 427: mp = findmount(0, dev); ! 428: if (mp == NULL) ! 429: return (-1); ! 430: return (mp - &mount[0]); ! 431: } ! 432: ! 433: /* ! 434: * Update is the internal name of 'sync'. It goes through the disk ! 435: * queues to initiate sandbagged IO; goes through the inodes to write ! 436: * modified nodes; and it goes through the mount table to initiate modified ! 437: * super blocks. ! 438: */ ! 439: update() ! 440: { ! 441: register struct inode *ip; ! 442: ! 443: if (updlock) ! 444: return; ! 445: updlock++; ! 446: /* ! 447: * Write back each (modified) inode. ! 448: */ ! 449: for (ip = inode; ip < inodeNINODE; ip++) ! 450: if((ip->i_flag&ILOCK)==0 && ip->i_count) { ! 451: ip->i_flag |= ILOCK; ! 452: ip->i_count++; ! 453: iupdat(ip, &time, &time, 0); ! 454: iput(ip); ! 455: } ! 456: updlock = 0; ! 457: /* ! 458: * Force stale buffer cache information to be flushed, ! 459: * for all devices. ! 460: */ ! 461: trace(TR_BFIN, updlock, 0); ! 462: bflush(NODEV); ! 463: trace(TR_BFOUT, updlock, 0); ! 464: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.