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