xref: /xv6-public/fs.c (revision 24111398)
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];
1532630628Srtm struct spinlock inode_table_lock = { "inode_table" };
1611a9947fSrtm 
179d3fb671Srtm uint rootdev = 1;
189d3fb671Srtm 
19*24111398Skaashoek static uint
20*24111398Skaashoek balloc(uint dev)
21*24111398Skaashoek {
22*24111398Skaashoek   int b;
23*24111398Skaashoek   struct buf *bp;
24*24111398Skaashoek   struct superblock *sb;
25*24111398Skaashoek   int bi;
26*24111398Skaashoek   int size;
27*24111398Skaashoek   int ninodes;
28*24111398Skaashoek   uchar m;
29*24111398Skaashoek 
30*24111398Skaashoek   bp = bread(dev, 1);
31*24111398Skaashoek   sb = (struct superblock *) bp->data;
32*24111398Skaashoek   size = sb->size;
33*24111398Skaashoek   ninodes = sb->ninodes;
34*24111398Skaashoek 
35*24111398Skaashoek   for (b = 0; b < size; b++) {
36*24111398Skaashoek     if (b % BPB == 0) {
37*24111398Skaashoek       brelse(bp);
38*24111398Skaashoek       bp = bread(dev, BBLOCK(b, ninodes));
39*24111398Skaashoek     }
40*24111398Skaashoek     bi = b % BPB;
41*24111398Skaashoek     m = 0x1 << (bi % 8);
42*24111398Skaashoek     if ((bp->data[bi/8] & m) == 0) {  // is block free?
43*24111398Skaashoek       break;
44*24111398Skaashoek     }
45*24111398Skaashoek   }
46*24111398Skaashoek   if (b >= size)
47*24111398Skaashoek     panic("balloc: out of blocks\n");
48*24111398Skaashoek 
49*24111398Skaashoek   cprintf ("balloc: allocate block %d\n", b);
50*24111398Skaashoek   bp->data[bi/8] |= 0x1 << (bi % 8);
51*24111398Skaashoek   bwrite (dev, bp, BBLOCK(b, ninodes));  // mark it allocated on disk
52*24111398Skaashoek   return b;
53*24111398Skaashoek }
54*24111398Skaashoek 
55*24111398Skaashoek 
569d3fb671Srtm // returns an inode with busy set and incremented reference count.
5711a9947fSrtm struct inode *
5811a9947fSrtm iget(uint dev, uint inum)
5911a9947fSrtm {
6011a9947fSrtm   struct inode *ip, *nip = 0;
6111a9947fSrtm   struct dinode *dip;
6211a9947fSrtm   struct buf *bp;
6311a9947fSrtm 
6411a9947fSrtm   acquire(&inode_table_lock);
6511a9947fSrtm 
6611a9947fSrtm  loop:
6711a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
6811a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
6911a9947fSrtm       if(ip->busy){
7011a9947fSrtm         sleep(ip, &inode_table_lock);
7111a9947fSrtm         goto loop;
7211a9947fSrtm       }
7311a9947fSrtm       ip->count++;
7411a9947fSrtm       release(&inode_table_lock);
7511a9947fSrtm       return ip;
7611a9947fSrtm     }
7711a9947fSrtm     if(nip == 0 && ip->count == 0)
7811a9947fSrtm       nip = ip;
7911a9947fSrtm   }
8011a9947fSrtm 
8111a9947fSrtm   if(nip == 0)
8211a9947fSrtm     panic("out of inodes");
8311a9947fSrtm 
8411a9947fSrtm   nip->dev = dev;
8511a9947fSrtm   nip->inum = inum;
8611a9947fSrtm   nip->count = 1;
8711a9947fSrtm   nip->busy = 1;
8811a9947fSrtm 
8911a9947fSrtm   release(&inode_table_lock);
9011a9947fSrtm 
91*24111398Skaashoek   bp = bread(dev, IBLOCK(inum));
9211a9947fSrtm   dip = &((struct dinode *)(bp->data))[inum % IPB];
9311a9947fSrtm   nip->type = dip->type;
94e8d11c2eSkaashoek   nip->major = dip->major;
95e8d11c2eSkaashoek   nip->minor = dip->minor;
9611a9947fSrtm   nip->nlink = dip->nlink;
9711a9947fSrtm   nip->size = dip->size;
9811a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
9911a9947fSrtm   brelse(bp);
10011a9947fSrtm 
10111a9947fSrtm   return nip;
10211a9947fSrtm }
10311a9947fSrtm 
104e8d11c2eSkaashoek // allocate an inode on disk
105e8d11c2eSkaashoek struct inode *
106e8d11c2eSkaashoek ialloc(uint dev, short type)
107e8d11c2eSkaashoek {
108e8d11c2eSkaashoek   struct inode *ip;
109e8d11c2eSkaashoek   struct dinode *dip = 0;
110e8d11c2eSkaashoek   struct superblock *sb;
111e8d11c2eSkaashoek   int ninodes;
112e8d11c2eSkaashoek   int inum;
113e8d11c2eSkaashoek   struct buf *bp;
114e8d11c2eSkaashoek 
115e8d11c2eSkaashoek   bp = bread(dev, 1);
116*24111398Skaashoek   sb = (struct superblock *) bp->data;
117e8d11c2eSkaashoek   ninodes = sb->ninodes;
118e8d11c2eSkaashoek   brelse(bp);
119e8d11c2eSkaashoek 
120e8d11c2eSkaashoek   for (inum = 1; inum < ninodes; inum++) {  // loop over inode blocks
121*24111398Skaashoek     bp = bread(dev, IBLOCK(inum));
122e8d11c2eSkaashoek     dip = &((struct dinode *)(bp->data))[inum % IPB];
123e8d11c2eSkaashoek     if (dip->type == 0) {  // a free inode
124e8d11c2eSkaashoek       break;
125e8d11c2eSkaashoek     }
126e8d11c2eSkaashoek     brelse(bp);
127e8d11c2eSkaashoek   }
128e8d11c2eSkaashoek 
129e8d11c2eSkaashoek   if (inum >= ninodes) {
130*24111398Skaashoek     panic ("ialloc: no inodes left\n");
131e8d11c2eSkaashoek   }
132e8d11c2eSkaashoek 
133e8d11c2eSkaashoek   cprintf ("ialloc: %d\n", inum);
134e8d11c2eSkaashoek   dip->type = type;
135*24111398Skaashoek   bwrite (dev, bp, IBLOCK(inum));   // mark it allocated on the disk
136e8d11c2eSkaashoek   brelse(bp);
137e8d11c2eSkaashoek   ip = iget (dev, inum);
138e8d11c2eSkaashoek   return ip;
139e8d11c2eSkaashoek }
140e8d11c2eSkaashoek 
141e8d11c2eSkaashoek void
142e8d11c2eSkaashoek iupdate (struct inode *ip)
143e8d11c2eSkaashoek {
144e8d11c2eSkaashoek   struct buf *bp;
145e8d11c2eSkaashoek   struct dinode *dip;
146e8d11c2eSkaashoek 
147*24111398Skaashoek   bp = bread(ip->dev, IBLOCK(ip->inum));
148e8d11c2eSkaashoek   dip = &((struct dinode *)(bp->data))[ip->inum % IPB];
149e8d11c2eSkaashoek   dip->type = ip->type;
150e8d11c2eSkaashoek   dip->major = ip->major;
151e8d11c2eSkaashoek   dip->minor = ip->minor;
152e8d11c2eSkaashoek   dip->nlink = ip->nlink;
153e8d11c2eSkaashoek   dip->size = ip->size;
154*24111398Skaashoek   bwrite (ip->dev, bp, IBLOCK(ip->inum));   // mark it allocated on the disk
155e8d11c2eSkaashoek   brelse(bp);
156e8d11c2eSkaashoek }
157e8d11c2eSkaashoek 
15811a9947fSrtm void
1599d3fb671Srtm ilock(struct inode *ip)
1609d3fb671Srtm {
1619d3fb671Srtm   if(ip->count < 1)
1629d3fb671Srtm     panic("ilock");
1639d3fb671Srtm 
1649d3fb671Srtm   acquire(&inode_table_lock);
1659d3fb671Srtm 
1669d3fb671Srtm   while(ip->busy)
1679d3fb671Srtm     sleep(ip, &inode_table_lock);
1689d3fb671Srtm   ip->busy = 1;
1699d3fb671Srtm 
1709d3fb671Srtm   release(&inode_table_lock);
1719d3fb671Srtm }
1729d3fb671Srtm 
1739d3fb671Srtm // caller is holding onto a reference to this inode, but no
1749d3fb671Srtm // longer needs to examine or change it, so clear ip->busy.
1759d3fb671Srtm void
1769d3fb671Srtm iunlock(struct inode *ip)
1779d3fb671Srtm {
1789d3fb671Srtm   if(ip->busy != 1)
1799d3fb671Srtm     panic("iunlock");
1809d3fb671Srtm 
1819d3fb671Srtm   acquire(&inode_table_lock);
1829d3fb671Srtm 
1839d3fb671Srtm   ip->busy = 0;
1849d3fb671Srtm   wakeup(ip);
1859d3fb671Srtm 
1869d3fb671Srtm   release(&inode_table_lock);
1879d3fb671Srtm }
1889d3fb671Srtm 
1899d3fb671Srtm // caller is releasing a reference to this inode.
1909d3fb671Srtm // you must have the inode lock.
1919d3fb671Srtm void
19211a9947fSrtm iput(struct inode *ip)
19311a9947fSrtm {
1949d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
1959d3fb671Srtm     panic("iput");
1969d3fb671Srtm 
19711a9947fSrtm   acquire(&inode_table_lock);
19811a9947fSrtm 
19911a9947fSrtm   ip->count -= 1;
20011a9947fSrtm   ip->busy = 0;
20111a9947fSrtm   wakeup(ip);
20211a9947fSrtm 
20311a9947fSrtm   release(&inode_table_lock);
20411a9947fSrtm }
2059d3fb671Srtm 
2069d3fb671Srtm void
20732630628Srtm idecref(struct inode *ip)
2089d3fb671Srtm {
2099d3fb671Srtm   acquire(&inode_table_lock);
2109d3fb671Srtm 
21132630628Srtm   if(ip->count < 1)
21232630628Srtm     panic("idecref");
21332630628Srtm 
21432630628Srtm   ip->count -= 1;
2159d3fb671Srtm 
2169d3fb671Srtm   release(&inode_table_lock);
2179d3fb671Srtm }
2189d3fb671Srtm 
2199d3fb671Srtm uint
2209d3fb671Srtm bmap(struct inode *ip, uint bn)
2219d3fb671Srtm {
2229d3fb671Srtm   unsigned x;
2239d3fb671Srtm 
2249d3fb671Srtm   if(bn >= NDIRECT)
2259d3fb671Srtm     panic("bmap 1");
2269d3fb671Srtm   x = ip->addrs[bn];
2279d3fb671Srtm   if(x == 0)
2289d3fb671Srtm     panic("bmap 2");
2299d3fb671Srtm   return x;
2309d3fb671Srtm }
2319d3fb671Srtm 
232c59361f1Srtm #define min(a, b) ((a) < (b) ? (a) : (b))
233c59361f1Srtm 
234c59361f1Srtm int
235c59361f1Srtm readi(struct inode *ip, void *xdst, uint off, uint n)
236c59361f1Srtm {
237c59361f1Srtm   char *dst = (char *) xdst;
238c59361f1Srtm   uint target = n, n1;
239c59361f1Srtm   struct buf *bp;
240c59361f1Srtm 
241c59361f1Srtm   while(n > 0 && off < ip->size){
242*24111398Skaashoek     bp = bread(ip->dev, bmap(ip, off / BSIZE));
243c59361f1Srtm     n1 = min(n, ip->size - off);
244*24111398Skaashoek     n1 = min(n1, BSIZE - (off % BSIZE));
245*24111398Skaashoek     memmove(dst, bp->data + (off % BSIZE), n1);
246c59361f1Srtm     n -= n1;
247c59361f1Srtm     off += n1;
248c59361f1Srtm     dst += n1;
249c59361f1Srtm     brelse(bp);
250c59361f1Srtm   }
251c59361f1Srtm 
252c59361f1Srtm   return target - n;
253c59361f1Srtm }
254c59361f1Srtm 
2559d3fb671Srtm struct inode *
2569d3fb671Srtm namei(char *path)
2579d3fb671Srtm {
2589d3fb671Srtm   struct inode *dp;
2599d3fb671Srtm   char *cp = path;
2609d3fb671Srtm   uint off, dev;
2619d3fb671Srtm   struct buf *bp;
2629d3fb671Srtm   struct dirent *ep;
2639d3fb671Srtm   int i;
2649d3fb671Srtm   unsigned ninum;
2659d3fb671Srtm 
2669d3fb671Srtm   dp = iget(rootdev, 1);
2679d3fb671Srtm 
2689d3fb671Srtm   while(*cp == '/')
2699d3fb671Srtm     cp++;
2709d3fb671Srtm 
2719d3fb671Srtm   while(1){
2729d3fb671Srtm     if(*cp == '\0')
2739d3fb671Srtm       return dp;
2749d3fb671Srtm 
2759d3fb671Srtm     if(dp->type != T_DIR){
2769d3fb671Srtm       iput(dp);
2779d3fb671Srtm       return 0;
2789d3fb671Srtm     }
2799d3fb671Srtm 
280*24111398Skaashoek     for(off = 0; off < dp->size; off += BSIZE){
281*24111398Skaashoek       bp = bread(dp->dev, bmap(dp, off / BSIZE));
2829d3fb671Srtm       for(ep = (struct dirent *) bp->data;
283*24111398Skaashoek           ep < (struct dirent *) (bp->data + BSIZE);
2849d3fb671Srtm           ep++){
2859d3fb671Srtm         if(ep->inum == 0)
2869d3fb671Srtm           continue;
2879d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
2889d3fb671Srtm           if(cp[i] != ep->name[i])
2899d3fb671Srtm             break;
2909d3fb671Srtm         if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){
2919d3fb671Srtm           ninum = ep->inum;
2929d3fb671Srtm           brelse(bp);
2939d3fb671Srtm           cp += i;
2949d3fb671Srtm           goto found;
2959d3fb671Srtm         }
2969d3fb671Srtm       }
2979d3fb671Srtm       brelse(bp);
2989d3fb671Srtm     }
2999d3fb671Srtm     iput(dp);
3009d3fb671Srtm     return 0;
3019d3fb671Srtm 
3029d3fb671Srtm   found:
3039d3fb671Srtm     dev = dp->dev;
3049d3fb671Srtm     iput(dp);
3059d3fb671Srtm     dp = iget(dev, ninum);
3069d3fb671Srtm     while(*cp == '/')
3079d3fb671Srtm       cp++;
3089d3fb671Srtm   }
3099d3fb671Srtm }
310e8d11c2eSkaashoek 
311e8d11c2eSkaashoek struct inode *
312e8d11c2eSkaashoek mknod(struct inode *dp, char *cp, short type, short major, short minor)
313e8d11c2eSkaashoek {
314e8d11c2eSkaashoek   struct inode *ip;
315e8d11c2eSkaashoek   struct dirent *ep = 0;
316e8d11c2eSkaashoek   int off;
317e8d11c2eSkaashoek   int i;
318e8d11c2eSkaashoek   struct buf *bp = 0;
319e8d11c2eSkaashoek 
320e8d11c2eSkaashoek   cprintf("mknod: %s %d %d %d\n", cp, type, major, minor);
321e8d11c2eSkaashoek 
322e8d11c2eSkaashoek   ip = ialloc(dp->dev, type);
323e8d11c2eSkaashoek   if (ip == 0) return 0;
324e8d11c2eSkaashoek   ip->major = major;
325e8d11c2eSkaashoek   ip->minor = minor;
326e8d11c2eSkaashoek 
327*24111398Skaashoek   for(off = 0; off < dp->size; off += BSIZE) {
328*24111398Skaashoek     bp = bread(dp->dev, bmap(dp, off / BSIZE));
329e8d11c2eSkaashoek     for(ep = (struct dirent *) bp->data;
330*24111398Skaashoek 	ep < (struct dirent *) (bp->data + BSIZE);
331e8d11c2eSkaashoek 	ep++){
332e8d11c2eSkaashoek       if(ep->inum == 0) {
333e8d11c2eSkaashoek 	goto found;
334e8d11c2eSkaashoek       }
335e8d11c2eSkaashoek     }
336e8d11c2eSkaashoek     brelse(bp);
337e8d11c2eSkaashoek   }
338e8d11c2eSkaashoek   panic("mknod: no dir entry free\n");
339e8d11c2eSkaashoek 
340e8d11c2eSkaashoek  found:
341e8d11c2eSkaashoek   ep->inum = ip->inum;
342e8d11c2eSkaashoek   for(i = 0; i < DIRSIZ && cp[i]; i++) ep->name[i] = cp[i];
343*24111398Skaashoek   bwrite (dp->dev, bp, bmap(dp, off/BSIZE));   // write directory
344e8d11c2eSkaashoek   brelse(bp);
345e8d11c2eSkaashoek   iupdate (ip);
346e8d11c2eSkaashoek   return ip;
347e8d11c2eSkaashoek }
348