xref: /xv6-public/fs.c (revision bb207a1d)
111a9947fSrtm #include "types.h"
21f544842Skaashoek #include "stat.h"
311a9947fSrtm #include "param.h"
411a9947fSrtm #include "x86.h"
511a9947fSrtm #include "mmu.h"
611a9947fSrtm #include "proc.h"
711a9947fSrtm #include "defs.h"
811a9947fSrtm #include "spinlock.h"
911a9947fSrtm #include "buf.h"
1011a9947fSrtm #include "fs.h"
1111a9947fSrtm #include "fsvar.h"
126fa5ffb5Skaashoek #include "dev.h"
1311a9947fSrtm 
14*bb207a1dSrsc // Inode table.  The inode table is an in-memory cache of the
15*bb207a1dSrsc // on-disk inode structures.  If an inode in the table has a non-zero
16*bb207a1dSrsc // reference count, then some open files refer to it and it must stay
17*bb207a1dSrsc // in memory.  If an inode has a zero reference count, it is only in
18*bb207a1dSrsc // memory as a cache in hopes of being used again (avoiding a disk read).
19*bb207a1dSrsc // Any inode with reference count zero can be evicted from the table.
20*bb207a1dSrsc //
21*bb207a1dSrsc // In addition to having a reference count, inodes can be marked busy
22*bb207a1dSrsc // (just like bufs), meaning that some code has logically locked the
23*bb207a1dSrsc // inode, and others are not allowed to look at it.
24*bb207a1dSrsc // This locking can last for a long
25*bb207a1dSrsc // time (for example, if the inode is busy during a disk access),
26*bb207a1dSrsc // so we don't use spin locks.  Instead, if a process wants to use
27*bb207a1dSrsc // a particular inode, it must sleep(ip) to wait for it to be not busy.
28*bb207a1dSrsc // See iget below.
29*bb207a1dSrsc //
30*bb207a1dSrsc // XXX Inodes with dev == 0 exist only in memory.  They have no on-disk
31*bb207a1dSrsc // representation.  This functionality is used to implement pipes.
3211a9947fSrtm struct inode inode[NINODE];
335be0039cSrtm struct spinlock inode_table_lock;
3411a9947fSrtm 
359d3fb671Srtm uint rootdev = 1;
369d3fb671Srtm 
375be0039cSrtm void
385be0039cSrtm iinit(void)
395be0039cSrtm {
405be0039cSrtm   initlock(&inode_table_lock, "inode_table");
415be0039cSrtm }
425be0039cSrtm 
43f5527388Srsc // Allocate a disk block.
4424111398Skaashoek static uint
4524111398Skaashoek balloc(uint dev)
4624111398Skaashoek {
4724111398Skaashoek   int b;
4824111398Skaashoek   struct buf *bp;
4924111398Skaashoek   struct superblock *sb;
5028d9ef04Skaashoek   int bi = 0;
5124111398Skaashoek   int size;
5224111398Skaashoek   int ninodes;
5324111398Skaashoek   uchar m;
5424111398Skaashoek 
5524111398Skaashoek   bp = bread(dev, 1);
5624111398Skaashoek   sb = (struct superblock*) bp->data;
5724111398Skaashoek   size = sb->size;
5824111398Skaashoek   ninodes = sb->ninodes;
5924111398Skaashoek 
6024111398Skaashoek   for(b = 0; b < size; b++) {
6124111398Skaashoek     if(b % BPB == 0) {
6224111398Skaashoek       brelse(bp);
6324111398Skaashoek       bp = bread(dev, BBLOCK(b, ninodes));
6424111398Skaashoek     }
6524111398Skaashoek     bi = b % BPB;
6624111398Skaashoek     m = 0x1 << (bi % 8);
6724111398Skaashoek     if((bp->data[bi/8] & m) == 0) {  // is block free?
6824111398Skaashoek       break;
6924111398Skaashoek     }
7024111398Skaashoek   }
7124111398Skaashoek   if(b >= size)
722aa4c3bcSrtm     panic("balloc: out of blocks");
7324111398Skaashoek 
7424111398Skaashoek   bp->data[bi/8] |= 0x1 << (bi % 8);
7505e97551Srtm   bwrite(bp, BBLOCK(b, ninodes));  // mark it allocated on disk
7628d9ef04Skaashoek   brelse(bp);
7724111398Skaashoek   return b;
7824111398Skaashoek }
7924111398Skaashoek 
80*bb207a1dSrsc // Free a disk block.
8128d9ef04Skaashoek static void
8228d9ef04Skaashoek bfree(int dev, uint b)
8328d9ef04Skaashoek {
8428d9ef04Skaashoek   struct buf *bp;
8528d9ef04Skaashoek   struct superblock *sb;
8628d9ef04Skaashoek   int bi;
8728d9ef04Skaashoek   int ninodes;
8828d9ef04Skaashoek   uchar m;
8928d9ef04Skaashoek 
9028d9ef04Skaashoek   bp = bread(dev, 1);
9128d9ef04Skaashoek   sb = (struct superblock*) bp->data;
9228d9ef04Skaashoek   ninodes = sb->ninodes;
9328d9ef04Skaashoek   brelse(bp);
9428d9ef04Skaashoek 
95c372e8dcSkaashoek   bp = bread(dev, b);
96c372e8dcSkaashoek   memset(bp->data, 0, BSIZE);
97c372e8dcSkaashoek   bwrite(bp, b);
98c372e8dcSkaashoek   brelse(bp);
99c372e8dcSkaashoek 
10028d9ef04Skaashoek   bp = bread(dev, BBLOCK(b, ninodes));
10128d9ef04Skaashoek   bi = b % BPB;
10228d9ef04Skaashoek   m = ~(0x1 << (bi %8));
10328d9ef04Skaashoek   bp->data[bi/8] &= m;
10405e97551Srtm   bwrite(bp, BBLOCK(b, ninodes));  // mark it free on disk
10528d9ef04Skaashoek   brelse(bp);
10628d9ef04Skaashoek }
10724111398Skaashoek 
108f5527388Srsc // Find the inode with number inum on device dev
109f5527388Srsc // and return an in-memory copy.  Loads the inode
110f5527388Srsc // from disk into the in-core table if necessary.
111f5527388Srsc // The returned inode has busy set and has its ref count incremented.
112f5527388Srsc // Caller must iput the return value when done with it.
11311a9947fSrtm struct inode*
11411a9947fSrtm iget(uint dev, uint inum)
11511a9947fSrtm {
11617e3cf15Srtm   struct inode *ip, *nip;
11711a9947fSrtm   struct dinode *dip;
11811a9947fSrtm   struct buf *bp;
11911a9947fSrtm 
12011a9947fSrtm   acquire(&inode_table_lock);
12111a9947fSrtm 
12211a9947fSrtm  loop:
12317e3cf15Srtm   nip = 0;
12411a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
12511a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
12611a9947fSrtm       if(ip->busy){
12711a9947fSrtm         sleep(ip, &inode_table_lock);
128*bb207a1dSrsc         // Since we droped inode_table_lock, ip might have been reused
129*bb207a1dSrsc         // for some other inode entirely.  Must start the scan over,
130*bb207a1dSrsc         // and hopefully this time we will find the inode we want
131*bb207a1dSrsc         // and it will not be busy.
13211a9947fSrtm         goto loop;
13311a9947fSrtm       }
13411a9947fSrtm       ip->count++;
13517a85657Srtm       ip->busy = 1;
13611a9947fSrtm       release(&inode_table_lock);
13711a9947fSrtm       return ip;
13811a9947fSrtm     }
13911a9947fSrtm     if(nip == 0 && ip->count == 0)
14011a9947fSrtm       nip = ip;
14111a9947fSrtm   }
14211a9947fSrtm 
14311a9947fSrtm   if(nip == 0)
14411a9947fSrtm     panic("out of inodes");
14511a9947fSrtm 
14611a9947fSrtm   nip->dev = dev;
14711a9947fSrtm   nip->inum = inum;
14811a9947fSrtm   nip->count = 1;
14911a9947fSrtm   nip->busy = 1;
15011a9947fSrtm 
15111a9947fSrtm   release(&inode_table_lock);
15211a9947fSrtm 
15324111398Skaashoek   bp = bread(dev, IBLOCK(inum));
15411a9947fSrtm   dip = &((struct dinode*)(bp->data))[inum % IPB];
15511a9947fSrtm   nip->type = dip->type;
156e8d11c2eSkaashoek   nip->major = dip->major;
157e8d11c2eSkaashoek   nip->minor = dip->minor;
15811a9947fSrtm   nip->nlink = dip->nlink;
15911a9947fSrtm   nip->size = dip->size;
16011a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
16111a9947fSrtm   brelse(bp);
16211a9947fSrtm 
16311a9947fSrtm   return nip;
16411a9947fSrtm }
16511a9947fSrtm 
166*bb207a1dSrsc // Copy ip->d, which has changed, to disk.
167*bb207a1dSrsc // Caller must have locked ip.
16828d9ef04Skaashoek void
16928d9ef04Skaashoek iupdate(struct inode *ip)
17028d9ef04Skaashoek {
17128d9ef04Skaashoek   struct buf *bp;
17228d9ef04Skaashoek   struct dinode *dip;
17328d9ef04Skaashoek 
17428d9ef04Skaashoek   bp = bread(ip->dev, IBLOCK(ip->inum));
17528d9ef04Skaashoek   dip = &((struct dinode*)(bp->data))[ip->inum % IPB];
17628d9ef04Skaashoek   dip->type = ip->type;
17728d9ef04Skaashoek   dip->major = ip->major;
17828d9ef04Skaashoek   dip->minor = ip->minor;
17928d9ef04Skaashoek   dip->nlink = ip->nlink;
18028d9ef04Skaashoek   dip->size = ip->size;
18128d9ef04Skaashoek   memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
18205e97551Srtm   bwrite(bp, IBLOCK(ip->inum));   // mark it allocated on the disk
18328d9ef04Skaashoek   brelse(bp);
18428d9ef04Skaashoek }
18528d9ef04Skaashoek 
186*bb207a1dSrsc // Allocate a new inode with the given type
187*bb207a1dSrsc // from the file system on device dev.
188e8d11c2eSkaashoek struct inode*
189e8d11c2eSkaashoek ialloc(uint dev, short type)
190e8d11c2eSkaashoek {
191e8d11c2eSkaashoek   struct inode *ip;
192e8d11c2eSkaashoek   struct dinode *dip = 0;
193e8d11c2eSkaashoek   struct superblock *sb;
194e8d11c2eSkaashoek   int ninodes;
195e8d11c2eSkaashoek   int inum;
196e8d11c2eSkaashoek   struct buf *bp;
197e8d11c2eSkaashoek 
198e8d11c2eSkaashoek   bp = bread(dev, 1);
19924111398Skaashoek   sb = (struct superblock*) bp->data;
200e8d11c2eSkaashoek   ninodes = sb->ninodes;
201e8d11c2eSkaashoek   brelse(bp);
202e8d11c2eSkaashoek 
203e8d11c2eSkaashoek   for(inum = 1; inum < ninodes; inum++) {  // loop over inode blocks
20424111398Skaashoek     bp = bread(dev, IBLOCK(inum));
205e8d11c2eSkaashoek     dip = &((struct dinode*)(bp->data))[inum % IPB];
206e8d11c2eSkaashoek     if(dip->type == 0) {  // a free inode
207e8d11c2eSkaashoek       break;
208e8d11c2eSkaashoek     }
209e8d11c2eSkaashoek     brelse(bp);
210e8d11c2eSkaashoek   }
211e8d11c2eSkaashoek 
21217e3cf15Srtm   if(inum >= ninodes)
2132aa4c3bcSrtm     panic("ialloc: no inodes left");
214e8d11c2eSkaashoek 
2152aa4c3bcSrtm   memset(dip, 0, sizeof(*dip));
216e8d11c2eSkaashoek   dip->type = type;
21705e97551Srtm   bwrite(bp, IBLOCK(inum));   // mark it allocated on the disk
218e8d11c2eSkaashoek   brelse(bp);
219e8d11c2eSkaashoek   ip = iget(dev, inum);
220e8d11c2eSkaashoek   return ip;
221e8d11c2eSkaashoek }
222e8d11c2eSkaashoek 
223*bb207a1dSrsc // Free the given inode from its file system.
22428d9ef04Skaashoek static void
22524437cd5Skaashoek ifree(struct inode *ip)
226e8d11c2eSkaashoek {
22728d9ef04Skaashoek   ip->type = 0;
22828d9ef04Skaashoek   iupdate(ip);
229e8d11c2eSkaashoek }
230e8d11c2eSkaashoek 
231*bb207a1dSrsc // Lock the given inode (wait for it to be not busy,
232*bb207a1dSrsc // and then ip->busy).
233*bb207a1dSrsc // Caller must already hold a reference to ip.
234*bb207a1dSrsc // Otherwise, if all the references to ip go away,
235*bb207a1dSrsc // it might be reused underfoot.
23611a9947fSrtm void
2379d3fb671Srtm ilock(struct inode *ip)
2389d3fb671Srtm {
2399d3fb671Srtm   if(ip->count < 1)
2409d3fb671Srtm     panic("ilock");
2419d3fb671Srtm 
2429d3fb671Srtm   acquire(&inode_table_lock);
2439d3fb671Srtm 
2449d3fb671Srtm   while(ip->busy)
2459d3fb671Srtm     sleep(ip, &inode_table_lock);
2469d3fb671Srtm   ip->busy = 1;
2479d3fb671Srtm 
2489d3fb671Srtm   release(&inode_table_lock);
2499d3fb671Srtm }
2509d3fb671Srtm 
251*bb207a1dSrsc // Caller holds reference to ip and has locked it.
252*bb207a1dSrsc // Caller no longer needs to examine / change it.
253*bb207a1dSrsc // Unlock it, but keep the reference.
2549d3fb671Srtm void
2559d3fb671Srtm iunlock(struct inode *ip)
2569d3fb671Srtm {
25717e3cf15Srtm   if(ip->busy != 1 || ip->count < 1)
2589d3fb671Srtm     panic("iunlock");
2599d3fb671Srtm 
2609d3fb671Srtm   acquire(&inode_table_lock);
2619d3fb671Srtm 
2629d3fb671Srtm   ip->busy = 0;
2639d3fb671Srtm   wakeup(ip);
2649d3fb671Srtm 
2659d3fb671Srtm   release(&inode_table_lock);
2669d3fb671Srtm }
2679d3fb671Srtm 
268*bb207a1dSrsc // Return the disk block address of the nth block in inode ip.
26922bac2cbSkaashoek uint
27022bac2cbSkaashoek bmap(struct inode *ip, uint bn)
27122bac2cbSkaashoek {
27222bac2cbSkaashoek   unsigned x;
273ea2909b6Skaashoek   uint *a;
274ea2909b6Skaashoek   struct buf *inbp;
27522bac2cbSkaashoek 
276ea2909b6Skaashoek   if(bn >= MAXFILE)
27722bac2cbSkaashoek     panic("bmap 1");
278ea2909b6Skaashoek   if(bn < NDIRECT) {
27922bac2cbSkaashoek     x = ip->addrs[bn];
28022bac2cbSkaashoek     if(x == 0)
28122bac2cbSkaashoek       panic("bmap 2");
282ea2909b6Skaashoek   } else {
2835051da6dSrtm     if(ip->addrs[INDIRECT] == 0)
2845051da6dSrtm       panic("bmap 3");
2851be76685Skaashoek     inbp = bread(ip->dev, ip->addrs[INDIRECT]);
286ea2909b6Skaashoek     a = (uint*) inbp->data;
287ea2909b6Skaashoek     x = a[bn - NDIRECT];
288ea2909b6Skaashoek     brelse(inbp);
289ea2909b6Skaashoek     if(x == 0)
2905051da6dSrtm       panic("bmap 4");
291ea2909b6Skaashoek   }
29222bac2cbSkaashoek   return x;
29322bac2cbSkaashoek }
29422bac2cbSkaashoek 
295*bb207a1dSrsc // Truncate the inode ip, discarding all its data blocks.
29622bac2cbSkaashoek void
2972aa4c3bcSrtm itrunc(struct inode *ip)
29822bac2cbSkaashoek {
299ea2909b6Skaashoek   int i, j;
3001be76685Skaashoek   struct buf *inbp;
30122bac2cbSkaashoek 
302ea2909b6Skaashoek   for(i = 0; i < NADDRS; i++) {
30322bac2cbSkaashoek     if(ip->addrs[i] != 0) {
304ea2909b6Skaashoek       if(i == INDIRECT) {
3051be76685Skaashoek         inbp = bread(ip->dev, ip->addrs[INDIRECT]);
3061be76685Skaashoek         uint *a = (uint*) inbp->data;
307bcfb84b6Srtm         for(j = 0; j < NINDIRECT; j++) {
308ea2909b6Skaashoek           if(a[j] != 0) {
309ea2909b6Skaashoek             bfree(ip->dev, a[j]);
310ea2909b6Skaashoek             a[j] = 0;
311ea2909b6Skaashoek           }
312ea2909b6Skaashoek         }
3131be76685Skaashoek         brelse(inbp);
314ea2909b6Skaashoek       }
31522bac2cbSkaashoek       bfree(ip->dev, ip->addrs[i]);
31622bac2cbSkaashoek       ip->addrs[i] = 0;
31722bac2cbSkaashoek     }
31822bac2cbSkaashoek   }
31922bac2cbSkaashoek   ip->size = 0;
32022bac2cbSkaashoek   iupdate(ip);
32122bac2cbSkaashoek }
32222bac2cbSkaashoek 
323*bb207a1dSrsc // Caller holds reference to ip and has locked it,
324*bb207a1dSrsc // possibly editing it.
325*bb207a1dSrsc // Release lock and drop the reference.
3269d3fb671Srtm void
32711a9947fSrtm iput(struct inode *ip)
32811a9947fSrtm {
3299d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
3309d3fb671Srtm     panic("iput");
3319d3fb671Srtm 
3322aa4c3bcSrtm   if((ip->count == 1) && (ip->nlink == 0)) {
3332aa4c3bcSrtm     itrunc(ip);
3342aa4c3bcSrtm     ifree(ip);
3352aa4c3bcSrtm   }
33622bac2cbSkaashoek 
33711a9947fSrtm   acquire(&inode_table_lock);
33811a9947fSrtm 
33911a9947fSrtm   ip->count -= 1;
34011a9947fSrtm   ip->busy = 0;
34111a9947fSrtm   wakeup(ip);
34211a9947fSrtm 
34311a9947fSrtm   release(&inode_table_lock);
34411a9947fSrtm }
3459d3fb671Srtm 
346*bb207a1dSrsc // Caller holds reference to ip but not lock.
347*bb207a1dSrsc // Drop reference.
3489d3fb671Srtm void
34932630628Srtm idecref(struct inode *ip)
3509d3fb671Srtm {
351211ff0c6Srtm   ilock(ip);
352211ff0c6Srtm   iput(ip);
3539d3fb671Srtm }
3549d3fb671Srtm 
355*bb207a1dSrsc // Increment reference count for ip.
3561f544842Skaashoek void
357e958c538Skaashoek iincref(struct inode *ip)
358e958c538Skaashoek {
359e958c538Skaashoek   ilock(ip);
360e958c538Skaashoek   ip->count++;
361e958c538Skaashoek   iunlock(ip);
362e958c538Skaashoek }
363e958c538Skaashoek 
364*bb207a1dSrsc // Copy stat information from inode.
365*bb207a1dSrsc // XXX Assumes inode is from disk file system.
366e958c538Skaashoek void
3671f544842Skaashoek stati(struct inode *ip, struct stat *st)
3681f544842Skaashoek {
3691dca3afbSrsc   st->dev = ip->dev;
3701dca3afbSrsc   st->ino = ip->inum;
3711dca3afbSrsc   st->type = ip->type;
3721dca3afbSrsc   st->nlink = ip->nlink;
3731dca3afbSrsc   st->size = ip->size;
3741f544842Skaashoek }
3751f544842Skaashoek 
37622bac2cbSkaashoek #define min(a, b) ((a) < (b) ? (a) : (b))
37722bac2cbSkaashoek 
378*bb207a1dSrsc // Read data from inode.
379*bb207a1dSrsc // XXX Assumes inode is from disk file system.
380c59361f1Srtm int
38117a85657Srtm readi(struct inode *ip, char *dst, uint off, uint n)
382c59361f1Srtm {
383c59361f1Srtm   uint target = n, n1;
384c59361f1Srtm   struct buf *bp;
385c59361f1Srtm 
386939f9edeSkaashoek   if(ip->type == T_DEV) {
3871dca3afbSrsc     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)
388939f9edeSkaashoek       return -1;
3891dca3afbSrsc     return devsw[ip->major].read(ip->minor, dst, n);
390939f9edeSkaashoek   }
391939f9edeSkaashoek 
392c59361f1Srtm   while(n > 0 && off < ip->size){
39324111398Skaashoek     bp = bread(ip->dev, bmap(ip, off / BSIZE));
394c59361f1Srtm     n1 = min(n, ip->size - off);
39524111398Skaashoek     n1 = min(n1, BSIZE - (off % BSIZE));
39624111398Skaashoek     memmove(dst, bp->data + (off % BSIZE), n1);
397c59361f1Srtm     n -= n1;
398c59361f1Srtm     off += n1;
399c59361f1Srtm     dst += n1;
400c59361f1Srtm     brelse(bp);
401c59361f1Srtm   }
402c59361f1Srtm 
403c59361f1Srtm   return target - n;
404c59361f1Srtm }
405c59361f1Srtm 
406*bb207a1dSrsc // Allocate the nth block in inode ip if necessary.
4071be76685Skaashoek static int
408ea2909b6Skaashoek newblock(struct inode *ip, uint lbn)
409ea2909b6Skaashoek {
410ea2909b6Skaashoek   struct buf *inbp;
411ea2909b6Skaashoek   uint *inaddrs;
412ea2909b6Skaashoek   uint b;
413ea2909b6Skaashoek 
414ea2909b6Skaashoek   if(lbn < NDIRECT) {
415ea2909b6Skaashoek     if(ip->addrs[lbn] == 0) {
416ea2909b6Skaashoek       b = balloc(ip->dev);
41748b82470Srsc       if(b <= 0)
41848b82470Srsc         return -1;
419ea2909b6Skaashoek       ip->addrs[lbn] = b;
420ea2909b6Skaashoek     }
421ea2909b6Skaashoek   } else {
422ea2909b6Skaashoek     if(ip->addrs[INDIRECT] == 0) {
423ea2909b6Skaashoek       b = balloc(ip->dev);
42448b82470Srsc       if(b <= 0)
42548b82470Srsc         return -1;
426ea2909b6Skaashoek       ip->addrs[INDIRECT] = b;
427ea2909b6Skaashoek     }
4281be76685Skaashoek     inbp = bread(ip->dev, ip->addrs[INDIRECT]);
429ea2909b6Skaashoek     inaddrs = (uint*) inbp->data;
430ea2909b6Skaashoek     if(inaddrs[lbn - NDIRECT] == 0) {
431ea2909b6Skaashoek       b = balloc(ip->dev);
43248b82470Srsc       if(b <= 0)
43348b82470Srsc         return -1;
434ea2909b6Skaashoek       inaddrs[lbn - NDIRECT] = b;
4351be76685Skaashoek       bwrite(inbp, ip->addrs[INDIRECT]);
436ea2909b6Skaashoek     }
437ea2909b6Skaashoek     brelse(inbp);
438ea2909b6Skaashoek   }
439ea2909b6Skaashoek   return 0;
440ea2909b6Skaashoek }
441ea2909b6Skaashoek 
442*bb207a1dSrsc // Write data to inode.
443*bb207a1dSrsc // XXX Assumes inode is from disk file system.
444ea2909b6Skaashoek int
44517a85657Srtm writei(struct inode *ip, char *addr, uint off, uint n)
4466fa5ffb5Skaashoek {
4476fa5ffb5Skaashoek   if(ip->type == T_DEV) {
4481dca3afbSrsc     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
449939f9edeSkaashoek       return -1;
4501dca3afbSrsc     return devsw[ip->major].write(ip->minor, addr, n);
451ea2909b6Skaashoek   } else if(ip->type == T_FILE || ip->type == T_DIR) {
45228d9ef04Skaashoek     struct buf *bp;
45328d9ef04Skaashoek     int r = 0;
45428d9ef04Skaashoek     int m;
45528d9ef04Skaashoek     int lbn;
45628d9ef04Skaashoek     while(r < n) {
45728d9ef04Skaashoek       lbn = off / BSIZE;
45848b82470Srsc       if(lbn >= MAXFILE)
45948b82470Srsc         return r;
460ea2909b6Skaashoek       if(newblock(ip, lbn) < 0) {
461ea2909b6Skaashoek         cprintf("newblock failed\n");
462ea2909b6Skaashoek         return r;
46328d9ef04Skaashoek       }
46422bac2cbSkaashoek       m = min(BSIZE - off % BSIZE, n-r);
465ea2909b6Skaashoek       bp = bread(ip->dev, bmap(ip, lbn));
46628d9ef04Skaashoek       memmove(bp->data + off % BSIZE, addr, m);
467ea2909b6Skaashoek       bwrite(bp, bmap(ip, lbn));
46828d9ef04Skaashoek       brelse(bp);
46928d9ef04Skaashoek       r += m;
47028d9ef04Skaashoek       off += m;
47128d9ef04Skaashoek     }
47228d9ef04Skaashoek     if(r > 0) {
47328d9ef04Skaashoek       if(off > ip->size) {
47448b82470Srsc         if(ip->type == T_DIR)
47548b82470Srsc           ip->size = ((off / BSIZE) + 1) * BSIZE;
47648b82470Srsc         else
47748b82470Srsc           ip->size = off;
47828d9ef04Skaashoek       }
47928d9ef04Skaashoek       iupdate(ip);
48028d9ef04Skaashoek     }
48128d9ef04Skaashoek     return r;
4826fa5ffb5Skaashoek   } else {
4832aa4c3bcSrtm     panic("writei: unknown type");
4848a8be1b8Srtm     return 0;
4856fa5ffb5Skaashoek   }
4866fa5ffb5Skaashoek }
4876fa5ffb5Skaashoek 
488211ff0c6Srtm // look up a path name, in one of three modes.
489211ff0c6Srtm // NAMEI_LOOKUP: return locked target inode.
490211ff0c6Srtm // NAMEI_CREATE: return locked parent inode.
4915051da6dSrtm //   return 0 if name does exist.
4925051da6dSrtm //   *ret_last points to last path component (i.e. new file name).
4935051da6dSrtm //   *ret_ip points to the the name that did exist, if it did.
4945051da6dSrtm //   *ret_ip and *ret_last may be zero even if return value is zero.
495211ff0c6Srtm // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off.
496211ff0c6Srtm //   return 0 if name doesn't exist.
4979d3fb671Srtm struct inode*
4980cfc7290Srsc namei(char *path, int mode, uint *ret_off,
4990cfc7290Srsc       char **ret_last, struct inode **ret_ip)
5009d3fb671Srtm {
5019d3fb671Srtm   struct inode *dp;
5028787cd01Skaashoek   struct proc *p = curproc[cpu()];
503211ff0c6Srtm   char *cp = path, *cp1;
5049d3fb671Srtm   uint off, dev;
5059d3fb671Srtm   struct buf *bp;
5069d3fb671Srtm   struct dirent *ep;
507211ff0c6Srtm   int i, atend;
5089d3fb671Srtm   unsigned ninum;
5099d3fb671Srtm 
5105051da6dSrtm   if(ret_off)
5115051da6dSrtm     *ret_off = 0xffffffff;
5125051da6dSrtm   if(ret_last)
5135051da6dSrtm     *ret_last = 0;
5145051da6dSrtm   if(ret_ip)
5155051da6dSrtm     *ret_ip = 0;
5165051da6dSrtm 
51748b82470Srsc   if(*cp == '/')
51848b82470Srsc     dp = iget(rootdev, 1);
5198787cd01Skaashoek   else {
5208787cd01Skaashoek     dp = p->cwd;
5218787cd01Skaashoek     iincref(dp);
5228787cd01Skaashoek     ilock(dp);
5238787cd01Skaashoek   }
5249d3fb671Srtm 
5259d3fb671Srtm   while(*cp == '/')
5269d3fb671Srtm     cp++;
5279d3fb671Srtm 
528db8fb62eSrsc   for(;;){
5290633b971Skaashoek     if(*cp == '\0'){
530211ff0c6Srtm       if(mode == NAMEI_LOOKUP)
5319d3fb671Srtm         return dp;
5325051da6dSrtm       if(mode == NAMEI_CREATE && ret_ip){
5335051da6dSrtm         *ret_ip = dp;
5345051da6dSrtm         return 0;
5355051da6dSrtm       }
536211ff0c6Srtm       iput(dp);
537211ff0c6Srtm       return 0;
5380633b971Skaashoek     }
5399d3fb671Srtm 
5409d3fb671Srtm     if(dp->type != T_DIR){
5419d3fb671Srtm       iput(dp);
5429d3fb671Srtm       return 0;
5439d3fb671Srtm     }
5449d3fb671Srtm 
54524111398Skaashoek     for(off = 0; off < dp->size; off += BSIZE){
54624111398Skaashoek       bp = bread(dp->dev, bmap(dp, off / BSIZE));
5479d3fb671Srtm       for(ep = (struct dirent*) bp->data;
54824111398Skaashoek           ep < (struct dirent*) (bp->data + BSIZE);
5499d3fb671Srtm           ep++){
5509d3fb671Srtm         if(ep->inum == 0)
5519d3fb671Srtm           continue;
5529d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
5539d3fb671Srtm           if(cp[i] != ep->name[i])
5549d3fb671Srtm             break;
55503c70cc2Srtm         if((cp[i] == '\0' || cp[i] == '/' || i >= DIRSIZ) &&
55603c70cc2Srtm            (i >= DIRSIZ || ep->name[i] == '\0')){
55703c70cc2Srtm           while(cp[i] != '\0' && cp[i] != '/')
55803c70cc2Srtm             i++;
559211ff0c6Srtm           off += (uchar*)ep - bp->data;
5609d3fb671Srtm           ninum = ep->inum;
5619d3fb671Srtm           brelse(bp);
5629d3fb671Srtm           cp += i;
5639d3fb671Srtm           goto found;
5649d3fb671Srtm         }
5659d3fb671Srtm       }
5669d3fb671Srtm       brelse(bp);
5679d3fb671Srtm     }
568211ff0c6Srtm     atend = 1;
569211ff0c6Srtm     for(cp1 = cp; *cp1; cp1++)
570211ff0c6Srtm       if(*cp1 == '/')
571211ff0c6Srtm         atend = 0;
5725051da6dSrtm     if(mode == NAMEI_CREATE && atend){
5735051da6dSrtm       if(*cp == '\0'){
5745051da6dSrtm         iput(dp);
5755051da6dSrtm         return 0;
5765051da6dSrtm       }
5775051da6dSrtm       *ret_last = cp;
578211ff0c6Srtm       return dp;
5795051da6dSrtm     }
580211ff0c6Srtm 
5819d3fb671Srtm     iput(dp);
5829d3fb671Srtm     return 0;
5839d3fb671Srtm 
5849d3fb671Srtm   found:
585211ff0c6Srtm     if(mode == NAMEI_DELETE && *cp == '\0'){
586211ff0c6Srtm       *ret_off = off;
587211ff0c6Srtm       return dp;
588211ff0c6Srtm     }
5899d3fb671Srtm     dev = dp->dev;
5909d3fb671Srtm     iput(dp);
5919d3fb671Srtm     dp = iget(dev, ninum);
5927ce01cf9Srtm     if(dp->type == 0 || dp->nlink < 1)
5937ce01cf9Srtm       panic("namei");
5949d3fb671Srtm     while(*cp == '/')
5959d3fb671Srtm       cp++;
5969d3fb671Srtm   }
5979d3fb671Srtm }
598e8d11c2eSkaashoek 
599*bb207a1dSrsc // Write a new directory entry (name, ino) into the directory dp.
600*bb207a1dSrsc // Caller must have locked dp.
6019e5970d5Srtm void
6029e5970d5Srtm wdir(struct inode *dp, char *name, uint ino)
6039e5970d5Srtm {
6049e5970d5Srtm   uint off;
605e4bcd2a3Srtm   struct dirent de;
6069e5970d5Srtm   int i;
6079e5970d5Srtm 
608e4bcd2a3Srtm   for(off = 0; off < dp->size; off += sizeof(de)){
609e4bcd2a3Srtm     if(readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
610e4bcd2a3Srtm       panic("wdir read");
611e4bcd2a3Srtm     if(de.inum == 0)
612e4bcd2a3Srtm       break;
613e4bcd2a3Srtm   }
614211ff0c6Srtm 
615e4bcd2a3Srtm   de.inum = ino;
6162aa4c3bcSrtm   for(i = 0; i < DIRSIZ && name[i]; i++)
617e4bcd2a3Srtm     de.name[i] = name[i];
6189e5970d5Srtm   for( ; i < DIRSIZ; i++)
619e4bcd2a3Srtm     de.name[i] = '\0';
620e4bcd2a3Srtm 
621e4bcd2a3Srtm   if(writei(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
622e4bcd2a3Srtm     panic("wdir write");
6239e5970d5Srtm }
6249e5970d5Srtm 
625*bb207a1dSrsc // Create the path cp and return its locked inode structure.
626*bb207a1dSrsc // If cp already exists, return 0.
627e8d11c2eSkaashoek struct inode*
6280633b971Skaashoek mknod(char *cp, short type, short major, short minor)
629e8d11c2eSkaashoek {
6300633b971Skaashoek   struct inode *ip, *dp;
6315051da6dSrtm   char *last;
632e8d11c2eSkaashoek 
6335051da6dSrtm   if((dp = namei(cp, NAMEI_CREATE, 0, &last, 0)) == 0)
6340633b971Skaashoek     return 0;
635211ff0c6Srtm 
6365051da6dSrtm   ip = mknod1(dp, last, type, major, minor);
6375051da6dSrtm 
6385051da6dSrtm   iput(dp);
6395051da6dSrtm 
6405051da6dSrtm   return ip;
6415051da6dSrtm }
6425051da6dSrtm 
643*bb207a1dSrsc // Create a new inode named name inside dp
644*bb207a1dSrsc // and return its locked inode structure.
645*bb207a1dSrsc // If name already exists, return 0.
6465051da6dSrtm struct inode*
6475051da6dSrtm mknod1(struct inode *dp, char *name, short type, short major, short minor)
6485051da6dSrtm {
6495051da6dSrtm   struct inode *ip;
6505051da6dSrtm 
651e8d11c2eSkaashoek   ip = ialloc(dp->dev, type);
6522aa4c3bcSrtm   if(ip == 0)
6530633b971Skaashoek     return 0;
654e8d11c2eSkaashoek   ip->major = major;
655e8d11c2eSkaashoek   ip->minor = minor;
6566c0e444fSkaashoek   ip->size = 0;
6577ce01cf9Srtm   ip->nlink = 1;
6586c0e444fSkaashoek 
6596c0e444fSkaashoek   iupdate(ip);  // write new inode to disk
660e8d11c2eSkaashoek 
6615051da6dSrtm   wdir(dp, name, ip->inum);
6625051da6dSrtm 
663e8d11c2eSkaashoek   return ip;
664e8d11c2eSkaashoek }
66524437cd5Skaashoek 
666*bb207a1dSrsc // Unlink the inode named cp.
66724437cd5Skaashoek int
66824437cd5Skaashoek unlink(char *cp)
66924437cd5Skaashoek {
670211ff0c6Srtm   struct inode *ip, *dp;
671211ff0c6Srtm   struct dirent de;
67217e3cf15Srtm   uint off, inum, dev;
67324437cd5Skaashoek 
6745051da6dSrtm   dp = namei(cp, NAMEI_DELETE, &off, 0, 0);
6755051da6dSrtm   if(dp == 0)
67624437cd5Skaashoek     return -1;
67724437cd5Skaashoek 
67817e3cf15Srtm   dev = dp->dev;
67917e3cf15Srtm 
68017e3cf15Srtm   if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
681211ff0c6Srtm     panic("unlink no entry");
68217e3cf15Srtm 
683211ff0c6Srtm   inum = de.inum;
68424437cd5Skaashoek 
685211ff0c6Srtm   memset(&de, 0, sizeof(de));
686211ff0c6Srtm   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
687211ff0c6Srtm     panic("unlink dir write");
68824437cd5Skaashoek 
68924437cd5Skaashoek   iupdate(dp);
69024437cd5Skaashoek   iput(dp);
691211ff0c6Srtm 
69217e3cf15Srtm   ip = iget(dev, inum);
693211ff0c6Srtm 
694bcfb84b6Srtm   if(ip->nlink < 1)
695bcfb84b6Srtm     panic("unlink nlink < 1");
696bcfb84b6Srtm 
697211ff0c6Srtm   ip->nlink--;
698211ff0c6Srtm 
699211ff0c6Srtm   iupdate(ip);
70022bac2cbSkaashoek   iput(ip);
701211ff0c6Srtm 
70224437cd5Skaashoek   return 0;
70324437cd5Skaashoek }
7049e5970d5Srtm 
705*bb207a1dSrsc // Create the path new as a link to the same inode as old.
7069e5970d5Srtm int
7079e5970d5Srtm link(char *name1, char *name2)
7089e5970d5Srtm {
709211ff0c6Srtm   struct inode *ip, *dp;
7105051da6dSrtm   char *last;
7119e5970d5Srtm 
7125051da6dSrtm   if((ip = namei(name1, NAMEI_LOOKUP, 0, 0, 0)) == 0)
7139e5970d5Srtm     return -1;
714211ff0c6Srtm   if(ip->type == T_DIR){
715211ff0c6Srtm     iput(ip);
716211ff0c6Srtm     return -1;
717211ff0c6Srtm   }
7189e5970d5Srtm 
719211ff0c6Srtm   iunlock(ip);
720211ff0c6Srtm 
7215051da6dSrtm   if((dp = namei(name2, NAMEI_CREATE, 0, &last, 0)) == 0) {
722211ff0c6Srtm     idecref(ip);
723211ff0c6Srtm     return -1;
724211ff0c6Srtm   }
725211ff0c6Srtm   if(dp->dev != ip->dev){
726211ff0c6Srtm     idecref(ip);
727211ff0c6Srtm     iput(dp);
728211ff0c6Srtm     return -1;
729211ff0c6Srtm   }
730211ff0c6Srtm 
731211ff0c6Srtm   ilock(ip);
7329e5970d5Srtm   ip->nlink += 1;
7339e5970d5Srtm   iupdate(ip);
7349e5970d5Srtm 
7355051da6dSrtm   wdir(dp, last, ip->inum);
7369e5970d5Srtm   iput(dp);
7379e5970d5Srtm   iput(ip);
7389e5970d5Srtm 
7399e5970d5Srtm   return 0;
7409e5970d5Srtm }
741