111a9947fSrtm #include "types.h" 211a9947fSrtm #include "param.h" 311a9947fSrtm #include "x86.h" 411a9947fSrtm #include "mmu.h" 511a9947fSrtm #include "proc.h" 611a9947fSrtm #include "defs.h" 711a9947fSrtm #include "spinlock.h" 811a9947fSrtm #include "buf.h" 911a9947fSrtm #include "fs.h" 1011a9947fSrtm #include "fsvar.h" 116fa5ffb5Skaashoek #include "dev.h" 1211a9947fSrtm 1311a9947fSrtm // these are inodes currently in use 1411a9947fSrtm // an entry is free if count == 0 1511a9947fSrtm struct inode inode[NINODE]; 1632630628Srtm struct spinlock inode_table_lock = { "inode_table" }; 1711a9947fSrtm 189d3fb671Srtm uint rootdev = 1; 199d3fb671Srtm 2024111398Skaashoek static uint 2124111398Skaashoek balloc(uint dev) 2224111398Skaashoek { 2324111398Skaashoek int b; 2424111398Skaashoek struct buf *bp; 2524111398Skaashoek struct superblock *sb; 2624111398Skaashoek int bi; 2724111398Skaashoek int size; 2824111398Skaashoek int ninodes; 2924111398Skaashoek uchar m; 3024111398Skaashoek 3124111398Skaashoek bp = bread(dev, 1); 3224111398Skaashoek sb = (struct superblock *) bp->data; 3324111398Skaashoek size = sb->size; 3424111398Skaashoek ninodes = sb->ninodes; 3524111398Skaashoek 3624111398Skaashoek for (b = 0; b < size; b++) { 3724111398Skaashoek if (b % BPB == 0) { 3824111398Skaashoek brelse(bp); 3924111398Skaashoek bp = bread(dev, BBLOCK(b, ninodes)); 4024111398Skaashoek } 4124111398Skaashoek bi = b % BPB; 4224111398Skaashoek m = 0x1 << (bi % 8); 4324111398Skaashoek if ((bp->data[bi/8] & m) == 0) { // is block free? 4424111398Skaashoek break; 4524111398Skaashoek } 4624111398Skaashoek } 4724111398Skaashoek if (b >= size) 4824111398Skaashoek panic("balloc: out of blocks\n"); 4924111398Skaashoek 5024111398Skaashoek cprintf ("balloc: allocate block %d\n", b); 5124111398Skaashoek bp->data[bi/8] |= 0x1 << (bi % 8); 5224111398Skaashoek bwrite (dev, bp, BBLOCK(b, ninodes)); // mark it allocated on disk 5324111398Skaashoek return b; 5424111398Skaashoek } 5524111398Skaashoek 5624111398Skaashoek 579d3fb671Srtm // returns an inode with busy set and incremented reference count. 5811a9947fSrtm struct inode * 5911a9947fSrtm iget(uint dev, uint inum) 6011a9947fSrtm { 6111a9947fSrtm struct inode *ip, *nip = 0; 6211a9947fSrtm struct dinode *dip; 6311a9947fSrtm struct buf *bp; 6411a9947fSrtm 6511a9947fSrtm acquire(&inode_table_lock); 6611a9947fSrtm 6711a9947fSrtm loop: 6811a9947fSrtm for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ 6911a9947fSrtm if(ip->count > 0 && ip->dev == dev && ip->inum == inum){ 7011a9947fSrtm if(ip->busy){ 7111a9947fSrtm sleep(ip, &inode_table_lock); 7211a9947fSrtm goto loop; 7311a9947fSrtm } 7411a9947fSrtm ip->count++; 7511a9947fSrtm release(&inode_table_lock); 7611a9947fSrtm return ip; 7711a9947fSrtm } 7811a9947fSrtm if(nip == 0 && ip->count == 0) 7911a9947fSrtm nip = ip; 8011a9947fSrtm } 8111a9947fSrtm 8211a9947fSrtm if(nip == 0) 8311a9947fSrtm panic("out of inodes"); 8411a9947fSrtm 8511a9947fSrtm nip->dev = dev; 8611a9947fSrtm nip->inum = inum; 8711a9947fSrtm nip->count = 1; 8811a9947fSrtm nip->busy = 1; 8911a9947fSrtm 9011a9947fSrtm release(&inode_table_lock); 9111a9947fSrtm 9224111398Skaashoek bp = bread(dev, IBLOCK(inum)); 9311a9947fSrtm dip = &((struct dinode *)(bp->data))[inum % IPB]; 9411a9947fSrtm nip->type = dip->type; 95e8d11c2eSkaashoek nip->major = dip->major; 96e8d11c2eSkaashoek nip->minor = dip->minor; 9711a9947fSrtm nip->nlink = dip->nlink; 9811a9947fSrtm nip->size = dip->size; 9911a9947fSrtm memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); 10011a9947fSrtm brelse(bp); 10111a9947fSrtm 10211a9947fSrtm return nip; 10311a9947fSrtm } 10411a9947fSrtm 105e8d11c2eSkaashoek // allocate an inode on disk 106e8d11c2eSkaashoek struct inode * 107e8d11c2eSkaashoek ialloc(uint dev, short type) 108e8d11c2eSkaashoek { 109e8d11c2eSkaashoek struct inode *ip; 110e8d11c2eSkaashoek struct dinode *dip = 0; 111e8d11c2eSkaashoek struct superblock *sb; 112e8d11c2eSkaashoek int ninodes; 113e8d11c2eSkaashoek int inum; 114e8d11c2eSkaashoek struct buf *bp; 115e8d11c2eSkaashoek 116e8d11c2eSkaashoek bp = bread(dev, 1); 11724111398Skaashoek sb = (struct superblock *) bp->data; 118e8d11c2eSkaashoek ninodes = sb->ninodes; 119e8d11c2eSkaashoek brelse(bp); 120e8d11c2eSkaashoek 121e8d11c2eSkaashoek for (inum = 1; inum < ninodes; inum++) { // loop over inode blocks 12224111398Skaashoek bp = bread(dev, IBLOCK(inum)); 123e8d11c2eSkaashoek dip = &((struct dinode *)(bp->data))[inum % IPB]; 124e8d11c2eSkaashoek if (dip->type == 0) { // a free inode 125e8d11c2eSkaashoek break; 126e8d11c2eSkaashoek } 127e8d11c2eSkaashoek brelse(bp); 128e8d11c2eSkaashoek } 129e8d11c2eSkaashoek 130e8d11c2eSkaashoek if (inum >= ninodes) { 13124111398Skaashoek panic ("ialloc: no inodes left\n"); 132e8d11c2eSkaashoek } 133e8d11c2eSkaashoek 134e8d11c2eSkaashoek cprintf ("ialloc: %d\n", inum); 135e8d11c2eSkaashoek dip->type = type; 13624111398Skaashoek bwrite (dev, bp, IBLOCK(inum)); // mark it allocated on the disk 137e8d11c2eSkaashoek brelse(bp); 138e8d11c2eSkaashoek ip = iget (dev, inum); 139e8d11c2eSkaashoek return ip; 140e8d11c2eSkaashoek } 141e8d11c2eSkaashoek 142e8d11c2eSkaashoek void 143e8d11c2eSkaashoek iupdate (struct inode *ip) 144e8d11c2eSkaashoek { 145e8d11c2eSkaashoek struct buf *bp; 146e8d11c2eSkaashoek struct dinode *dip; 147e8d11c2eSkaashoek 14824111398Skaashoek bp = bread(ip->dev, IBLOCK(ip->inum)); 149e8d11c2eSkaashoek dip = &((struct dinode *)(bp->data))[ip->inum % IPB]; 150e8d11c2eSkaashoek dip->type = ip->type; 151e8d11c2eSkaashoek dip->major = ip->major; 152e8d11c2eSkaashoek dip->minor = ip->minor; 153e8d11c2eSkaashoek dip->nlink = ip->nlink; 154e8d11c2eSkaashoek dip->size = ip->size; 15524111398Skaashoek bwrite (ip->dev, bp, IBLOCK(ip->inum)); // mark it allocated on the disk 156e8d11c2eSkaashoek brelse(bp); 157e8d11c2eSkaashoek } 158e8d11c2eSkaashoek 15911a9947fSrtm void 1609d3fb671Srtm ilock(struct inode *ip) 1619d3fb671Srtm { 1629d3fb671Srtm if(ip->count < 1) 1639d3fb671Srtm panic("ilock"); 1649d3fb671Srtm 1659d3fb671Srtm acquire(&inode_table_lock); 1669d3fb671Srtm 1679d3fb671Srtm while(ip->busy) 1689d3fb671Srtm sleep(ip, &inode_table_lock); 1699d3fb671Srtm ip->busy = 1; 1709d3fb671Srtm 1719d3fb671Srtm release(&inode_table_lock); 1729d3fb671Srtm } 1739d3fb671Srtm 1749d3fb671Srtm // caller is holding onto a reference to this inode, but no 1759d3fb671Srtm // longer needs to examine or change it, so clear ip->busy. 1769d3fb671Srtm void 1779d3fb671Srtm iunlock(struct inode *ip) 1789d3fb671Srtm { 1799d3fb671Srtm if(ip->busy != 1) 1809d3fb671Srtm panic("iunlock"); 1819d3fb671Srtm 1829d3fb671Srtm acquire(&inode_table_lock); 1839d3fb671Srtm 1849d3fb671Srtm ip->busy = 0; 1859d3fb671Srtm wakeup(ip); 1869d3fb671Srtm 1879d3fb671Srtm release(&inode_table_lock); 1889d3fb671Srtm } 1899d3fb671Srtm 1909d3fb671Srtm // caller is releasing a reference to this inode. 1919d3fb671Srtm // you must have the inode lock. 1929d3fb671Srtm void 19311a9947fSrtm iput(struct inode *ip) 19411a9947fSrtm { 1959d3fb671Srtm if(ip->count < 1 || ip->busy != 1) 1969d3fb671Srtm panic("iput"); 1979d3fb671Srtm 19811a9947fSrtm acquire(&inode_table_lock); 19911a9947fSrtm 20011a9947fSrtm ip->count -= 1; 20111a9947fSrtm ip->busy = 0; 20211a9947fSrtm wakeup(ip); 20311a9947fSrtm 20411a9947fSrtm release(&inode_table_lock); 20511a9947fSrtm } 2069d3fb671Srtm 2079d3fb671Srtm void 20832630628Srtm idecref(struct inode *ip) 2099d3fb671Srtm { 2109d3fb671Srtm acquire(&inode_table_lock); 2119d3fb671Srtm 21232630628Srtm if(ip->count < 1) 21332630628Srtm panic("idecref"); 21432630628Srtm 21532630628Srtm ip->count -= 1; 2169d3fb671Srtm 2179d3fb671Srtm release(&inode_table_lock); 2189d3fb671Srtm } 2199d3fb671Srtm 2209d3fb671Srtm uint 2219d3fb671Srtm bmap(struct inode *ip, uint bn) 2229d3fb671Srtm { 2239d3fb671Srtm unsigned x; 2249d3fb671Srtm 2259d3fb671Srtm if(bn >= NDIRECT) 2269d3fb671Srtm panic("bmap 1"); 2279d3fb671Srtm x = ip->addrs[bn]; 2289d3fb671Srtm if(x == 0) 2299d3fb671Srtm panic("bmap 2"); 2309d3fb671Srtm return x; 2319d3fb671Srtm } 2329d3fb671Srtm 233c59361f1Srtm #define min(a, b) ((a) < (b) ? (a) : (b)) 234c59361f1Srtm 235c59361f1Srtm int 236c59361f1Srtm readi(struct inode *ip, void *xdst, uint off, uint n) 237c59361f1Srtm { 238c59361f1Srtm char *dst = (char *) xdst; 239c59361f1Srtm uint target = n, n1; 240c59361f1Srtm struct buf *bp; 241c59361f1Srtm 242*939f9edeSkaashoek if (ip->type == T_DEV) { 243*939f9edeSkaashoek if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_read) 244*939f9edeSkaashoek return -1; 245*939f9edeSkaashoek return devsw[ip->major].d_read (ip->minor, xdst, n); 246*939f9edeSkaashoek } 247*939f9edeSkaashoek 248c59361f1Srtm while(n > 0 && off < ip->size){ 24924111398Skaashoek bp = bread(ip->dev, bmap(ip, off / BSIZE)); 250c59361f1Srtm n1 = min(n, ip->size - off); 25124111398Skaashoek n1 = min(n1, BSIZE - (off % BSIZE)); 25224111398Skaashoek memmove(dst, bp->data + (off % BSIZE), n1); 253c59361f1Srtm n -= n1; 254c59361f1Srtm off += n1; 255c59361f1Srtm dst += n1; 256c59361f1Srtm brelse(bp); 257c59361f1Srtm } 258c59361f1Srtm 259c59361f1Srtm return target - n; 260c59361f1Srtm } 261c59361f1Srtm 2626fa5ffb5Skaashoek int 2636fa5ffb5Skaashoek writei(struct inode *ip, void *addr, uint n) 2646fa5ffb5Skaashoek { 2656fa5ffb5Skaashoek if (ip->type == T_DEV) { 266*939f9edeSkaashoek if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write) 267*939f9edeSkaashoek return -1; 2686fa5ffb5Skaashoek return devsw[ip->major].d_write (ip->minor, addr, n); 2696fa5ffb5Skaashoek } else { 2706fa5ffb5Skaashoek panic ("writei: unknown type\n"); 2716fa5ffb5Skaashoek } 2726fa5ffb5Skaashoek } 2736fa5ffb5Skaashoek 2749d3fb671Srtm struct inode * 2759d3fb671Srtm namei(char *path) 2769d3fb671Srtm { 2779d3fb671Srtm struct inode *dp; 2789d3fb671Srtm char *cp = path; 2799d3fb671Srtm uint off, dev; 2809d3fb671Srtm struct buf *bp; 2819d3fb671Srtm struct dirent *ep; 2829d3fb671Srtm int i; 2839d3fb671Srtm unsigned ninum; 2849d3fb671Srtm 2859d3fb671Srtm dp = iget(rootdev, 1); 2869d3fb671Srtm 2879d3fb671Srtm while(*cp == '/') 2889d3fb671Srtm cp++; 2899d3fb671Srtm 2909d3fb671Srtm while(1){ 2919d3fb671Srtm if(*cp == '\0') 2929d3fb671Srtm return dp; 2939d3fb671Srtm 2949d3fb671Srtm if(dp->type != T_DIR){ 2959d3fb671Srtm iput(dp); 2969d3fb671Srtm return 0; 2979d3fb671Srtm } 2989d3fb671Srtm 29924111398Skaashoek for(off = 0; off < dp->size; off += BSIZE){ 30024111398Skaashoek bp = bread(dp->dev, bmap(dp, off / BSIZE)); 3019d3fb671Srtm for(ep = (struct dirent *) bp->data; 30224111398Skaashoek ep < (struct dirent *) (bp->data + BSIZE); 3039d3fb671Srtm ep++){ 3049d3fb671Srtm if(ep->inum == 0) 3059d3fb671Srtm continue; 3069d3fb671Srtm for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++) 3079d3fb671Srtm if(cp[i] != ep->name[i]) 3089d3fb671Srtm break; 3099d3fb671Srtm if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){ 3109d3fb671Srtm ninum = ep->inum; 3119d3fb671Srtm brelse(bp); 3129d3fb671Srtm cp += i; 3139d3fb671Srtm goto found; 3149d3fb671Srtm } 3159d3fb671Srtm } 3169d3fb671Srtm brelse(bp); 3179d3fb671Srtm } 3189d3fb671Srtm iput(dp); 3199d3fb671Srtm return 0; 3209d3fb671Srtm 3219d3fb671Srtm found: 3229d3fb671Srtm dev = dp->dev; 3239d3fb671Srtm iput(dp); 3249d3fb671Srtm dp = iget(dev, ninum); 3259d3fb671Srtm while(*cp == '/') 3269d3fb671Srtm cp++; 3279d3fb671Srtm } 3289d3fb671Srtm } 329e8d11c2eSkaashoek 330e8d11c2eSkaashoek struct inode * 331e8d11c2eSkaashoek mknod(struct inode *dp, char *cp, short type, short major, short minor) 332e8d11c2eSkaashoek { 333e8d11c2eSkaashoek struct inode *ip; 334e8d11c2eSkaashoek struct dirent *ep = 0; 335e8d11c2eSkaashoek int off; 336e8d11c2eSkaashoek int i; 337e8d11c2eSkaashoek struct buf *bp = 0; 338e8d11c2eSkaashoek 339e8d11c2eSkaashoek cprintf("mknod: %s %d %d %d\n", cp, type, major, minor); 340e8d11c2eSkaashoek 341e8d11c2eSkaashoek ip = ialloc(dp->dev, type); 342e8d11c2eSkaashoek if (ip == 0) return 0; 343e8d11c2eSkaashoek ip->major = major; 344e8d11c2eSkaashoek ip->minor = minor; 3456c0e444fSkaashoek ip->size = 0; 3466c0e444fSkaashoek ip->nlink = 0; 3476c0e444fSkaashoek 3486c0e444fSkaashoek iupdate (ip); // write new inode to disk 349e8d11c2eSkaashoek 35024111398Skaashoek for(off = 0; off < dp->size; off += BSIZE) { 35124111398Skaashoek bp = bread(dp->dev, bmap(dp, off / BSIZE)); 352e8d11c2eSkaashoek for(ep = (struct dirent *) bp->data; 35324111398Skaashoek ep < (struct dirent *) (bp->data + BSIZE); 354e8d11c2eSkaashoek ep++){ 355e8d11c2eSkaashoek if(ep->inum == 0) { 356e8d11c2eSkaashoek goto found; 357e8d11c2eSkaashoek } 358e8d11c2eSkaashoek } 359e8d11c2eSkaashoek brelse(bp); 360e8d11c2eSkaashoek } 361e8d11c2eSkaashoek panic("mknod: no dir entry free\n"); 362e8d11c2eSkaashoek 363e8d11c2eSkaashoek found: 364e8d11c2eSkaashoek ep->inum = ip->inum; 365e8d11c2eSkaashoek for(i = 0; i < DIRSIZ && cp[i]; i++) ep->name[i] = cp[i]; 3666c0e444fSkaashoek bwrite (dp->dev, bp, bmap(dp, off/BSIZE)); // write directory block 367e8d11c2eSkaashoek brelse(bp); 3686c0e444fSkaashoek 3696c0e444fSkaashoek dp->size += sizeof(struct dirent); // update directory inode 3706c0e444fSkaashoek iupdate (dp); 3716c0e444fSkaashoek 372e8d11c2eSkaashoek return ip; 373e8d11c2eSkaashoek } 374