1 #include "types.h" 2 #include "stat.h" 3 #include "param.h" 4 #include "x86.h" 5 #include "mmu.h" 6 #include "proc.h" 7 #include "defs.h" 8 #include "spinlock.h" 9 #include "buf.h" 10 #include "fs.h" 11 #include "fsvar.h" 12 #include "dev.h" 13 14 // these are inodes currently in use 15 // an entry is free if count == 0 16 struct inode inode[NINODE]; 17 struct spinlock inode_table_lock; 18 19 uint rootdev = 1; 20 21 void 22 iinit(void) 23 { 24 initlock(&inode_table_lock, "inode_table"); 25 } 26 27 /* 28 * allocate a disk block 29 */ 30 static uint 31 balloc(uint dev) 32 { 33 int b; 34 struct buf *bp; 35 struct superblock *sb; 36 int bi = 0; 37 int size; 38 int ninodes; 39 uchar m; 40 41 bp = bread(dev, 1); 42 sb = (struct superblock*) bp->data; 43 size = sb->size; 44 ninodes = sb->ninodes; 45 46 for(b = 0; b < size; b++) { 47 if(b % BPB == 0) { 48 brelse(bp); 49 bp = bread(dev, BBLOCK(b, ninodes)); 50 } 51 bi = b % BPB; 52 m = 0x1 << (bi % 8); 53 if((bp->data[bi/8] & m) == 0) { // is block free? 54 break; 55 } 56 } 57 if(b >= size) 58 panic("balloc: out of blocks"); 59 60 bp->data[bi/8] |= 0x1 << (bi % 8); 61 bwrite(bp, BBLOCK(b, ninodes)); // mark it allocated on disk 62 brelse(bp); 63 return b; 64 } 65 66 static void 67 bfree(int dev, uint b) 68 { 69 struct buf *bp; 70 struct superblock *sb; 71 int bi; 72 int ninodes; 73 uchar m; 74 75 bp = bread(dev, 1); 76 sb = (struct superblock*) bp->data; 77 ninodes = sb->ninodes; 78 brelse(bp); 79 80 bp = bread(dev, b); 81 memset(bp->data, 0, BSIZE); 82 bwrite(bp, b); 83 brelse(bp); 84 85 bp = bread(dev, BBLOCK(b, ninodes)); 86 bi = b % BPB; 87 m = ~(0x1 << (bi %8)); 88 bp->data[bi/8] &= m; 89 bwrite(bp, BBLOCK(b, ninodes)); // mark it free on disk 90 brelse(bp); 91 } 92 93 /* 94 * fetch an inode, from the in-core table if it's already 95 * in use, otherwise read from the disk. 96 * returns an inode with busy set and incremented reference count. 97 */ 98 struct inode* 99 iget(uint dev, uint inum) 100 { 101 struct inode *ip, *nip; 102 struct dinode *dip; 103 struct buf *bp; 104 105 acquire(&inode_table_lock); 106 107 loop: 108 nip = 0; 109 for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ 110 if(ip->count > 0 && ip->dev == dev && ip->inum == inum){ 111 if(ip->busy){ 112 sleep(ip, &inode_table_lock); 113 goto loop; 114 } 115 ip->count++; 116 ip->busy = 1; 117 release(&inode_table_lock); 118 return ip; 119 } 120 if(nip == 0 && ip->count == 0) 121 nip = ip; 122 } 123 124 if(nip == 0) 125 panic("out of inodes"); 126 127 nip->dev = dev; 128 nip->inum = inum; 129 nip->count = 1; 130 nip->busy = 1; 131 132 release(&inode_table_lock); 133 134 bp = bread(dev, IBLOCK(inum)); 135 dip = &((struct dinode*)(bp->data))[inum % IPB]; 136 nip->type = dip->type; 137 nip->major = dip->major; 138 nip->minor = dip->minor; 139 nip->nlink = dip->nlink; 140 nip->size = dip->size; 141 memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); 142 brelse(bp); 143 144 return nip; 145 } 146 147 void 148 iupdate(struct inode *ip) 149 { 150 struct buf *bp; 151 struct dinode *dip; 152 153 bp = bread(ip->dev, IBLOCK(ip->inum)); 154 dip = &((struct dinode*)(bp->data))[ip->inum % IPB]; 155 dip->type = ip->type; 156 dip->major = ip->major; 157 dip->minor = ip->minor; 158 dip->nlink = ip->nlink; 159 dip->size = ip->size; 160 memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); 161 bwrite(bp, IBLOCK(ip->inum)); // mark it allocated on the disk 162 brelse(bp); 163 } 164 165 struct inode* 166 ialloc(uint dev, short type) 167 { 168 struct inode *ip; 169 struct dinode *dip = 0; 170 struct superblock *sb; 171 int ninodes; 172 int inum; 173 struct buf *bp; 174 175 bp = bread(dev, 1); 176 sb = (struct superblock*) bp->data; 177 ninodes = sb->ninodes; 178 brelse(bp); 179 180 for(inum = 1; inum < ninodes; inum++) { // loop over inode blocks 181 bp = bread(dev, IBLOCK(inum)); 182 dip = &((struct dinode*)(bp->data))[inum % IPB]; 183 if(dip->type == 0) { // a free inode 184 break; 185 } 186 brelse(bp); 187 } 188 189 if(inum >= ninodes) 190 panic("ialloc: no inodes left"); 191 192 memset(dip, 0, sizeof(*dip)); 193 dip->type = type; 194 bwrite(bp, IBLOCK(inum)); // mark it allocated on the disk 195 brelse(bp); 196 ip = iget(dev, inum); 197 return ip; 198 } 199 200 static void 201 ifree(struct inode *ip) 202 { 203 ip->type = 0; 204 iupdate(ip); 205 } 206 207 void 208 ilock(struct inode *ip) 209 { 210 if(ip->count < 1) 211 panic("ilock"); 212 213 acquire(&inode_table_lock); 214 215 while(ip->busy) 216 sleep(ip, &inode_table_lock); 217 ip->busy = 1; 218 219 release(&inode_table_lock); 220 } 221 222 // caller is holding onto a reference to this inode, but no 223 // longer needs to examine or change it, so clear ip->busy. 224 void 225 iunlock(struct inode *ip) 226 { 227 if(ip->busy != 1 || ip->count < 1) 228 panic("iunlock"); 229 230 acquire(&inode_table_lock); 231 232 ip->busy = 0; 233 wakeup(ip); 234 235 release(&inode_table_lock); 236 } 237 238 uint 239 bmap(struct inode *ip, uint bn) 240 { 241 unsigned x; 242 uint *a; 243 struct buf *inbp; 244 245 if(bn >= MAXFILE) 246 panic("bmap 1"); 247 if(bn < NDIRECT) { 248 x = ip->addrs[bn]; 249 if(x == 0) 250 panic("bmap 2"); 251 } else { 252 if(ip->addrs[INDIRECT] == 0) 253 panic("bmap 3"); 254 inbp = bread(ip->dev, ip->addrs[INDIRECT]); 255 a = (uint*) inbp->data; 256 x = a[bn - NDIRECT]; 257 brelse(inbp); 258 if(x == 0) 259 panic("bmap 4"); 260 } 261 return x; 262 } 263 264 void 265 itrunc(struct inode *ip) 266 { 267 int i, j; 268 struct buf *inbp; 269 270 for(i = 0; i < NADDRS; i++) { 271 if(ip->addrs[i] != 0) { 272 if(i == INDIRECT) { 273 inbp = bread(ip->dev, ip->addrs[INDIRECT]); 274 uint *a = (uint*) inbp->data; 275 for(j = 0; j < NINDIRECT; j++) { 276 if(a[j] != 0) { 277 bfree(ip->dev, a[j]); 278 a[j] = 0; 279 } 280 } 281 brelse(inbp); 282 } 283 bfree(ip->dev, ip->addrs[i]); 284 ip->addrs[i] = 0; 285 } 286 } 287 ip->size = 0; 288 iupdate(ip); 289 } 290 291 // caller is releasing a reference to this inode. 292 // you must have the inode lock. 293 void 294 iput(struct inode *ip) 295 { 296 if(ip->count < 1 || ip->busy != 1) 297 panic("iput"); 298 299 if((ip->count == 1) && (ip->nlink == 0)) { 300 itrunc(ip); 301 ifree(ip); 302 } 303 304 acquire(&inode_table_lock); 305 306 ip->count -= 1; 307 ip->busy = 0; 308 wakeup(ip); 309 310 release(&inode_table_lock); 311 } 312 313 void 314 idecref(struct inode *ip) 315 { 316 ilock(ip); 317 iput(ip); 318 } 319 320 void 321 iincref(struct inode *ip) 322 { 323 ilock(ip); 324 ip->count++; 325 iunlock(ip); 326 } 327 328 void 329 stati(struct inode *ip, struct stat *st) 330 { 331 st->st_dev = ip->dev; 332 st->st_ino = ip->inum; 333 st->st_type = ip->type; 334 st->st_nlink = ip->nlink; 335 st->st_size = ip->size; 336 } 337 338 #define min(a, b) ((a) < (b) ? (a) : (b)) 339 340 int 341 readi(struct inode *ip, char *dst, uint off, uint n) 342 { 343 uint target = n, n1; 344 struct buf *bp; 345 346 if(ip->type == T_DEV) { 347 if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_read) 348 return -1; 349 return devsw[ip->major].d_read(ip->minor, dst, n); 350 } 351 352 while(n > 0 && off < ip->size){ 353 bp = bread(ip->dev, bmap(ip, off / BSIZE)); 354 n1 = min(n, ip->size - off); 355 n1 = min(n1, BSIZE - (off % BSIZE)); 356 memmove(dst, bp->data + (off % BSIZE), n1); 357 n -= n1; 358 off += n1; 359 dst += n1; 360 brelse(bp); 361 } 362 363 return target - n; 364 } 365 366 static int 367 newblock(struct inode *ip, uint lbn) 368 { 369 struct buf *inbp; 370 uint *inaddrs; 371 uint b; 372 373 if(lbn < NDIRECT) { 374 if(ip->addrs[lbn] == 0) { 375 b = balloc(ip->dev); 376 if(b <= 0) return -1; 377 ip->addrs[lbn] = b; 378 } 379 } else { 380 if(ip->addrs[INDIRECT] == 0) { 381 b = balloc(ip->dev); 382 if(b <= 0) return -1; 383 ip->addrs[INDIRECT] = b; 384 } 385 inbp = bread(ip->dev, ip->addrs[INDIRECT]); 386 inaddrs = (uint*) inbp->data; 387 if(inaddrs[lbn - NDIRECT] == 0) { 388 b = balloc(ip->dev); 389 if(b <= 0) return -1; 390 inaddrs[lbn - NDIRECT] = b; 391 bwrite(inbp, ip->addrs[INDIRECT]); 392 } 393 brelse(inbp); 394 } 395 return 0; 396 } 397 398 int 399 writei(struct inode *ip, char *addr, uint off, uint n) 400 { 401 if(ip->type == T_DEV) { 402 if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write) 403 return -1; 404 return devsw[ip->major].d_write(ip->minor, addr, n); 405 } else if(ip->type == T_FILE || ip->type == T_DIR) { 406 struct buf *bp; 407 int r = 0; 408 int m; 409 int lbn; 410 while(r < n) { 411 lbn = off / BSIZE; 412 if(lbn >= MAXFILE) return r; 413 if(newblock(ip, lbn) < 0) { 414 cprintf("newblock failed\n"); 415 return r; 416 } 417 m = min(BSIZE - off % BSIZE, n-r); 418 bp = bread(ip->dev, bmap(ip, lbn)); 419 memmove(bp->data + off % BSIZE, addr, m); 420 bwrite(bp, bmap(ip, lbn)); 421 brelse(bp); 422 r += m; 423 off += m; 424 } 425 if(r > 0) { 426 if(off > ip->size) { 427 if(ip->type == T_DIR) ip->size = ((off / BSIZE) + 1) * BSIZE; 428 else ip->size = off; 429 } 430 iupdate(ip); 431 } 432 return r; 433 } else { 434 panic("writei: unknown type"); 435 return 0; 436 } 437 } 438 439 // look up a path name, in one of three modes. 440 // NAMEI_LOOKUP: return locked target inode. 441 // NAMEI_CREATE: return locked parent inode. 442 // return 0 if name does exist. 443 // *ret_last points to last path component (i.e. new file name). 444 // *ret_ip points to the the name that did exist, if it did. 445 // *ret_ip and *ret_last may be zero even if return value is zero. 446 // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off. 447 // return 0 if name doesn't exist. 448 struct inode* 449 namei(char *path, int mode, uint *ret_off, char **ret_last, struct inode **ret_ip) 450 { 451 struct inode *dp; 452 struct proc *p = curproc[cpu()]; 453 char *cp = path, *cp1; 454 uint off, dev; 455 struct buf *bp; 456 struct dirent *ep; 457 int i, atend; 458 unsigned ninum; 459 460 if(ret_off) 461 *ret_off = 0xffffffff; 462 if(ret_last) 463 *ret_last = 0; 464 if(ret_ip) 465 *ret_ip = 0; 466 467 if(*cp == '/') dp = iget(rootdev, 1); 468 else { 469 dp = p->cwd; 470 iincref(dp); 471 ilock(dp); 472 } 473 474 while(*cp == '/') 475 cp++; 476 477 while(1){ 478 if(*cp == '\0'){ 479 if(mode == NAMEI_LOOKUP) 480 return dp; 481 if(mode == NAMEI_CREATE && ret_ip){ 482 *ret_ip = dp; 483 return 0; 484 } 485 iput(dp); 486 return 0; 487 } 488 489 if(dp->type != T_DIR){ 490 iput(dp); 491 return 0; 492 } 493 494 for(off = 0; off < dp->size; off += BSIZE){ 495 bp = bread(dp->dev, bmap(dp, off / BSIZE)); 496 for(ep = (struct dirent*) bp->data; 497 ep < (struct dirent*) (bp->data + BSIZE); 498 ep++){ 499 if(ep->inum == 0) 500 continue; 501 for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++) 502 if(cp[i] != ep->name[i]) 503 break; 504 if((cp[i] == '\0' || cp[i] == '/' || i >= DIRSIZ) && 505 (i >= DIRSIZ || ep->name[i] == '\0')){ 506 while(cp[i] != '\0' && cp[i] != '/') 507 i++; 508 off += (uchar*)ep - bp->data; 509 ninum = ep->inum; 510 brelse(bp); 511 cp += i; 512 goto found; 513 } 514 } 515 brelse(bp); 516 } 517 atend = 1; 518 for(cp1 = cp; *cp1; cp1++) 519 if(*cp1 == '/') 520 atend = 0; 521 if(mode == NAMEI_CREATE && atend){ 522 if(*cp == '\0'){ 523 iput(dp); 524 return 0; 525 } 526 *ret_last = cp; 527 return dp; 528 } 529 530 iput(dp); 531 return 0; 532 533 found: 534 if(mode == NAMEI_DELETE && *cp == '\0'){ 535 *ret_off = off; 536 return dp; 537 } 538 dev = dp->dev; 539 iput(dp); 540 dp = iget(dev, ninum); 541 if(dp->type == 0 || dp->nlink < 1) 542 panic("namei"); 543 while(*cp == '/') 544 cp++; 545 } 546 } 547 548 void 549 wdir(struct inode *dp, char *name, uint ino) 550 { 551 uint off; 552 struct dirent de; 553 int i; 554 555 for(off = 0; off < dp->size; off += sizeof(de)){ 556 if(readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de)) 557 panic("wdir read"); 558 if(de.inum == 0) 559 break; 560 } 561 562 de.inum = ino; 563 for(i = 0; i < DIRSIZ && name[i]; i++) 564 de.name[i] = name[i]; 565 for( ; i < DIRSIZ; i++) 566 de.name[i] = '\0'; 567 568 if(writei(dp, (char*) &de, off, sizeof(de)) != sizeof(de)) 569 panic("wdir write"); 570 } 571 572 struct inode* 573 mknod(char *cp, short type, short major, short minor) 574 { 575 struct inode *ip, *dp; 576 char *last; 577 578 if((dp = namei(cp, NAMEI_CREATE, 0, &last, 0)) == 0) 579 return 0; 580 581 ip = mknod1(dp, last, type, major, minor); 582 583 iput(dp); 584 585 return ip; 586 } 587 588 struct inode* 589 mknod1(struct inode *dp, char *name, short type, short major, short minor) 590 { 591 struct inode *ip; 592 593 ip = ialloc(dp->dev, type); 594 if(ip == 0) 595 return 0; 596 ip->major = major; 597 ip->minor = minor; 598 ip->size = 0; 599 ip->nlink = 1; 600 601 iupdate(ip); // write new inode to disk 602 603 wdir(dp, name, ip->inum); 604 605 return ip; 606 } 607 608 int 609 unlink(char *cp) 610 { 611 struct inode *ip, *dp; 612 struct dirent de; 613 uint off, inum, dev; 614 615 dp = namei(cp, NAMEI_DELETE, &off, 0, 0); 616 if(dp == 0) 617 return -1; 618 619 dev = dp->dev; 620 621 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0) 622 panic("unlink no entry"); 623 624 inum = de.inum; 625 626 memset(&de, 0, sizeof(de)); 627 if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 628 panic("unlink dir write"); 629 630 iupdate(dp); 631 iput(dp); 632 633 ip = iget(dev, inum); 634 635 if(ip->nlink < 1) 636 panic("unlink nlink < 1"); 637 638 ip->nlink--; 639 640 iupdate(ip); 641 iput(ip); 642 643 return 0; 644 } 645 646 int 647 link(char *name1, char *name2) 648 { 649 struct inode *ip, *dp; 650 char *last; 651 652 if((ip = namei(name1, NAMEI_LOOKUP, 0, 0, 0)) == 0) 653 return -1; 654 if(ip->type == T_DIR){ 655 iput(ip); 656 return -1; 657 } 658 659 iunlock(ip); 660 661 if((dp = namei(name2, NAMEI_CREATE, 0, &last, 0)) == 0) { 662 idecref(ip); 663 return -1; 664 } 665 if(dp->dev != ip->dev){ 666 idecref(ip); 667 iput(dp); 668 return -1; 669 } 670 671 ilock(ip); 672 ip->nlink += 1; 673 iupdate(ip); 674 675 wdir(dp, last, ip->inum); 676 iput(dp); 677 iput(ip); 678 679 return 0; 680 } 681