xref: /xv6-public/fs.c (revision c59361f1)
111a9947fSrtm #include "types.h"
211a9947fSrtm #include "param.h"
311a9947fSrtm #include "x86.h"
411a9947fSrtm #include "mmu.h"
511a9947fSrtm #include "proc.h"
611a9947fSrtm #include "defs.h"
711a9947fSrtm #include "spinlock.h"
811a9947fSrtm #include "buf.h"
911a9947fSrtm #include "fs.h"
1011a9947fSrtm #include "fsvar.h"
1111a9947fSrtm 
1211a9947fSrtm // these are inodes currently in use
1311a9947fSrtm // an entry is free if count == 0
1411a9947fSrtm struct inode inode[NINODE];
1511a9947fSrtm struct spinlock inode_table_lock;
1611a9947fSrtm 
179d3fb671Srtm uint rootdev = 1;
189d3fb671Srtm 
199d3fb671Srtm // returns an inode with busy set and incremented reference count.
2011a9947fSrtm struct inode *
2111a9947fSrtm iget(uint dev, uint inum)
2211a9947fSrtm {
2311a9947fSrtm   struct inode *ip, *nip = 0;
2411a9947fSrtm   struct dinode *dip;
2511a9947fSrtm   struct buf *bp;
2611a9947fSrtm 
2711a9947fSrtm   acquire(&inode_table_lock);
2811a9947fSrtm 
2911a9947fSrtm  loop:
3011a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
3111a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
3211a9947fSrtm       if(ip->busy){
3311a9947fSrtm         sleep(ip, &inode_table_lock);
3411a9947fSrtm         goto loop;
3511a9947fSrtm       }
3611a9947fSrtm       ip->count++;
3711a9947fSrtm       release(&inode_table_lock);
3811a9947fSrtm       return ip;
3911a9947fSrtm     }
4011a9947fSrtm     if(nip == 0 && ip->count == 0)
4111a9947fSrtm       nip = ip;
4211a9947fSrtm   }
4311a9947fSrtm 
4411a9947fSrtm   if(nip == 0)
4511a9947fSrtm     panic("out of inodes");
4611a9947fSrtm 
4711a9947fSrtm   nip->dev = dev;
4811a9947fSrtm   nip->inum = inum;
4911a9947fSrtm   nip->count = 1;
5011a9947fSrtm   nip->busy = 1;
5111a9947fSrtm 
5211a9947fSrtm   release(&inode_table_lock);
5311a9947fSrtm 
5411a9947fSrtm   bp = bread(dev, inum / IPB + 2);
5511a9947fSrtm   dip = &((struct dinode *)(bp->data))[inum % IPB];
5611a9947fSrtm   nip->type = dip->type;
5711a9947fSrtm   nip->nlink = dip->nlink;
5811a9947fSrtm   nip->size = dip->size;
5911a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
6011a9947fSrtm   brelse(bp);
6111a9947fSrtm 
6211a9947fSrtm   return nip;
6311a9947fSrtm }
6411a9947fSrtm 
6511a9947fSrtm void
669d3fb671Srtm ilock(struct inode *ip)
679d3fb671Srtm {
689d3fb671Srtm   if(ip->count < 1)
699d3fb671Srtm     panic("ilock");
709d3fb671Srtm 
719d3fb671Srtm   acquire(&inode_table_lock);
729d3fb671Srtm 
739d3fb671Srtm   while(ip->busy)
749d3fb671Srtm     sleep(ip, &inode_table_lock);
759d3fb671Srtm   ip->busy = 1;
769d3fb671Srtm 
779d3fb671Srtm   release(&inode_table_lock);
789d3fb671Srtm }
799d3fb671Srtm 
809d3fb671Srtm // caller is holding onto a reference to this inode, but no
819d3fb671Srtm // longer needs to examine or change it, so clear ip->busy.
829d3fb671Srtm void
839d3fb671Srtm iunlock(struct inode *ip)
849d3fb671Srtm {
859d3fb671Srtm   if(ip->busy != 1)
869d3fb671Srtm     panic("iunlock");
879d3fb671Srtm 
889d3fb671Srtm   acquire(&inode_table_lock);
899d3fb671Srtm 
909d3fb671Srtm   ip->busy = 0;
919d3fb671Srtm   wakeup(ip);
929d3fb671Srtm 
939d3fb671Srtm   release(&inode_table_lock);
949d3fb671Srtm }
959d3fb671Srtm 
969d3fb671Srtm // caller is releasing a reference to this inode.
979d3fb671Srtm // you must have the inode lock.
989d3fb671Srtm void
9911a9947fSrtm iput(struct inode *ip)
10011a9947fSrtm {
1019d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
1029d3fb671Srtm     panic("iput");
1039d3fb671Srtm 
10411a9947fSrtm   acquire(&inode_table_lock);
10511a9947fSrtm 
10611a9947fSrtm   ip->count -= 1;
10711a9947fSrtm   ip->busy = 0;
10811a9947fSrtm   wakeup(ip);
10911a9947fSrtm 
11011a9947fSrtm   release(&inode_table_lock);
11111a9947fSrtm }
1129d3fb671Srtm 
1139d3fb671Srtm void
1149d3fb671Srtm iincref(struct inode *ip)
1159d3fb671Srtm {
1169d3fb671Srtm   acquire(&inode_table_lock);
1179d3fb671Srtm 
1189d3fb671Srtm   ip->count += 1;
1199d3fb671Srtm 
1209d3fb671Srtm   release(&inode_table_lock);
1219d3fb671Srtm }
1229d3fb671Srtm 
1239d3fb671Srtm uint
1249d3fb671Srtm bmap(struct inode *ip, uint bn)
1259d3fb671Srtm {
1269d3fb671Srtm   unsigned x;
1279d3fb671Srtm 
1289d3fb671Srtm   if(bn >= NDIRECT)
1299d3fb671Srtm     panic("bmap 1");
1309d3fb671Srtm   x = ip->addrs[bn];
1319d3fb671Srtm   if(x == 0)
1329d3fb671Srtm     panic("bmap 2");
1339d3fb671Srtm   return x;
1349d3fb671Srtm }
1359d3fb671Srtm 
136*c59361f1Srtm #define min(a, b) ((a) < (b) ? (a) : (b))
137*c59361f1Srtm 
138*c59361f1Srtm int
139*c59361f1Srtm readi(struct inode *ip, void *xdst, uint off, uint n)
140*c59361f1Srtm {
141*c59361f1Srtm   char *dst = (char *) xdst;
142*c59361f1Srtm   uint target = n, n1;
143*c59361f1Srtm   struct buf *bp;
144*c59361f1Srtm 
145*c59361f1Srtm   while(n > 0 && off < ip->size){
146*c59361f1Srtm     bp = bread(ip->dev, bmap(ip, off / 512));
147*c59361f1Srtm     n1 = min(n, ip->size - off);
148*c59361f1Srtm     n1 = min(n1, 512 - (off % 512));
149*c59361f1Srtm     memmove(dst, bp->data + (off % 512), n1);
150*c59361f1Srtm     n -= n1;
151*c59361f1Srtm     off += n1;
152*c59361f1Srtm     dst += n1;
153*c59361f1Srtm     brelse(bp);
154*c59361f1Srtm   }
155*c59361f1Srtm 
156*c59361f1Srtm   return target - n;
157*c59361f1Srtm }
158*c59361f1Srtm 
1599d3fb671Srtm struct inode *
1609d3fb671Srtm namei(char *path)
1619d3fb671Srtm {
1629d3fb671Srtm   struct inode *dp;
1639d3fb671Srtm   char *cp = path;
1649d3fb671Srtm   uint off, dev;
1659d3fb671Srtm   struct buf *bp;
1669d3fb671Srtm   struct dirent *ep;
1679d3fb671Srtm   int i;
1689d3fb671Srtm   unsigned ninum;
1699d3fb671Srtm 
1709d3fb671Srtm   dp = iget(rootdev, 1);
1719d3fb671Srtm 
1729d3fb671Srtm   while(*cp == '/')
1739d3fb671Srtm     cp++;
1749d3fb671Srtm 
1759d3fb671Srtm   while(1){
1769d3fb671Srtm     if(*cp == '\0')
1779d3fb671Srtm       return dp;
1789d3fb671Srtm 
1799d3fb671Srtm     if(dp->type != T_DIR){
1809d3fb671Srtm       iput(dp);
1819d3fb671Srtm       return 0;
1829d3fb671Srtm     }
1839d3fb671Srtm 
1849d3fb671Srtm     for(off = 0; off < dp->size; off += 512){
1859d3fb671Srtm       bp = bread(dp->dev, bmap(dp, off / 512));
1869d3fb671Srtm       for(ep = (struct dirent *) bp->data;
1879d3fb671Srtm           ep < (struct dirent *) (bp->data + 512);
1889d3fb671Srtm           ep++){
1899d3fb671Srtm         if(ep->inum == 0)
1909d3fb671Srtm           continue;
1919d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
1929d3fb671Srtm           if(cp[i] != ep->name[i])
1939d3fb671Srtm             break;
1949d3fb671Srtm         if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){
1959d3fb671Srtm           ninum = ep->inum;
1969d3fb671Srtm           brelse(bp);
1979d3fb671Srtm           cp += i;
1989d3fb671Srtm           goto found;
1999d3fb671Srtm         }
2009d3fb671Srtm       }
2019d3fb671Srtm       brelse(bp);
2029d3fb671Srtm     }
2039d3fb671Srtm     iput(dp);
2049d3fb671Srtm     return 0;
2059d3fb671Srtm 
2069d3fb671Srtm   found:
2079d3fb671Srtm     dev = dp->dev;
2089d3fb671Srtm     iput(dp);
2099d3fb671Srtm     dp = iget(dev, ninum);
2109d3fb671Srtm     while(*cp == '/')
2119d3fb671Srtm       cp++;
2129d3fb671Srtm   }
2139d3fb671Srtm }
214