Xv6 with picoc & Linkage editor  v1.0
The project delineate mutual cohesion between c library, linkage editor ( linker), interpreter and operating system by porting the same on xv6 kernel
fs.c
00001 // File system implementation.  Five layers:
00002 //   + Blocks: allocator for raw disk blocks.
00003 //   + Log: crash recovery for multi-step updates.
00004 //   + Files: inode allocator, reading, writing, metadata.
00005 //   + Directories: inode with special contents (list of other inodes!)
00006 //   + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.
00007 //
00008 // This file contains the low-level file system manipulation 
00009 // routines.  The (higher-level) system call implementations
00010 // are in sysfile.c.
00011 
00012 #include "types.h"
00013 #include "defs.h"
00014 #include "param.h"
00015 #include "stat.h"
00016 #include "mmu.h"
00017 #include "proc.h"
00018 #include "spinlock.h"
00019 #include "buf.h"
00020 #include "fs.h"
00021 #include "file.h"
00022 
00023 #define min(a, b) ((a) < (b) ? (a) : (b))
00024 static void itrunc(struct inode*);
00025 
00026 // Read the super block.
00027 void
00028 readsb(int dev, struct superblock *sb)
00029 {
00030   struct buf *bp;
00031   
00032   bp = bread(dev, 1);
00033   memmove(sb, bp->data, sizeof(*sb));
00034   brelse(bp);
00035 }
00036 
00037 // Zero a block.
00038 static void
00039 bzero(int dev, int bno)
00040 {
00041   struct buf *bp;
00042   
00043   bp = bread(dev, bno);
00044   memset(bp->data, 0, BSIZE);
00045   log_write(bp);
00046   brelse(bp);
00047 }
00048 
00049 // Blocks. 
00050 
00051 // Allocate a zeroed disk block.
00052 static uint
00053 balloc(uint dev)
00054 {
00055   int b, bi, m;
00056   struct buf *bp;
00057   struct superblock sb;
00058 
00059   bp = 0;
00060   readsb(dev, &sb);
00061   for(b = 0; b < sb.size; b += BPB){
00062     bp = bread(dev, BBLOCK(b, sb.ninodes));
00063     for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
00064       m = 1 << (bi % 8);
00065       if((bp->data[bi/8] & m) == 0){  // Is block free?
00066         bp->data[bi/8] |= m;  // Mark block in use.
00067         log_write(bp);
00068         brelse(bp);
00069         bzero(dev, b + bi);
00070         return b + bi;
00071       }
00072     }
00073     brelse(bp);
00074   }
00075   cprintf("problem is there");
00076   panic("balloc: out of blocks");
00077 }
00078 
00079 // Free a disk block.
00080 static void
00081 bfree(int dev, uint b)
00082 {
00083   struct buf *bp;
00084   struct superblock sb;
00085   int bi, m;
00086 
00087   readsb(dev, &sb);
00088   bp = bread(dev, BBLOCK(b, sb.ninodes));
00089   bi = b % BPB;
00090   m = 1 << (bi % 8);
00091   if((bp->data[bi/8] & m) == 0){
00092     cprintf("while freeing value of b is %d\n",b);
00093     panic("freeing free block");
00094   }
00095   bp->data[bi/8] &= ~m;
00096   log_write(bp);
00097   brelse(bp);
00098 }
00099 
00100 // Inodes.
00101 //
00102 // An inode describes a single unnamed file.
00103 // The inode disk structure holds metadata: the file's type,
00104 // its size, the number of links referring to it, and the
00105 // list of blocks holding the file's content.
00106 //
00107 // The inodes are laid out sequentially on disk immediately after
00108 // the superblock. Each inode has a number, indicating its
00109 // position on the disk.
00110 //
00111 // The kernel keeps a cache of in-use inodes in memory
00112 // to provide a place for synchronizing access
00113 // to inodes used by multiple processes. The cached
00114 // inodes include book-keeping information that is
00115 // not stored on disk: ip->ref and ip->flags.
00116 //
00117 // An inode and its in-memory represtative go through a
00118 // sequence of states before they can be used by the
00119 // rest of the file system code.
00120 //
00121 // * Allocation: an inode is allocated if its type (on disk)
00122 //   is non-zero. ialloc() allocates, iput() frees if
00123 //   the link count has fallen to zero.
00124 //
00125 // * Referencing in cache: an entry in the inode cache
00126 //   is free if ip->ref is zero. Otherwise ip->ref tracks
00127 //   the number of in-memory pointers to the entry (open
00128 //   files and current directories). iget() to find or
00129 //   create a cache entry and increment its ref, iput()
00130 //   to decrement ref.
00131 //
00132 // * Valid: the information (type, size, &c) in an inode
00133 //   cache entry is only correct when the I_VALID bit
00134 //   is set in ip->flags. ilock() reads the inode from
00135 //   the disk and sets I_VALID, while iput() clears
00136 //   I_VALID if ip->ref has fallen to zero.
00137 //
00138 // * Locked: file system code may only examine and modify
00139 //   the information in an inode and its content if it
00140 //   has first locked the inode. The I_BUSY flag indicates
00141 //   that the inode is locked. ilock() sets I_BUSY,
00142 //   while iunlock clears it.
00143 //
00144 // Thus a typical sequence is:
00145 //   ip = iget(dev, inum)
00146 //   ilock(ip)
00147 //   ... examine and modify ip->xxx ...
00148 //   iunlock(ip)
00149 //   iput(ip)
00150 //
00151 // ilock() is separate from iget() so that system calls can
00152 // get a long-term reference to an inode (as for an open file)
00153 // and only lock it for short periods (e.g., in read()).
00154 // The separation also helps avoid deadlock and races during
00155 // pathname lookup. iget() increments ip->ref so that the inode
00156 // stays cached and pointers to it remain valid.
00157 //
00158 // Many internal file system functions expect the caller to
00159 // have locked the inodes involved; this lets callers create
00160 // multi-step atomic operations.
00161 
00162 struct {
00163   struct spinlock lock;
00164   struct inode inode[NINODE];
00165 } icache;
00166 
00167 void
00168 iinit(void)
00169 {
00170   initlock(&icache.lock, "icache");
00171 }
00172 
00173 static struct inode* iget(uint dev, uint inum);
00174 
00175 //PAGEBREAK!
00176 // Allocate a new inode with the given type on device dev.
00177 // A free inode has a type of zero.
00178 struct inode*
00179 ialloc(uint dev, short type)
00180 {
00181   int inum;
00182   struct buf *bp;
00183   struct dinode *dip;
00184   struct superblock sb;
00185 
00186   readsb(dev, &sb);
00187 
00188   for(inum = 1; inum < sb.ninodes; inum++){
00189     bp = bread(dev, IBLOCK(inum));
00190     dip = (struct dinode*)bp->data + inum%IPB;
00191     if(dip->type == 0){  // a free inode
00192       memset(dip, 0, sizeof(*dip));
00193       dip->type = type;
00194       log_write(bp);   // mark it allocated on the disk
00195       brelse(bp);
00196       return iget(dev, inum);
00197     }
00198     brelse(bp);
00199   }
00200   panic("ialloc: no inodes");
00201 }
00202 
00203 // Copy a modified in-memory inode to disk.
00204 void
00205 iupdate(struct inode *ip)
00206 {
00207   struct buf *bp;
00208   struct dinode *dip;
00209 
00210   bp = bread(ip->dev, IBLOCK(ip->inum));
00211   dip = (struct dinode*)bp->data + ip->inum%IPB;
00212   dip->type = ip->type;
00213   dip->major = ip->major;
00214   dip->minor = ip->minor;
00215   dip->nlink = ip->nlink;
00216   dip->size = ip->size;
00217   memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
00218   log_write(bp);
00219   brelse(bp);
00220 }
00221 
00222 // Find the inode with number inum on device dev
00223 // and return the in-memory copy. Does not lock
00224 // the inode and does not read it from disk.
00225 static struct inode*
00226 iget(uint dev, uint inum)
00227 {
00228   struct inode *ip, *empty;
00229 
00230   acquire(&icache.lock);
00231 
00232   // Is the inode already cached?
00233   empty = 0;
00234   for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){
00235     if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
00236       ip->ref++;
00237       release(&icache.lock);
00238       return ip;
00239     }
00240     if(empty == 0 && ip->ref == 0)    // Remember empty slot.
00241       empty = ip;
00242   }
00243 
00244   // Recycle an inode cache entry.
00245   if(empty == 0)
00246     panic("iget: no inodes");
00247 
00248   ip = empty;
00249   ip->dev = dev;
00250   ip->inum = inum;
00251   ip->ref = 1;
00252   ip->flags = 0;
00253   release(&icache.lock);
00254 
00255   return ip;
00256 }
00257 
00258 // Increment reference count for ip.
00259 // Returns ip to enable ip = idup(ip1) idiom.
00260 struct inode*
00261 idup(struct inode *ip)
00262 {
00263   acquire(&icache.lock);
00264   ip->ref++;
00265   release(&icache.lock);
00266   return ip;
00267 }
00268 
00269 // Lock the given inode.
00270 // Reads the inode from disk if necessary.
00271 void
00272 ilock(struct inode *ip)
00273 {
00274   struct buf *bp;
00275   struct dinode *dip;
00276 
00277   if(ip == 0 || ip->ref < 1)
00278     panic("ilock");
00279 
00280   acquire(&icache.lock);
00281   while(ip->flags & I_BUSY)
00282     sleep(ip, &icache.lock);
00283   ip->flags |= I_BUSY;
00284   release(&icache.lock);
00285 
00286   if(!(ip->flags & I_VALID)){
00287     bp = bread(ip->dev, IBLOCK(ip->inum));
00288     dip = (struct dinode*)bp->data + ip->inum%IPB;
00289     ip->type = dip->type;
00290     ip->major = dip->major;
00291     ip->minor = dip->minor;
00292     ip->nlink = dip->nlink;
00293     ip->size = dip->size;
00294     memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
00295     brelse(bp);
00296     ip->flags |= I_VALID;
00297     if(ip->type == 0)
00298       panic("ilock: no type");
00299   }
00300 }
00301 
00302 // Unlock the given inode.
00303 void
00304 iunlock(struct inode *ip)
00305 {
00306   if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1)
00307     panic("iunlock");
00308 
00309   acquire(&icache.lock);
00310   ip->flags &= ~I_BUSY;
00311   wakeup(ip);
00312   release(&icache.lock);
00313 }
00314 
00315 // Drop a reference to an in-memory inode.
00316 // If that was the last reference, the inode cache entry can
00317 // be recycled.
00318 // If that was the last reference and the inode has no links
00319 // to it, free the inode (and its content) on disk.
00320 void
00321 iput(struct inode *ip)
00322 {
00323   acquire(&icache.lock);
00324   if(ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0){
00325     // inode has no links: truncate and free inode.
00326     if(ip->flags & I_BUSY)
00327       panic("iput busy");
00328     ip->flags |= I_BUSY;
00329     release(&icache.lock);
00330     itrunc(ip);
00331     ip->type = 0;
00332     iupdate(ip);
00333     acquire(&icache.lock);
00334     ip->flags = 0;
00335     wakeup(ip);
00336   }
00337   ip->ref--;
00338   release(&icache.lock);
00339 }
00340 
00341 // Common idiom: unlock, then put.
00342 void
00343 iunlockput(struct inode *ip)
00344 {
00345   iunlock(ip);
00346   iput(ip);
00347 }
00348 
00349 //PAGEBREAK!
00350 // Inode content
00351 //
00352 // The content (data) associated with each inode is stored
00353 // in blocks on the disk. The first NDIRECT block numbers
00354 // are listed in ip->addrs[].  The next NINDIRECT blocks are 
00355 // listed in block ip->addrs[NDIRECT].
00356 
00357 // Return the disk block address of the nth block in inode ip.
00358 // If there is no such block, bmap allocates one.
00359 static uint
00360 bmap(struct inode *ip, uint bn)
00361 {
00362 //  cprintf("In bmap function value of bn is %d\n", bn);
00363   uint addr, *a, *b;
00364   struct buf *bp;
00365 
00366   if(bn < NDIRECT - 1){
00367     if((addr = ip->addrs[bn]) == 0)
00368       ip->addrs[bn] = addr = balloc(ip->dev);
00369     return addr;
00370   }
00371   bn -= (NDIRECT - 1) ;
00372 
00373   if(bn < NINDIRECT){
00374     // Load indirect block, allocating if necessary.
00375     if((addr = ip->addrs[NDIRECT - 1]) == 0){
00376       ip->addrs[NDIRECT - 1] = addr = balloc(ip->dev);
00377 //      cprintf("allocating block for 1st single indirect %d\n",addr);
00378     }
00379     bp = bread(ip->dev, addr);
00380     a = (uint*)bp->data;
00381     if((addr = a[bn]) == 0){
00382       a[bn] = addr = balloc(ip->dev);
00383  //     cprintf("allocating block for 2nd single indirect %d\n",addr);
00384       log_write(bp);
00385     }
00386     brelse(bp);
00387     return addr;
00388   }
00389 //*part being added
00390 // this is for double indirect 
00391 
00392 
00393   bn -= NINDIRECT;
00394 //  cprintf("printnig inode\n");
00395 //  for (i = 0 ; i < NDIRECT+2 && flagforme;i++)
00396 //    cprintf("a[%d] = %d\n",i,ip->addrs[i]);
00397   
00398   if(bn < NDINDIRECT){
00399     if((addr = ip->addrs[NDIRECT]) == 0){
00400       ip->addrs[NDIRECT] = addr = balloc(ip->dev);
00401     }
00402     
00403 //    cprintf("1st addr is %d\n", addr);
00404     bp = bread(ip->dev, addr);
00405     a = (uint*)bp->data;
00406 //  cprintf("printing value of a \n");
00407 //  for (i = 0 ; i < NDIRECT+2;i++)
00408 //      cprintf("a[%2d] = %d",a[i]);
00409     
00410     if((addr = a[bn/NINDIRECT]) == 0){
00411       a[bn/NINDIRECT] = addr = balloc(ip->dev);
00412       log_write(bp);
00413     }
00414     brelse(bp);
00415     bp = bread(ip->dev,addr);
00416     b = (uint*)bp->data;
00417     if((addr = b[bn % NINDIRECT]) == 0){
00418         b[bn % NINDIRECT] = addr = balloc(ip->dev);
00419  //       cprintf("allocating block for 3rd double indirect %d \n", addr);
00420         log_write(bp);
00421     }
00422     brelse(bp);
00423     return addr;
00424   }
00425 
00426   panic("bmap: out of range");
00427 }
00428 
00429 // Truncate inode (discard contents).
00430 // Only called when the inode has no links
00431 // to it (no directory entries referring to it)
00432 // and has no in-memory reference to it (is
00433 // not an open file or current directory).
00434 static void
00435 itrunc(struct inode *ip)
00436 {
00437   int i, j,k;
00438   struct buf *bp,*bp1;
00439   uint *a, *b;
00440 
00441   for(i = 0; i < (NDIRECT-1); i++){
00442     if(ip->addrs[i]){
00443       bfree(ip->dev, ip->addrs[i]);
00444       ip->addrs[i] = 0;
00445     }
00446   }
00447 
00448   if(ip->addrs[NDIRECT-1]){
00449     bp = bread(ip->dev, ip->addrs[NDIRECT-1]);
00450     a = (uint*)bp->data;
00451     for(j = 0; j < NINDIRECT; j++){
00452       if(a[j])
00453         bfree(ip->dev,a[j]);
00454     }
00455     brelse(bp);
00456     bfree(ip->dev, ip->addrs[NDIRECT-1]);  
00457     ip->addrs[NDIRECT-1] = 0;
00458   }
00459  
00460   if(ip->addrs[NDIRECT]){
00461     bp = bread(ip->dev, ip->addrs[NDIRECT]);
00462     a = (uint*)bp->data;
00463     for(j = 0; j < NINDIRECT; j++){
00464       if(a[j]){
00465         bp1 = bread(ip->dev, a[j]);
00466         b = (uint*)bp1->data;
00467         for(k = 0; k < NINDIRECT; k++){
00468           if(b[k])
00469             bfree(ip->dev, b[k]);
00470         }
00471         brelse(bp1);
00472         bfree(ip->dev, a[j]);
00473       }
00474     }
00475     brelse(bp);
00476     bfree(ip->dev, ip->addrs[NDIRECT]);
00477     ip->addrs[NDIRECT] = 0;
00478   }
00479 
00480   ip->size = 0;
00481   iupdate(ip);
00482 }
00483 
00484 // Copy stat information from inode.
00485 void
00486 stati(struct inode *ip, struct stat *st)
00487 {
00488   st->dev = ip->dev;
00489   st->ino = ip->inum;
00490   st->type = ip->type;
00491   st->nlink = ip->nlink;
00492   st->size = ip->size;
00493 }
00494 
00495 //PAGEBREAK!
00496 // Read data from inode.
00497 int
00498 readi(struct inode *ip, char *dst, uint off, uint n)
00499 {
00500 //  cprintf("In readi function\n");
00501   uint tot, m;
00502   struct buf *bp;
00503 
00504   if(ip->type == T_DEV){
00505     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)
00506       return -1;
00507     return devsw[ip->major].read(ip, dst, n);
00508   }
00509 
00510   if(off > ip->size || off + n < off)
00511     return -1;
00512   if(off + n > ip->size)
00513     n = ip->size - off;
00514 
00515   for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
00516 //    cprintf("value of readi is %d\n",bmap(ip,off/BSIZE));
00517     bp = bread(ip->dev, bmap(ip, off/BSIZE));
00518     m = min(n - tot, BSIZE - off%BSIZE);
00519     memmove(dst, bp->data + off%BSIZE, m);
00520     brelse(bp);
00521   }
00522   return n;
00523 }
00524 
00525 // PAGEBREAK!
00526 // Write data to inode.
00527 int
00528 writei(struct inode *ip, char *src, uint off, uint n)
00529 {
00530   uint tot, m;
00531   struct buf *bp;
00532   if(ip->type == T_DEV){
00533     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
00534       return -1;
00535     return devsw[ip->major].write(ip, src, n);
00536   }
00537 
00538   if(off > ip->size || off + n < off)
00539     return -1;
00540   if(off + n > MAXFILE*BSIZE)
00541     return -1;
00542 
00543   for(tot=0; tot<n; tot+=m, off+=m, src+=m){
00544     cprintf("value of writei is %d\n",bmap(ip, off/BSIZE));
00545     bp = bread(ip->dev, bmap(ip, off/BSIZE));
00546     m = min(n - tot, BSIZE - off%BSIZE);
00547     memmove(bp->data + off%BSIZE, src, m);
00548     log_write(bp);
00549     brelse(bp);
00550   }
00551 
00552   if(n > 0 && off > ip->size){
00553     ip->size = off;
00554     iupdate(ip);
00555   }
00556   return n;
00557 }
00558 
00559 //PAGEBREAK!
00560 // Directories
00561 
00562 int
00563 namecmp(const char *s, const char *t)
00564 {
00565   return strncmp(s, t, DIRSIZ);
00566 }
00567 
00568 // Look for a directory entry in a directory.
00569 // If found, set *poff to byte offset of entry.
00570 struct inode*
00571 dirlookup(struct inode *dp, char *name, uint *poff)
00572 {
00573   uint off, inum;
00574   struct dirent de;
00575 
00576   if(dp->type != T_DIR)
00577     panic("dirlookup not DIR");
00578 
00579   for(off = 0; off < dp->size; off += sizeof(de)){
00580     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00581       panic("dirlink read");
00582     if(de.inum == 0)
00583       continue;
00584     if(namecmp(name, de.name) == 0){
00585       // entry matches path element
00586       if(poff)
00587         *poff = off;
00588       inum = de.inum;
00589       return iget(dp->dev, inum);
00590     }
00591   }
00592 
00593   return 0;
00594 }
00595 
00596 // Write a new directory entry (name, inum) into the directory dp.
00597 int
00598 dirlink(struct inode *dp, char *name, uint inum)
00599 {
00600   int off;
00601   struct dirent de;
00602   struct inode *ip;
00603 
00604   // Check that name is not present.
00605   if((ip = dirlookup(dp, name, 0)) != 0){
00606     iput(ip);
00607     return -1;
00608   }
00609 
00610   // Look for an empty dirent.
00611   for(off = 0; off < dp->size; off += sizeof(de)){
00612     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00613       panic("dirlink read");
00614     if(de.inum == 0)
00615       break;
00616   }
00617 
00618   strncpy(de.name, name, DIRSIZ);
00619   de.inum = inum;
00620   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00621     panic("dirlink");
00622   
00623   return 0;
00624 }
00625 
00626 //PAGEBREAK!
00627 // Paths
00628 
00629 // Copy the next path element from path into name.
00630 // Return a pointer to the element following the copied one.
00631 // The returned path has no leading slashes,
00632 // so the caller can check *path=='\0' to see if the name is the last one.
00633 // If no name to remove, return 0.
00634 //
00635 // Examples:
00636 //   skipelem("a/bb/c", name) = "bb/c", setting name = "a"
00637 //   skipelem("///a//bb", name) = "bb", setting name = "a"
00638 //   skipelem("a", name) = "", setting name = "a"
00639 //   skipelem("", name) = skipelem("////", name) = 0
00640 //
00641 static char*
00642 skipelem(char *path, char *name)
00643 {
00644   char *s;
00645   int len;
00646 
00647   while(*path == '/')
00648     path++;
00649   if(*path == 0)
00650     return 0;
00651   s = path;
00652   while(*path != '/' && *path != 0)
00653     path++;
00654   len = path - s;
00655   if(len >= DIRSIZ)
00656     memmove(name, s, DIRSIZ);
00657   else {
00658     memmove(name, s, len);
00659     name[len] = 0;
00660   }
00661   while(*path == '/')
00662     path++;
00663   return path;
00664 }
00665 
00666 // Look up and return the inode for a path name.
00667 // If parent != 0, return the inode for the parent and copy the final
00668 // path element into name, which must have room for DIRSIZ bytes.
00669 static struct inode*
00670 namex(char *path, int nameiparent, char *name)
00671 {
00672   struct inode *ip, *next;
00673   if(*path == '/')
00674     ip = iget(ROOTDEV, ROOTINO);
00675   else
00676     ip = idup(proc->cwd);
00677 
00678   while((path = skipelem(path, name)) != 0){
00679     ilock(ip);
00680     if(ip->type != T_DIR){
00681       iunlockput(ip);
00682       return 0;
00683     }
00684     if(nameiparent && *path == '\0'){
00685       // Stop one level early.
00686       iunlock(ip);
00687       return ip;
00688     }
00689     if((next = dirlookup(ip, name, 0)) == 0){
00690       iunlockput(ip);
00691       return 0;
00692     }
00693     iunlockput(ip);
00694     ip = next;
00695   }
00696   if(nameiparent){
00697     iput(ip);
00698     return 0;
00699   }
00700   return ip;
00701 }
00702 
00703 struct inode*
00704 namei(char *path)
00705 {
00706   char name[DIRSIZ];
00707   return namex(path, 0, name);
00708 }
00709 
00710 struct inode*
00711 nameiparent(char *path, char *name)
00712 {
00713   return namex(path, 1, name);
00714 }
 All Data Structures