xref: /xv6-public/fs.c (revision 5be0039c)
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"
116fa5ffb5Skaashoek #include "dev.h"
1211a9947fSrtm 
1311a9947fSrtm // these are inodes currently in use
1411a9947fSrtm // an entry is free if count == 0
1511a9947fSrtm struct inode inode[NINODE];
16*5be0039cSrtm struct spinlock inode_table_lock;
1711a9947fSrtm 
189d3fb671Srtm uint rootdev = 1;
199d3fb671Srtm 
20*5be0039cSrtm void
21*5be0039cSrtm iinit(void)
22*5be0039cSrtm {
23*5be0039cSrtm   initlock(&inode_table_lock, "inode_table");
24*5be0039cSrtm }
25*5be0039cSrtm 
2624111398Skaashoek static uint
2724111398Skaashoek balloc(uint dev)
2824111398Skaashoek {
2924111398Skaashoek   int b;
3024111398Skaashoek   struct buf *bp;
3124111398Skaashoek   struct superblock *sb;
3228d9ef04Skaashoek   int bi = 0;
3324111398Skaashoek   int size;
3424111398Skaashoek   int ninodes;
3524111398Skaashoek   uchar m;
3624111398Skaashoek 
3724111398Skaashoek   bp = bread(dev, 1);
3824111398Skaashoek   sb = (struct superblock *) bp->data;
3924111398Skaashoek   size = sb->size;
4024111398Skaashoek   ninodes = sb->ninodes;
4124111398Skaashoek 
4224111398Skaashoek   for (b = 0; b < size; b++) {
4324111398Skaashoek     if (b % BPB == 0) {
4424111398Skaashoek       brelse(bp);
4524111398Skaashoek       bp = bread(dev, BBLOCK(b, ninodes));
4624111398Skaashoek     }
4724111398Skaashoek     bi = b % BPB;
4824111398Skaashoek     m = 0x1 << (bi % 8);
4924111398Skaashoek     if ((bp->data[bi/8] & m) == 0) {  // is block free?
5024111398Skaashoek       break;
5124111398Skaashoek     }
5224111398Skaashoek   }
5324111398Skaashoek   if (b >= size)
5424111398Skaashoek     panic("balloc: out of blocks\n");
5524111398Skaashoek 
5624111398Skaashoek   cprintf ("balloc: allocate block %d\n", b);
5724111398Skaashoek   bp->data[bi/8] |= 0x1 << (bi % 8);
5824111398Skaashoek   bwrite (dev, bp, BBLOCK(b, ninodes));  // mark it allocated on disk
5928d9ef04Skaashoek   brelse(bp);
6024111398Skaashoek   return b;
6124111398Skaashoek }
6224111398Skaashoek 
6328d9ef04Skaashoek static void
6428d9ef04Skaashoek bfree(int dev, uint b)
6528d9ef04Skaashoek {
6628d9ef04Skaashoek   struct buf *bp;
6728d9ef04Skaashoek   struct superblock *sb;
6828d9ef04Skaashoek   int bi;
6928d9ef04Skaashoek   int ninodes;
7028d9ef04Skaashoek   uchar m;
7128d9ef04Skaashoek 
7228d9ef04Skaashoek   cprintf ("bfree: free block %d\n", b);
7328d9ef04Skaashoek   bp = bread(dev, 1);
7428d9ef04Skaashoek   sb = (struct superblock *) bp->data;
7528d9ef04Skaashoek   ninodes = sb->ninodes;
7628d9ef04Skaashoek   brelse(bp);
7728d9ef04Skaashoek 
7828d9ef04Skaashoek   bp = bread(dev, BBLOCK(b, ninodes));
7928d9ef04Skaashoek   bi = b % BPB;
8028d9ef04Skaashoek   m = ~(0x1 << (bi %8));
8128d9ef04Skaashoek   bp->data[bi/8] &= m;
8228d9ef04Skaashoek   bwrite (dev, bp, BBLOCK(b, ninodes));  // mark it free on disk
8328d9ef04Skaashoek   brelse(bp);
8428d9ef04Skaashoek }
8524111398Skaashoek 
869d3fb671Srtm // returns an inode with busy set and incremented reference count.
8711a9947fSrtm struct inode *
8811a9947fSrtm iget(uint dev, uint inum)
8911a9947fSrtm {
9011a9947fSrtm   struct inode *ip, *nip = 0;
9111a9947fSrtm   struct dinode *dip;
9211a9947fSrtm   struct buf *bp;
9311a9947fSrtm 
9411a9947fSrtm   acquire(&inode_table_lock);
9511a9947fSrtm 
9611a9947fSrtm  loop:
9711a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
9811a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
9911a9947fSrtm       if(ip->busy){
10011a9947fSrtm         sleep(ip, &inode_table_lock);
10111a9947fSrtm         goto loop;
10211a9947fSrtm       }
10311a9947fSrtm       ip->count++;
10411a9947fSrtm       release(&inode_table_lock);
10511a9947fSrtm       return ip;
10611a9947fSrtm     }
10711a9947fSrtm     if(nip == 0 && ip->count == 0)
10811a9947fSrtm       nip = ip;
10911a9947fSrtm   }
11011a9947fSrtm 
11111a9947fSrtm   if(nip == 0)
11211a9947fSrtm     panic("out of inodes");
11311a9947fSrtm 
11411a9947fSrtm   nip->dev = dev;
11511a9947fSrtm   nip->inum = inum;
11611a9947fSrtm   nip->count = 1;
11711a9947fSrtm   nip->busy = 1;
11811a9947fSrtm 
11911a9947fSrtm   release(&inode_table_lock);
12011a9947fSrtm 
12124111398Skaashoek   bp = bread(dev, IBLOCK(inum));
12211a9947fSrtm   dip = &((struct dinode *)(bp->data))[inum % IPB];
12311a9947fSrtm   nip->type = dip->type;
124e8d11c2eSkaashoek   nip->major = dip->major;
125e8d11c2eSkaashoek   nip->minor = dip->minor;
12611a9947fSrtm   nip->nlink = dip->nlink;
12711a9947fSrtm   nip->size = dip->size;
12811a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
12911a9947fSrtm   brelse(bp);
13011a9947fSrtm 
13111a9947fSrtm   return nip;
13211a9947fSrtm }
13311a9947fSrtm 
13428d9ef04Skaashoek void
13528d9ef04Skaashoek iupdate (struct inode *ip)
13628d9ef04Skaashoek {
13728d9ef04Skaashoek   struct buf *bp;
13828d9ef04Skaashoek   struct dinode *dip;
13928d9ef04Skaashoek 
14028d9ef04Skaashoek   bp = bread(ip->dev, IBLOCK(ip->inum));
14128d9ef04Skaashoek   dip = &((struct dinode *)(bp->data))[ip->inum % IPB];
14228d9ef04Skaashoek   dip->type = ip->type;
14328d9ef04Skaashoek   dip->major = ip->major;
14428d9ef04Skaashoek   dip->minor = ip->minor;
14528d9ef04Skaashoek   dip->nlink = ip->nlink;
14628d9ef04Skaashoek   dip->size = ip->size;
14728d9ef04Skaashoek   memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
14828d9ef04Skaashoek   bwrite (ip->dev, bp, IBLOCK(ip->inum));   // mark it allocated on the disk
14928d9ef04Skaashoek   brelse(bp);
15028d9ef04Skaashoek }
15128d9ef04Skaashoek 
152e8d11c2eSkaashoek struct inode *
153e8d11c2eSkaashoek ialloc(uint dev, short type)
154e8d11c2eSkaashoek {
155e8d11c2eSkaashoek   struct inode *ip;
156e8d11c2eSkaashoek   struct dinode *dip = 0;
157e8d11c2eSkaashoek   struct superblock *sb;
158e8d11c2eSkaashoek   int ninodes;
159e8d11c2eSkaashoek   int inum;
160e8d11c2eSkaashoek   struct buf *bp;
161e8d11c2eSkaashoek 
162e8d11c2eSkaashoek   bp = bread(dev, 1);
16324111398Skaashoek   sb = (struct superblock *) bp->data;
164e8d11c2eSkaashoek   ninodes = sb->ninodes;
165e8d11c2eSkaashoek   brelse(bp);
166e8d11c2eSkaashoek 
167e8d11c2eSkaashoek   for (inum = 1; inum < ninodes; inum++) {  // loop over inode blocks
16824111398Skaashoek     bp = bread(dev, IBLOCK(inum));
169e8d11c2eSkaashoek     dip = &((struct dinode *)(bp->data))[inum % IPB];
170e8d11c2eSkaashoek     if (dip->type == 0) {  // a free inode
171e8d11c2eSkaashoek       break;
172e8d11c2eSkaashoek     }
173e8d11c2eSkaashoek     brelse(bp);
174e8d11c2eSkaashoek   }
175e8d11c2eSkaashoek 
176e8d11c2eSkaashoek   if (inum >= ninodes) {
17724111398Skaashoek     panic ("ialloc: no inodes left\n");
178e8d11c2eSkaashoek   }
179e8d11c2eSkaashoek 
180e8d11c2eSkaashoek   cprintf ("ialloc: %d\n", inum);
181e8d11c2eSkaashoek   dip->type = type;
18224111398Skaashoek   bwrite (dev, bp, IBLOCK(inum));   // mark it allocated on the disk
183e8d11c2eSkaashoek   brelse(bp);
184e8d11c2eSkaashoek   ip = iget (dev, inum);
185e8d11c2eSkaashoek   return ip;
186e8d11c2eSkaashoek }
187e8d11c2eSkaashoek 
18828d9ef04Skaashoek static void
18928d9ef04Skaashoek ifree(uint dev, struct inode *ip)
190e8d11c2eSkaashoek {
19128d9ef04Skaashoek   ip->type = 0;
19228d9ef04Skaashoek   iupdate(ip);
193e8d11c2eSkaashoek }
194e8d11c2eSkaashoek 
19511a9947fSrtm void
1969d3fb671Srtm ilock(struct inode *ip)
1979d3fb671Srtm {
1989d3fb671Srtm   if(ip->count < 1)
1999d3fb671Srtm     panic("ilock");
2009d3fb671Srtm 
2019d3fb671Srtm   acquire(&inode_table_lock);
2029d3fb671Srtm 
2039d3fb671Srtm   while(ip->busy)
2049d3fb671Srtm     sleep(ip, &inode_table_lock);
2059d3fb671Srtm   ip->busy = 1;
2069d3fb671Srtm 
2079d3fb671Srtm   release(&inode_table_lock);
2089d3fb671Srtm }
2099d3fb671Srtm 
2109d3fb671Srtm // caller is holding onto a reference to this inode, but no
2119d3fb671Srtm // longer needs to examine or change it, so clear ip->busy.
2129d3fb671Srtm void
2139d3fb671Srtm iunlock(struct inode *ip)
2149d3fb671Srtm {
2159d3fb671Srtm   if(ip->busy != 1)
2169d3fb671Srtm     panic("iunlock");
2179d3fb671Srtm 
2189d3fb671Srtm   acquire(&inode_table_lock);
2199d3fb671Srtm 
2209d3fb671Srtm   ip->busy = 0;
2219d3fb671Srtm   wakeup(ip);
2229d3fb671Srtm 
2239d3fb671Srtm   release(&inode_table_lock);
2249d3fb671Srtm }
2259d3fb671Srtm 
2269d3fb671Srtm // caller is releasing a reference to this inode.
2279d3fb671Srtm // you must have the inode lock.
2289d3fb671Srtm void
22911a9947fSrtm iput(struct inode *ip)
23011a9947fSrtm {
2319d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
2329d3fb671Srtm     panic("iput");
2339d3fb671Srtm 
23411a9947fSrtm   acquire(&inode_table_lock);
23511a9947fSrtm 
23611a9947fSrtm   ip->count -= 1;
23711a9947fSrtm   ip->busy = 0;
23811a9947fSrtm   wakeup(ip);
23911a9947fSrtm 
24011a9947fSrtm   release(&inode_table_lock);
24111a9947fSrtm }
2429d3fb671Srtm 
2439d3fb671Srtm void
24432630628Srtm idecref(struct inode *ip)
2459d3fb671Srtm {
2469d3fb671Srtm   acquire(&inode_table_lock);
2479d3fb671Srtm 
24832630628Srtm   if(ip->count < 1)
24932630628Srtm     panic("idecref");
25032630628Srtm 
25132630628Srtm   ip->count -= 1;
2529d3fb671Srtm 
2539d3fb671Srtm   release(&inode_table_lock);
2549d3fb671Srtm }
2559d3fb671Srtm 
2569d3fb671Srtm uint
2579d3fb671Srtm bmap(struct inode *ip, uint bn)
2589d3fb671Srtm {
2599d3fb671Srtm   unsigned x;
2609d3fb671Srtm 
2619d3fb671Srtm   if(bn >= NDIRECT)
2629d3fb671Srtm     panic("bmap 1");
2639d3fb671Srtm   x = ip->addrs[bn];
2649d3fb671Srtm   if(x == 0)
2659d3fb671Srtm     panic("bmap 2");
2669d3fb671Srtm   return x;
2679d3fb671Srtm }
2689d3fb671Srtm 
269c59361f1Srtm #define min(a, b) ((a) < (b) ? (a) : (b))
270c59361f1Srtm 
271c59361f1Srtm int
272c59361f1Srtm readi(struct inode *ip, void *xdst, uint off, uint n)
273c59361f1Srtm {
274c59361f1Srtm   char *dst = (char *) xdst;
275c59361f1Srtm   uint target = n, n1;
276c59361f1Srtm   struct buf *bp;
277c59361f1Srtm 
278939f9edeSkaashoek   if (ip->type == T_DEV) {
279939f9edeSkaashoek     if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_read)
280939f9edeSkaashoek       return -1;
281939f9edeSkaashoek     return devsw[ip->major].d_read (ip->minor, xdst, n);
282939f9edeSkaashoek   }
283939f9edeSkaashoek 
284c59361f1Srtm   while(n > 0 && off < ip->size){
28524111398Skaashoek     bp = bread(ip->dev, bmap(ip, off / BSIZE));
286c59361f1Srtm     n1 = min(n, ip->size - off);
28724111398Skaashoek     n1 = min(n1, BSIZE - (off % BSIZE));
28824111398Skaashoek     memmove(dst, bp->data + (off % BSIZE), n1);
289c59361f1Srtm     n -= n1;
290c59361f1Srtm     off += n1;
291c59361f1Srtm     dst += n1;
292c59361f1Srtm     brelse(bp);
293c59361f1Srtm   }
294c59361f1Srtm 
295c59361f1Srtm   return target - n;
296c59361f1Srtm }
297c59361f1Srtm 
29828d9ef04Skaashoek #define MIN(a, b) ((a < b) ? a : b)
29928d9ef04Skaashoek 
3006fa5ffb5Skaashoek int
30128d9ef04Skaashoek writei(struct inode *ip, void *addr, uint off, uint n)
3026fa5ffb5Skaashoek {
3036fa5ffb5Skaashoek   if (ip->type == T_DEV) {
304939f9edeSkaashoek     if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write)
305939f9edeSkaashoek       return -1;
3066fa5ffb5Skaashoek     return devsw[ip->major].d_write (ip->minor, addr, n);
30728d9ef04Skaashoek   } else if (ip->type == T_FILE || ip->type == T_DIR) { // XXX dir here too?
30828d9ef04Skaashoek     struct buf *bp;
30928d9ef04Skaashoek     int r = 0;
31028d9ef04Skaashoek     int m;
31128d9ef04Skaashoek     int lbn;
31228d9ef04Skaashoek     uint b;
31328d9ef04Skaashoek     while (r < n) {
31428d9ef04Skaashoek       lbn = off / BSIZE;
31528d9ef04Skaashoek       if (lbn >= NDIRECT) return r;
31628d9ef04Skaashoek       if (ip->addrs[lbn] == 0) {
31728d9ef04Skaashoek 	b = balloc(ip->dev);
31828d9ef04Skaashoek 	if (b <= 0) return r;
31928d9ef04Skaashoek 	ip->addrs[lbn] = b;
32028d9ef04Skaashoek       }
32128d9ef04Skaashoek       m = MIN(BSIZE - off % BSIZE, n-r);
32228d9ef04Skaashoek       bp = bread(ip->dev, bmap(ip, off / BSIZE));
32328d9ef04Skaashoek       memmove (bp->data + off % BSIZE, addr, m);
32428d9ef04Skaashoek       bwrite (ip->dev, bp, bmap(ip, off/BSIZE));
32528d9ef04Skaashoek       brelse (bp);
32628d9ef04Skaashoek       r += m;
32728d9ef04Skaashoek       off += m;
32828d9ef04Skaashoek     }
32928d9ef04Skaashoek     if (r > 0) {
33028d9ef04Skaashoek       if (off > ip->size) {
33128d9ef04Skaashoek 	ip->size = off;
33228d9ef04Skaashoek       }
33328d9ef04Skaashoek       iupdate(ip);
33428d9ef04Skaashoek     }
33528d9ef04Skaashoek     return r;
3366fa5ffb5Skaashoek   } else {
3376fa5ffb5Skaashoek     panic ("writei: unknown type\n");
3388a8be1b8Srtm     return 0;
3396fa5ffb5Skaashoek   }
3406fa5ffb5Skaashoek }
3416fa5ffb5Skaashoek 
3429d3fb671Srtm struct inode *
3439d3fb671Srtm namei(char *path)
3449d3fb671Srtm {
3459d3fb671Srtm   struct inode *dp;
3469d3fb671Srtm   char *cp = path;
3479d3fb671Srtm   uint off, dev;
3489d3fb671Srtm   struct buf *bp;
3499d3fb671Srtm   struct dirent *ep;
3509d3fb671Srtm   int i;
3519d3fb671Srtm   unsigned ninum;
3529d3fb671Srtm 
3539d3fb671Srtm   dp = iget(rootdev, 1);
3549d3fb671Srtm 
3559d3fb671Srtm   while(*cp == '/')
3569d3fb671Srtm     cp++;
3579d3fb671Srtm 
3589d3fb671Srtm   while(1){
3599d3fb671Srtm     if(*cp == '\0')
3609d3fb671Srtm       return dp;
3619d3fb671Srtm 
3629d3fb671Srtm     if(dp->type != T_DIR){
3639d3fb671Srtm       iput(dp);
3649d3fb671Srtm       return 0;
3659d3fb671Srtm     }
3669d3fb671Srtm 
36724111398Skaashoek     for(off = 0; off < dp->size; off += BSIZE){
36824111398Skaashoek       bp = bread(dp->dev, bmap(dp, off / BSIZE));
3699d3fb671Srtm       for(ep = (struct dirent *) bp->data;
37024111398Skaashoek           ep < (struct dirent *) (bp->data + BSIZE);
3719d3fb671Srtm           ep++){
3729d3fb671Srtm         if(ep->inum == 0)
3739d3fb671Srtm           continue;
3749d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
3759d3fb671Srtm           if(cp[i] != ep->name[i])
3769d3fb671Srtm             break;
3779d3fb671Srtm         if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){
3789d3fb671Srtm           ninum = ep->inum;
3799d3fb671Srtm           brelse(bp);
3809d3fb671Srtm           cp += i;
3819d3fb671Srtm           goto found;
3829d3fb671Srtm         }
3839d3fb671Srtm       }
3849d3fb671Srtm       brelse(bp);
3859d3fb671Srtm     }
3869d3fb671Srtm     iput(dp);
3879d3fb671Srtm     return 0;
3889d3fb671Srtm 
3899d3fb671Srtm   found:
3909d3fb671Srtm     dev = dp->dev;
3919d3fb671Srtm     iput(dp);
3929d3fb671Srtm     dp = iget(dev, ninum);
3939d3fb671Srtm     while(*cp == '/')
3949d3fb671Srtm       cp++;
3959d3fb671Srtm   }
3969d3fb671Srtm }
397e8d11c2eSkaashoek 
398e8d11c2eSkaashoek struct inode *
399e8d11c2eSkaashoek mknod(struct inode *dp, char *cp, short type, short major, short minor)
400e8d11c2eSkaashoek {
401e8d11c2eSkaashoek   struct inode *ip;
402e8d11c2eSkaashoek   struct dirent *ep = 0;
403e8d11c2eSkaashoek   int off;
404e8d11c2eSkaashoek   int i;
405e8d11c2eSkaashoek   struct buf *bp = 0;
406e8d11c2eSkaashoek 
407e8d11c2eSkaashoek   cprintf("mknod: %s %d %d %d\n", cp, type, major, minor);
408e8d11c2eSkaashoek 
409e8d11c2eSkaashoek   ip = ialloc(dp->dev, type);
410e8d11c2eSkaashoek   if (ip == 0) return 0;
411e8d11c2eSkaashoek   ip->major = major;
412e8d11c2eSkaashoek   ip->minor = minor;
4136c0e444fSkaashoek   ip->size = 0;
4146c0e444fSkaashoek   ip->nlink = 0;
4156c0e444fSkaashoek 
4166c0e444fSkaashoek   iupdate (ip);  // write new inode to disk
417e8d11c2eSkaashoek 
41824111398Skaashoek   for(off = 0; off < dp->size; off += BSIZE) {
41924111398Skaashoek     bp = bread(dp->dev, bmap(dp, off / BSIZE));
420e8d11c2eSkaashoek     for(ep = (struct dirent *) bp->data;
42124111398Skaashoek 	ep < (struct dirent *) (bp->data + BSIZE);
422e8d11c2eSkaashoek 	ep++){
423e8d11c2eSkaashoek       if(ep->inum == 0) {
424e8d11c2eSkaashoek 	goto found;
425e8d11c2eSkaashoek       }
426e8d11c2eSkaashoek     }
427e8d11c2eSkaashoek     brelse(bp);
428e8d11c2eSkaashoek   }
42928d9ef04Skaashoek   panic("mknod: XXXX no dir entry free\n");
430e8d11c2eSkaashoek 
431e8d11c2eSkaashoek  found:
432e8d11c2eSkaashoek   ep->inum = ip->inum;
433e8d11c2eSkaashoek   for(i = 0; i < DIRSIZ && cp[i]; i++) ep->name[i] = cp[i];
4346c0e444fSkaashoek   bwrite (dp->dev, bp, bmap(dp, off/BSIZE));   // write directory block
435e8d11c2eSkaashoek   brelse(bp);
4366c0e444fSkaashoek 
4376c0e444fSkaashoek   dp->size += sizeof(struct dirent);   // update directory inode
4386c0e444fSkaashoek   iupdate (dp);
4396c0e444fSkaashoek 
440e8d11c2eSkaashoek   return ip;
441e8d11c2eSkaashoek }
442