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