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 14bb207a1dSrsc // Inode table. The inode table is an in-memory cache of the 15bb207a1dSrsc // on-disk inode structures. If an inode in the table has a non-zero 16bb207a1dSrsc // reference count, then some open files refer to it and it must stay 17bb207a1dSrsc // in memory. If an inode has a zero reference count, it is only in 18bb207a1dSrsc // memory as a cache in hopes of being used again (avoiding a disk read). 19bb207a1dSrsc // Any inode with reference count zero can be evicted from the table. 20bb207a1dSrsc // 21bb207a1dSrsc // In addition to having a reference count, inodes can be marked busy 22bb207a1dSrsc // (just like bufs), meaning that some code has logically locked the 23bb207a1dSrsc // inode, and others are not allowed to look at it. 24bb207a1dSrsc // This locking can last for a long 25bb207a1dSrsc // time (for example, if the inode is busy during a disk access), 26bb207a1dSrsc // so we don't use spin locks. Instead, if a process wants to use 27bb207a1dSrsc // a particular inode, it must sleep(ip) to wait for it to be not busy. 28bb207a1dSrsc // See iget below. 2911a9947fSrtm struct inode inode[NINODE]; 305be0039cSrtm struct spinlock inode_table_lock; 3111a9947fSrtm 329d3fb671Srtm uint rootdev = 1; 339d3fb671Srtm 345be0039cSrtm void 355be0039cSrtm iinit(void) 365be0039cSrtm { 375be0039cSrtm initlock(&inode_table_lock, "inode_table"); 385be0039cSrtm } 395be0039cSrtm 40f5527388Srsc // Allocate a disk block. 4124111398Skaashoek static uint 4224111398Skaashoek balloc(uint dev) 4324111398Skaashoek { 4424111398Skaashoek int b; 4524111398Skaashoek struct buf *bp; 4624111398Skaashoek struct superblock *sb; 4728d9ef04Skaashoek int bi = 0; 4824111398Skaashoek int size; 4924111398Skaashoek int ninodes; 5024111398Skaashoek uchar m; 5124111398Skaashoek 5224111398Skaashoek bp = bread(dev, 1); 5324111398Skaashoek sb = (struct superblock*) bp->data; 5424111398Skaashoek size = sb->size; 5524111398Skaashoek ninodes = sb->ninodes; 5624111398Skaashoek 5724111398Skaashoek for(b = 0; b < size; b++) { 5824111398Skaashoek if(b % BPB == 0) { 5924111398Skaashoek brelse(bp); 6024111398Skaashoek bp = bread(dev, BBLOCK(b, ninodes)); 6124111398Skaashoek } 6224111398Skaashoek bi = b % BPB; 6324111398Skaashoek m = 0x1 << (bi % 8); 6424111398Skaashoek if((bp->data[bi/8] & m) == 0) { // is block free? 6524111398Skaashoek break; 6624111398Skaashoek } 6724111398Skaashoek } 6824111398Skaashoek if(b >= size) 692aa4c3bcSrtm panic("balloc: out of blocks"); 7024111398Skaashoek 7124111398Skaashoek bp->data[bi/8] |= 0x1 << (bi % 8); 7205e97551Srtm bwrite(bp, BBLOCK(b, ninodes)); // mark it allocated on disk 7328d9ef04Skaashoek brelse(bp); 7424111398Skaashoek return b; 7524111398Skaashoek } 7624111398Skaashoek 77bb207a1dSrsc // Free a disk block. 7828d9ef04Skaashoek static void 7928d9ef04Skaashoek bfree(int dev, uint b) 8028d9ef04Skaashoek { 8128d9ef04Skaashoek struct buf *bp; 8228d9ef04Skaashoek struct superblock *sb; 8328d9ef04Skaashoek int bi; 8428d9ef04Skaashoek int ninodes; 8528d9ef04Skaashoek uchar m; 8628d9ef04Skaashoek 8728d9ef04Skaashoek bp = bread(dev, 1); 8828d9ef04Skaashoek sb = (struct superblock*) bp->data; 8928d9ef04Skaashoek ninodes = sb->ninodes; 9028d9ef04Skaashoek brelse(bp); 9128d9ef04Skaashoek 92c372e8dcSkaashoek bp = bread(dev, b); 93c372e8dcSkaashoek memset(bp->data, 0, BSIZE); 94c372e8dcSkaashoek bwrite(bp, b); 95c372e8dcSkaashoek brelse(bp); 96c372e8dcSkaashoek 9728d9ef04Skaashoek bp = bread(dev, BBLOCK(b, ninodes)); 9828d9ef04Skaashoek bi = b % BPB; 9928d9ef04Skaashoek m = ~(0x1 << (bi %8)); 10028d9ef04Skaashoek bp->data[bi/8] &= m; 10105e97551Srtm bwrite(bp, BBLOCK(b, ninodes)); // mark it free on disk 10228d9ef04Skaashoek brelse(bp); 10328d9ef04Skaashoek } 10424111398Skaashoek 105f5527388Srsc // Find the inode with number inum on device dev 106f5527388Srsc // and return an in-memory copy. Loads the inode 107f5527388Srsc // from disk into the in-core table if necessary. 108f5527388Srsc // The returned inode has busy set and has its ref count incremented. 109f5527388Srsc // Caller must iput the return value when done with it. 11011a9947fSrtm struct inode* 11111a9947fSrtm iget(uint dev, uint inum) 11211a9947fSrtm { 11317e3cf15Srtm struct inode *ip, *nip; 11411a9947fSrtm struct dinode *dip; 11511a9947fSrtm struct buf *bp; 11611a9947fSrtm 11711a9947fSrtm acquire(&inode_table_lock); 11811a9947fSrtm 11911a9947fSrtm loop: 12017e3cf15Srtm nip = 0; 12111a9947fSrtm for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ 1220d6bbd31Srsc if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ 12311a9947fSrtm if(ip->busy){ 12411a9947fSrtm sleep(ip, &inode_table_lock); 125bb207a1dSrsc // Since we droped inode_table_lock, ip might have been reused 126bb207a1dSrsc // for some other inode entirely. Must start the scan over, 127bb207a1dSrsc // and hopefully this time we will find the inode we want 128bb207a1dSrsc // and it will not be busy. 12911a9947fSrtm goto loop; 13011a9947fSrtm } 1310d6bbd31Srsc ip->ref++; 13217a85657Srtm ip->busy = 1; 13311a9947fSrtm release(&inode_table_lock); 13411a9947fSrtm return ip; 13511a9947fSrtm } 1360d6bbd31Srsc if(nip == 0 && ip->ref == 0) 13711a9947fSrtm nip = ip; 13811a9947fSrtm } 13911a9947fSrtm 14011a9947fSrtm if(nip == 0) 141*32eea766Srsc panic("iget: no inodes"); 14211a9947fSrtm 14311a9947fSrtm nip->dev = dev; 14411a9947fSrtm nip->inum = inum; 1450d6bbd31Srsc nip->ref = 1; 14611a9947fSrtm nip->busy = 1; 14711a9947fSrtm 14811a9947fSrtm release(&inode_table_lock); 14911a9947fSrtm 15024111398Skaashoek bp = bread(dev, IBLOCK(inum)); 15111a9947fSrtm dip = &((struct dinode*)(bp->data))[inum % IPB]; 15211a9947fSrtm nip->type = dip->type; 153e8d11c2eSkaashoek nip->major = dip->major; 154e8d11c2eSkaashoek nip->minor = dip->minor; 15511a9947fSrtm nip->nlink = dip->nlink; 15611a9947fSrtm nip->size = dip->size; 15711a9947fSrtm memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); 15811a9947fSrtm brelse(bp); 15911a9947fSrtm 16011a9947fSrtm return nip; 16111a9947fSrtm } 16211a9947fSrtm 1638e1d1ec9Skaashoek // Copy inode in memory, which has changed, to disk. 164bb207a1dSrsc // Caller must have locked ip. 16528d9ef04Skaashoek void 16628d9ef04Skaashoek iupdate(struct inode *ip) 16728d9ef04Skaashoek { 16828d9ef04Skaashoek struct buf *bp; 16928d9ef04Skaashoek struct dinode *dip; 17028d9ef04Skaashoek 17128d9ef04Skaashoek bp = bread(ip->dev, IBLOCK(ip->inum)); 17228d9ef04Skaashoek dip = &((struct dinode*)(bp->data))[ip->inum % IPB]; 17328d9ef04Skaashoek dip->type = ip->type; 17428d9ef04Skaashoek dip->major = ip->major; 17528d9ef04Skaashoek dip->minor = ip->minor; 17628d9ef04Skaashoek dip->nlink = ip->nlink; 17728d9ef04Skaashoek dip->size = ip->size; 17828d9ef04Skaashoek memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); 17905e97551Srtm bwrite(bp, IBLOCK(ip->inum)); // mark it allocated on the disk 18028d9ef04Skaashoek brelse(bp); 18128d9ef04Skaashoek } 18228d9ef04Skaashoek 183bb207a1dSrsc // Allocate a new inode with the given type 184bb207a1dSrsc // from the file system on device dev. 185e8d11c2eSkaashoek struct inode* 186e8d11c2eSkaashoek ialloc(uint dev, short type) 187e8d11c2eSkaashoek { 188e8d11c2eSkaashoek struct inode *ip; 189e8d11c2eSkaashoek struct dinode *dip = 0; 190e8d11c2eSkaashoek struct superblock *sb; 191e8d11c2eSkaashoek int ninodes; 192e8d11c2eSkaashoek int inum; 193e8d11c2eSkaashoek struct buf *bp; 194e8d11c2eSkaashoek 195e8d11c2eSkaashoek bp = bread(dev, 1); 19624111398Skaashoek sb = (struct superblock*) bp->data; 197e8d11c2eSkaashoek ninodes = sb->ninodes; 198e8d11c2eSkaashoek brelse(bp); 199e8d11c2eSkaashoek 200e8d11c2eSkaashoek for(inum = 1; inum < ninodes; inum++) { // loop over inode blocks 20124111398Skaashoek bp = bread(dev, IBLOCK(inum)); 202e8d11c2eSkaashoek dip = &((struct dinode*)(bp->data))[inum % IPB]; 203e8d11c2eSkaashoek if(dip->type == 0) { // a free inode 204e8d11c2eSkaashoek break; 205e8d11c2eSkaashoek } 206e8d11c2eSkaashoek brelse(bp); 207e8d11c2eSkaashoek } 208e8d11c2eSkaashoek 20917e3cf15Srtm if(inum >= ninodes) 2102aa4c3bcSrtm panic("ialloc: no inodes left"); 211e8d11c2eSkaashoek 2122aa4c3bcSrtm memset(dip, 0, sizeof(*dip)); 213e8d11c2eSkaashoek dip->type = type; 21405e97551Srtm bwrite(bp, IBLOCK(inum)); // mark it allocated on the disk 215e8d11c2eSkaashoek brelse(bp); 216e8d11c2eSkaashoek ip = iget(dev, inum); 217e8d11c2eSkaashoek return ip; 218e8d11c2eSkaashoek } 219e8d11c2eSkaashoek 220bb207a1dSrsc // Free the given inode from its file system. 22128d9ef04Skaashoek static void 22224437cd5Skaashoek ifree(struct inode *ip) 223e8d11c2eSkaashoek { 22428d9ef04Skaashoek ip->type = 0; 22528d9ef04Skaashoek iupdate(ip); 226e8d11c2eSkaashoek } 227e8d11c2eSkaashoek 228bb207a1dSrsc // Lock the given inode (wait for it to be not busy, 229bb207a1dSrsc // and then ip->busy). 230bb207a1dSrsc // Caller must already hold a reference to ip. 231bb207a1dSrsc // Otherwise, if all the references to ip go away, 232bb207a1dSrsc // it might be reused underfoot. 23311a9947fSrtm void 2349d3fb671Srtm ilock(struct inode *ip) 2359d3fb671Srtm { 2360d6bbd31Srsc if(ip->ref < 1) 2379d3fb671Srtm panic("ilock"); 2389d3fb671Srtm 2399d3fb671Srtm acquire(&inode_table_lock); 2409d3fb671Srtm 2419d3fb671Srtm while(ip->busy) 2429d3fb671Srtm sleep(ip, &inode_table_lock); 2439d3fb671Srtm ip->busy = 1; 2449d3fb671Srtm 2459d3fb671Srtm release(&inode_table_lock); 2469d3fb671Srtm } 2479d3fb671Srtm 248bb207a1dSrsc // Caller holds reference to ip and has locked it. 249bb207a1dSrsc // Caller no longer needs to examine / change it. 250bb207a1dSrsc // Unlock it, but keep the reference. 2519d3fb671Srtm void 2529d3fb671Srtm iunlock(struct inode *ip) 2539d3fb671Srtm { 2540d6bbd31Srsc if(ip->busy != 1 || ip->ref < 1) 2559d3fb671Srtm panic("iunlock"); 2569d3fb671Srtm 2579d3fb671Srtm acquire(&inode_table_lock); 2589d3fb671Srtm 2599d3fb671Srtm ip->busy = 0; 2609d3fb671Srtm wakeup(ip); 2619d3fb671Srtm 2629d3fb671Srtm release(&inode_table_lock); 2639d3fb671Srtm } 2649d3fb671Srtm 265bb207a1dSrsc // Return the disk block address of the nth block in inode ip. 26622bac2cbSkaashoek uint 26722bac2cbSkaashoek bmap(struct inode *ip, uint bn) 26822bac2cbSkaashoek { 269d80b06a1Srsc uint *a, x; 270ea2909b6Skaashoek struct buf *inbp; 27122bac2cbSkaashoek 272ea2909b6Skaashoek if(bn >= MAXFILE) 27322bac2cbSkaashoek panic("bmap 1"); 274ea2909b6Skaashoek if(bn < NDIRECT) { 27522bac2cbSkaashoek x = ip->addrs[bn]; 27622bac2cbSkaashoek if(x == 0) 27722bac2cbSkaashoek panic("bmap 2"); 278ea2909b6Skaashoek } else { 2795051da6dSrtm if(ip->addrs[INDIRECT] == 0) 2805051da6dSrtm panic("bmap 3"); 2811be76685Skaashoek inbp = bread(ip->dev, ip->addrs[INDIRECT]); 282ea2909b6Skaashoek a = (uint*) inbp->data; 283ea2909b6Skaashoek x = a[bn - NDIRECT]; 284ea2909b6Skaashoek brelse(inbp); 285ea2909b6Skaashoek if(x == 0) 2865051da6dSrtm panic("bmap 4"); 287ea2909b6Skaashoek } 28822bac2cbSkaashoek return x; 28922bac2cbSkaashoek } 29022bac2cbSkaashoek 291bb207a1dSrsc // Truncate the inode ip, discarding all its data blocks. 29222bac2cbSkaashoek void 2932aa4c3bcSrtm itrunc(struct inode *ip) 29422bac2cbSkaashoek { 295ea2909b6Skaashoek int i, j; 2961be76685Skaashoek struct buf *inbp; 29722bac2cbSkaashoek 298ea2909b6Skaashoek for(i = 0; i < NADDRS; i++) { 29922bac2cbSkaashoek if(ip->addrs[i] != 0) { 300ea2909b6Skaashoek if(i == INDIRECT) { 3011be76685Skaashoek inbp = bread(ip->dev, ip->addrs[INDIRECT]); 3021be76685Skaashoek uint *a = (uint*) inbp->data; 303bcfb84b6Srtm for(j = 0; j < NINDIRECT; j++) { 304ea2909b6Skaashoek if(a[j] != 0) { 305ea2909b6Skaashoek bfree(ip->dev, a[j]); 306ea2909b6Skaashoek a[j] = 0; 307ea2909b6Skaashoek } 308ea2909b6Skaashoek } 3091be76685Skaashoek brelse(inbp); 310ea2909b6Skaashoek } 31122bac2cbSkaashoek bfree(ip->dev, ip->addrs[i]); 31222bac2cbSkaashoek ip->addrs[i] = 0; 31322bac2cbSkaashoek } 31422bac2cbSkaashoek } 31522bac2cbSkaashoek ip->size = 0; 31622bac2cbSkaashoek iupdate(ip); 31722bac2cbSkaashoek } 31822bac2cbSkaashoek 319bb207a1dSrsc // Caller holds reference to ip and has locked it, 320bb207a1dSrsc // possibly editing it. 321bb207a1dSrsc // Release lock and drop the reference. 3229d3fb671Srtm void 32311a9947fSrtm iput(struct inode *ip) 32411a9947fSrtm { 3250d6bbd31Srsc if(ip->ref < 1 || ip->busy != 1) 3269d3fb671Srtm panic("iput"); 3279d3fb671Srtm 3280d6bbd31Srsc if((ip->ref == 1) && (ip->nlink == 0)) { 3292aa4c3bcSrtm itrunc(ip); 3302aa4c3bcSrtm ifree(ip); 3312aa4c3bcSrtm } 33222bac2cbSkaashoek 33311a9947fSrtm acquire(&inode_table_lock); 33411a9947fSrtm 3350d6bbd31Srsc ip->ref -= 1; 33611a9947fSrtm ip->busy = 0; 33711a9947fSrtm wakeup(ip); 33811a9947fSrtm 33911a9947fSrtm release(&inode_table_lock); 34011a9947fSrtm } 3419d3fb671Srtm 342bb207a1dSrsc // Caller holds reference to ip but not lock. 343bb207a1dSrsc // Drop reference. 3449d3fb671Srtm void 34532630628Srtm idecref(struct inode *ip) 3469d3fb671Srtm { 347211ff0c6Srtm ilock(ip); 348211ff0c6Srtm iput(ip); 3499d3fb671Srtm } 3509d3fb671Srtm 351bb207a1dSrsc // Increment reference count for ip. 352d80b06a1Srsc // Returns ip to enable ip = iincref(ip1) idiom. 353d80b06a1Srsc struct inode* 354e958c538Skaashoek iincref(struct inode *ip) 355e958c538Skaashoek { 356e958c538Skaashoek ilock(ip); 3570d6bbd31Srsc ip->ref++; 358e958c538Skaashoek iunlock(ip); 359d80b06a1Srsc return ip; 360e958c538Skaashoek } 361e958c538Skaashoek 362bb207a1dSrsc // Copy stat information from inode. 363e958c538Skaashoek void 3641f544842Skaashoek stati(struct inode *ip, struct stat *st) 3651f544842Skaashoek { 3661dca3afbSrsc st->dev = ip->dev; 3671dca3afbSrsc st->ino = ip->inum; 3681dca3afbSrsc st->type = ip->type; 3691dca3afbSrsc st->nlink = ip->nlink; 3701dca3afbSrsc st->size = ip->size; 3711f544842Skaashoek } 3721f544842Skaashoek 37322bac2cbSkaashoek #define min(a, b) ((a) < (b) ? (a) : (b)) 37422bac2cbSkaashoek 375bb207a1dSrsc // Read data from inode. 376c59361f1Srtm int 37717a85657Srtm readi(struct inode *ip, char *dst, uint off, uint n) 378c59361f1Srtm { 379c59361f1Srtm uint target = n, n1; 380c59361f1Srtm struct buf *bp; 381c59361f1Srtm 382939f9edeSkaashoek if(ip->type == T_DEV) { 3831dca3afbSrsc if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) 384939f9edeSkaashoek return -1; 3851dca3afbSrsc return devsw[ip->major].read(ip->minor, dst, n); 386939f9edeSkaashoek } 387939f9edeSkaashoek 388c59361f1Srtm while(n > 0 && off < ip->size){ 38924111398Skaashoek bp = bread(ip->dev, bmap(ip, off / BSIZE)); 390c59361f1Srtm n1 = min(n, ip->size - off); 39124111398Skaashoek n1 = min(n1, BSIZE - (off % BSIZE)); 39224111398Skaashoek memmove(dst, bp->data + (off % BSIZE), n1); 393c59361f1Srtm n -= n1; 394c59361f1Srtm off += n1; 395c59361f1Srtm dst += n1; 396c59361f1Srtm brelse(bp); 397c59361f1Srtm } 398c59361f1Srtm 399c59361f1Srtm return target - n; 400c59361f1Srtm } 401c59361f1Srtm 402bb207a1dSrsc // Allocate the nth block in inode ip if necessary. 4031be76685Skaashoek static int 404ea2909b6Skaashoek newblock(struct inode *ip, uint lbn) 405ea2909b6Skaashoek { 406ea2909b6Skaashoek struct buf *inbp; 407ea2909b6Skaashoek uint *inaddrs; 408ea2909b6Skaashoek uint b; 409ea2909b6Skaashoek 410ea2909b6Skaashoek if(lbn < NDIRECT) { 411ea2909b6Skaashoek if(ip->addrs[lbn] == 0) { 412ea2909b6Skaashoek b = balloc(ip->dev); 41348b82470Srsc if(b <= 0) 41448b82470Srsc return -1; 415ea2909b6Skaashoek ip->addrs[lbn] = b; 416ea2909b6Skaashoek } 417ea2909b6Skaashoek } else { 418ea2909b6Skaashoek if(ip->addrs[INDIRECT] == 0) { 419ea2909b6Skaashoek b = balloc(ip->dev); 42048b82470Srsc if(b <= 0) 42148b82470Srsc return -1; 422ea2909b6Skaashoek ip->addrs[INDIRECT] = b; 423ea2909b6Skaashoek } 4241be76685Skaashoek inbp = bread(ip->dev, ip->addrs[INDIRECT]); 425ea2909b6Skaashoek inaddrs = (uint*) inbp->data; 426ea2909b6Skaashoek if(inaddrs[lbn - NDIRECT] == 0) { 427ea2909b6Skaashoek b = balloc(ip->dev); 42848b82470Srsc if(b <= 0) 42948b82470Srsc return -1; 430ea2909b6Skaashoek inaddrs[lbn - NDIRECT] = b; 4311be76685Skaashoek bwrite(inbp, ip->addrs[INDIRECT]); 432ea2909b6Skaashoek } 433ea2909b6Skaashoek brelse(inbp); 434ea2909b6Skaashoek } 435ea2909b6Skaashoek return 0; 436ea2909b6Skaashoek } 437ea2909b6Skaashoek 438bb207a1dSrsc // Write data to inode. 439ea2909b6Skaashoek int 44017a85657Srtm writei(struct inode *ip, char *addr, uint off, uint n) 4416fa5ffb5Skaashoek { 4426fa5ffb5Skaashoek if(ip->type == T_DEV) { 4431dca3afbSrsc if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) 444939f9edeSkaashoek return -1; 4451dca3afbSrsc return devsw[ip->major].write(ip->minor, addr, n); 446ea2909b6Skaashoek } else if(ip->type == T_FILE || ip->type == T_DIR) { 44728d9ef04Skaashoek struct buf *bp; 44828d9ef04Skaashoek int r = 0; 44928d9ef04Skaashoek int m; 45028d9ef04Skaashoek int lbn; 45128d9ef04Skaashoek while(r < n) { 45228d9ef04Skaashoek lbn = off / BSIZE; 45348b82470Srsc if(lbn >= MAXFILE) 45448b82470Srsc return r; 455ea2909b6Skaashoek if(newblock(ip, lbn) < 0) { 456ea2909b6Skaashoek cprintf("newblock failed\n"); 457ea2909b6Skaashoek return r; 45828d9ef04Skaashoek } 45922bac2cbSkaashoek m = min(BSIZE - off % BSIZE, n-r); 460ea2909b6Skaashoek bp = bread(ip->dev, bmap(ip, lbn)); 46128d9ef04Skaashoek memmove(bp->data + off % BSIZE, addr, m); 462ea2909b6Skaashoek bwrite(bp, bmap(ip, lbn)); 46328d9ef04Skaashoek brelse(bp); 46428d9ef04Skaashoek r += m; 46528d9ef04Skaashoek off += m; 46628d9ef04Skaashoek } 46728d9ef04Skaashoek if(r > 0) { 46828d9ef04Skaashoek if(off > ip->size) { 46948b82470Srsc if(ip->type == T_DIR) 47048b82470Srsc ip->size = ((off / BSIZE) + 1) * BSIZE; 47148b82470Srsc else 47248b82470Srsc ip->size = off; 47328d9ef04Skaashoek } 47428d9ef04Skaashoek iupdate(ip); 47528d9ef04Skaashoek } 47628d9ef04Skaashoek return r; 4776fa5ffb5Skaashoek } else { 4782aa4c3bcSrtm panic("writei: unknown type"); 4798a8be1b8Srtm return 0; 4806fa5ffb5Skaashoek } 4816fa5ffb5Skaashoek } 4826fa5ffb5Skaashoek 483211ff0c6Srtm // look up a path name, in one of three modes. 484211ff0c6Srtm // NAMEI_LOOKUP: return locked target inode. 485211ff0c6Srtm // NAMEI_CREATE: return locked parent inode. 4865051da6dSrtm // return 0 if name does exist. 4875051da6dSrtm // *ret_last points to last path component (i.e. new file name). 4885051da6dSrtm // *ret_ip points to the the name that did exist, if it did. 4895051da6dSrtm // *ret_ip and *ret_last may be zero even if return value is zero. 490211ff0c6Srtm // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off. 491211ff0c6Srtm // return 0 if name doesn't exist. 4929d3fb671Srtm struct inode* 4930cfc7290Srsc namei(char *path, int mode, uint *ret_off, 4940cfc7290Srsc char **ret_last, struct inode **ret_ip) 4959d3fb671Srtm { 4969d3fb671Srtm struct inode *dp; 4978787cd01Skaashoek struct proc *p = curproc[cpu()]; 498211ff0c6Srtm char *cp = path, *cp1; 4999d3fb671Srtm uint off, dev; 5009d3fb671Srtm struct buf *bp; 5019d3fb671Srtm struct dirent *ep; 50215421863Srsc int i, l, atend; 50315421863Srsc uint ninum; 5049d3fb671Srtm 5055051da6dSrtm if(ret_off) 5065051da6dSrtm *ret_off = 0xffffffff; 5075051da6dSrtm if(ret_last) 5085051da6dSrtm *ret_last = 0; 5095051da6dSrtm if(ret_ip) 5105051da6dSrtm *ret_ip = 0; 5115051da6dSrtm 51248b82470Srsc if(*cp == '/') 51348b82470Srsc dp = iget(rootdev, 1); 5148787cd01Skaashoek else { 515d80b06a1Srsc dp = iincref(p->cwd); 5168787cd01Skaashoek ilock(dp); 5178787cd01Skaashoek } 5189d3fb671Srtm 5190d6bbd31Srsc for(;;){ 5209d3fb671Srtm while(*cp == '/') 5219d3fb671Srtm cp++; 5229d3fb671Srtm 5230633b971Skaashoek if(*cp == '\0'){ 524211ff0c6Srtm if(mode == NAMEI_LOOKUP) 5259d3fb671Srtm return dp; 5265051da6dSrtm if(mode == NAMEI_CREATE && ret_ip){ 5275051da6dSrtm *ret_ip = dp; 5285051da6dSrtm return 0; 5295051da6dSrtm } 530211ff0c6Srtm iput(dp); 531211ff0c6Srtm return 0; 5320633b971Skaashoek } 5339d3fb671Srtm 5349d3fb671Srtm if(dp->type != T_DIR){ 5359d3fb671Srtm iput(dp); 5369d3fb671Srtm return 0; 5379d3fb671Srtm } 5389d3fb671Srtm 5390d6bbd31Srsc for(i = 0; cp[i] != 0 && cp[i] != '/'; i++) 5400d6bbd31Srsc ; 54115421863Srsc l = i; 54215421863Srsc if(i > DIRSIZ) 54315421863Srsc l = DIRSIZ; 5440d6bbd31Srsc 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; 55215421863Srsc if(memcmp(cp, ep->name, l) == 0 && 55315421863Srsc (l == DIRSIZ || ep->name[l]== 0)){ 5540d6bbd31Srsc // entry matches path element 555211ff0c6Srtm off += (uchar*)ep - bp->data; 5569d3fb671Srtm ninum = ep->inum; 5579d3fb671Srtm brelse(bp); 5589d3fb671Srtm cp += i; 5599d3fb671Srtm goto found; 5609d3fb671Srtm } 5619d3fb671Srtm } 5629d3fb671Srtm brelse(bp); 5639d3fb671Srtm } 564211ff0c6Srtm atend = 1; 565211ff0c6Srtm for(cp1 = cp; *cp1; cp1++) 566211ff0c6Srtm if(*cp1 == '/') 567211ff0c6Srtm atend = 0; 5685051da6dSrtm if(mode == NAMEI_CREATE && atend){ 5695051da6dSrtm if(*cp == '\0'){ 5705051da6dSrtm iput(dp); 5715051da6dSrtm return 0; 5725051da6dSrtm } 5735051da6dSrtm *ret_last = cp; 574211ff0c6Srtm return dp; 5755051da6dSrtm } 576211ff0c6Srtm 5779d3fb671Srtm iput(dp); 5789d3fb671Srtm return 0; 5799d3fb671Srtm 5809d3fb671Srtm found: 581211ff0c6Srtm if(mode == NAMEI_DELETE && *cp == '\0'){ 5825f0c20ecSrsc // can't unlink . and .. 5835f0c20ecSrsc if((i == 1 && memcmp(cp-1, ".", 1) == 0) || 5845f0c20ecSrsc (i == 2 && memcmp(cp-2, "..", 2) == 0)){ 5855f0c20ecSrsc iput(dp); 5865f0c20ecSrsc return 0; 5875f0c20ecSrsc } 588211ff0c6Srtm *ret_off = off; 589211ff0c6Srtm return dp; 590211ff0c6Srtm } 5919d3fb671Srtm dev = dp->dev; 5929d3fb671Srtm iput(dp); 5939d3fb671Srtm dp = iget(dev, ninum); 5947ce01cf9Srtm if(dp->type == 0 || dp->nlink < 1) 5957ce01cf9Srtm panic("namei"); 5969d3fb671Srtm } 5979d3fb671Srtm } 598e8d11c2eSkaashoek 599bb207a1dSrsc // Write a new directory entry (name, ino) into the directory dp. 600bb207a1dSrsc // 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 625bb207a1dSrsc // Create the path cp and return its locked inode structure. 626bb207a1dSrsc // 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 643bb207a1dSrsc // Create a new inode named name inside dp 644bb207a1dSrsc // and return its locked inode structure. 645bb207a1dSrsc // 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 666bb207a1dSrsc // 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 705bb207a1dSrsc // 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); 732be29b8e2Srsc ip->nlink++; 7339e5970d5Srtm iupdate(ip); 7349e5970d5Srtm 7355051da6dSrtm wdir(dp, last, ip->inum); 7369e5970d5Srtm iput(dp); 7379e5970d5Srtm iput(ip); 7389e5970d5Srtm 7399e5970d5Srtm return 0; 7409e5970d5Srtm } 741