📄 fs.c
字号:
#include "types.h"#include "stat.h"#include "param.h"#include "x86.h"#include "mmu.h"#include "proc.h"#include "defs.h"#include "spinlock.h"#include "buf.h"#include "fs.h"#include "fsvar.h"#include "dev.h"// Inode table. The inode table is an in-memory cache of the // on-disk inode structures. If an inode in the table has a non-zero// reference count, then some open files refer to it and it must stay// in memory. If an inode has a zero reference count, it is only in// memory as a cache in hopes of being used again (avoiding a disk read).// Any inode with reference count zero can be evicted from the table.// // In addition to having a reference count, inodes can be marked busy// (just like bufs), meaning that some code has logically locked the // inode, and others are not allowed to look at it. // This locking can last for a long// time (for example, if the inode is busy during a disk access),// so we don't use spin locks. Instead, if a process wants to use// a particular inode, it must sleep(ip) to wait for it to be not busy.// See iget below.struct inode inode[NINODE];struct spinlock inode_table_lock;uint rootdev = 1;voidiinit(void){ initlock(&inode_table_lock, "inode_table");}// Allocate a disk block.static uintballoc(uint dev){ int b; struct buf *bp; struct superblock *sb; int bi = 0; int size; int ninodes; uchar m; bp = bread(dev, 1); sb = (struct superblock*) bp->data; size = sb->size; ninodes = sb->ninodes; for(b = 0; b < size; b++) { if(b % BPB == 0) { brelse(bp); bp = bread(dev, BBLOCK(b, ninodes)); } bi = b % BPB; m = 0x1 << (bi % 8); if((bp->data[bi/8] & m) == 0) { // is block free? break; } } if(b >= size) panic("balloc: out of blocks"); bp->data[bi/8] |= 0x1 << (bi % 8); bwrite(bp, BBLOCK(b, ninodes)); // mark it allocated on disk brelse(bp); return b;}// Free a disk block.static voidbfree(int dev, uint b){ struct buf *bp; struct superblock *sb; int bi; int ninodes; uchar m; bp = bread(dev, 1); sb = (struct superblock*) bp->data; ninodes = sb->ninodes; brelse(bp); bp = bread(dev, b); memset(bp->data, 0, BSIZE); bwrite(bp, b); brelse(bp); bp = bread(dev, BBLOCK(b, ninodes)); bi = b % BPB; m = ~(0x1 << (bi %8)); bp->data[bi/8] &= m; bwrite(bp, BBLOCK(b, ninodes)); // mark it free on disk brelse(bp);}// Find the inode with number inum on device dev// and return an in-memory copy. Loads the inode// from disk into the in-core table if necessary.// The returned inode has busy set and has its ref count incremented.// Caller must iput the return value when done with it.struct inode*iget(uint dev, uint inum){ struct inode *ip, *nip; struct dinode *dip; struct buf *bp; acquire(&inode_table_lock); loop: nip = 0; for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ if(ip->busy){ sleep(ip, &inode_table_lock); // Since we droped inode_table_lock, ip might have been reused // for some other inode entirely. Must start the scan over, // and hopefully this time we will find the inode we want // and it will not be busy. goto loop; } ip->ref++; ip->busy = 1; release(&inode_table_lock); return ip; } if(nip == 0 && ip->ref == 0) nip = ip; } if(nip == 0) panic("out of inodes"); nip->dev = dev; nip->inum = inum; nip->ref = 1; nip->busy = 1; release(&inode_table_lock); bp = bread(dev, IBLOCK(inum)); dip = &((struct dinode*)(bp->data))[inum % IPB]; nip->type = dip->type; nip->major = dip->major; nip->minor = dip->minor; nip->nlink = dip->nlink; nip->size = dip->size; memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); brelse(bp); return nip;}// Copy inode in memory, which has changed, to disk.// Caller must have locked ip.voidiupdate(struct inode *ip){ struct buf *bp; struct dinode *dip; bp = bread(ip->dev, IBLOCK(ip->inum)); dip = &((struct dinode*)(bp->data))[ip->inum % IPB]; dip->type = ip->type; dip->major = ip->major; dip->minor = ip->minor; dip->nlink = ip->nlink; dip->size = ip->size; memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); bwrite(bp, IBLOCK(ip->inum)); // mark it allocated on the disk brelse(bp);}// Allocate a new inode with the given type// from the file system on device dev.struct inode*ialloc(uint dev, short type){ struct inode *ip; struct dinode *dip = 0; struct superblock *sb; int ninodes; int inum; struct buf *bp; bp = bread(dev, 1); sb = (struct superblock*) bp->data; ninodes = sb->ninodes; brelse(bp); for(inum = 1; inum < ninodes; inum++) { // loop over inode blocks bp = bread(dev, IBLOCK(inum)); dip = &((struct dinode*)(bp->data))[inum % IPB]; if(dip->type == 0) { // a free inode break; } brelse(bp); } if(inum >= ninodes) panic("ialloc: no inodes left"); memset(dip, 0, sizeof(*dip)); dip->type = type; bwrite(bp, IBLOCK(inum)); // mark it allocated on the disk brelse(bp); ip = iget(dev, inum); return ip;}// Free the given inode from its file system.static voidifree(struct inode *ip){ ip->type = 0; iupdate(ip);}// Lock the given inode (wait for it to be not busy,// and then ip->busy). // Caller must already hold a reference to ip.// Otherwise, if all the references to ip go away,// it might be reused underfoot.voidilock(struct inode *ip){ if(ip->ref < 1) panic("ilock"); acquire(&inode_table_lock); while(ip->busy) sleep(ip, &inode_table_lock); ip->busy = 1; release(&inode_table_lock);}// Caller holds reference to ip and has locked it.// Caller no longer needs to examine / change it.// Unlock it, but keep the reference.voidiunlock(struct inode *ip){ if(ip->busy != 1 || ip->ref < 1) panic("iunlock"); acquire(&inode_table_lock); ip->busy = 0; wakeup(ip); release(&inode_table_lock);}// Return the disk block address of the nth block in inode ip.uintbmap(struct inode *ip, uint bn){ unsigned x; uint *a; struct buf *inbp; if(bn >= MAXFILE) panic("bmap 1"); if(bn < NDIRECT) { x = ip->addrs[bn]; if(x == 0) panic("bmap 2"); } else { if(ip->addrs[INDIRECT] == 0) panic("bmap 3"); inbp = bread(ip->dev, ip->addrs[INDIRECT]); a = (uint*) inbp->data; x = a[bn - NDIRECT]; brelse(inbp); if(x == 0) panic("bmap 4"); } return x;}// Truncate the inode ip, discarding all its data blocks.voiditrunc(struct inode *ip){ int i, j; struct buf *inbp; for(i = 0; i < NADDRS; i++) { if(ip->addrs[i] != 0) { if(i == INDIRECT) { inbp = bread(ip->dev, ip->addrs[INDIRECT]); uint *a = (uint*) inbp->data; for(j = 0; j < NINDIRECT; j++) { if(a[j] != 0) { bfree(ip->dev, a[j]); a[j] = 0; } } brelse(inbp); } bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } ip->size = 0; iupdate(ip);}// Caller holds reference to ip and has locked it,// possibly editing it.// Release lock and drop the reference.voidiput(struct inode *ip){ if(ip->ref < 1 || ip->busy != 1) panic("iput"); if((ip->ref == 1) && (ip->nlink == 0)) { itrunc(ip); ifree(ip); } acquire(&inode_table_lock); ip->ref -= 1; ip->busy = 0; wakeup(ip); release(&inode_table_lock);}// Caller holds reference to ip but not lock.// Drop reference.voididecref(struct inode *ip){ ilock(ip); iput(ip);}// Increment reference count for ip.voidiincref(struct inode *ip){ ilock(ip); ip->ref++; iunlock(ip);}// Copy stat information from inode.voidstati(struct inode *ip, struct stat *st){ st->dev = ip->dev; st->ino = ip->inum; st->type = ip->type; st->nlink = ip->nlink;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -