Rename icache to itable

The inode cache isn't really a cache. The main purpose of it is to
allow for synchronization (locking individual inodes), providing
long-lived references to inodes, and ensuring that there is only inode
in memory.
This commit is contained in:
Frans Kaashoek 2020-11-23 19:30:15 -05:00
parent 6e3f75c2aa
commit 077323a8f0

View file

@ -113,9 +113,9 @@ bfree(int dev, uint b)
// sb.startinode. Each inode has a number, indicating its // sb.startinode. Each inode has a number, indicating its
// position on the disk. // position on the disk.
// //
// The kernel keeps a cache of in-use inodes in memory // The kernel keeps a table of in-use inodes in memory
// to provide a place for synchronizing access // to provide a place for synchronizing access
// to inodes used by multiple processes. The cached // to inodes used by multiple processes. The in-memory
// inodes include book-keeping information that is // inodes include book-keeping information that is
// not stored on disk: ip->ref and ip->valid. // not stored on disk: ip->ref and ip->valid.
// //
@ -127,15 +127,15 @@ bfree(int dev, uint b)
// is non-zero. ialloc() allocates, and iput() frees if // is non-zero. ialloc() allocates, and iput() frees if
// the reference and link counts have fallen to zero. // the reference and link counts have fallen to zero.
// //
// * Referencing in cache: an entry in the inode cache // * Referencing in table: an entry in the inode table
// is free if ip->ref is zero. Otherwise ip->ref tracks // is free if ip->ref is zero. Otherwise ip->ref tracks
// the number of in-memory pointers to the entry (open // the number of in-memory pointers to the entry (open
// files and current directories). iget() finds or // files and current directories). iget() finds or
// creates a cache entry and increments its ref; iput() // creates a table entry and increments its ref; iput()
// decrements ref. // decrements ref.
// //
// * Valid: the information (type, size, &c) in an inode // * Valid: the information (type, size, &c) in an inode
// cache entry is only correct when ip->valid is 1. // table entry is only correct when ip->valid is 1.
// ilock() reads the inode from // ilock() reads the inode from
// the disk and sets ip->valid, while iput() clears // the disk and sets ip->valid, while iput() clears
// ip->valid if ip->ref has fallen to zero. // ip->valid if ip->ref has fallen to zero.
@ -156,16 +156,16 @@ bfree(int dev, uint b)
// and only lock it for short periods (e.g., in read()). // and only lock it for short periods (e.g., in read()).
// The separation also helps avoid deadlock and races during // The separation also helps avoid deadlock and races during
// pathname lookup. iget() increments ip->ref so that the inode // pathname lookup. iget() increments ip->ref so that the inode
// stays cached and pointers to it remain valid. // stays in the table and pointers to it remain valid.
// //
// Many internal file system functions expect the caller to // Many internal file system functions expect the caller to
// have locked the inodes involved; this lets callers create // have locked the inodes involved; this lets callers create
// multi-step atomic operations. // multi-step atomic operations.
// //
// The icache.lock spin-lock protects the allocation of icache // The itable.lock spin-lock protects the allocation of itable
// entries. Since ip->ref indicates whether an entry is free, // entries. Since ip->ref indicates whether an entry is free,
// and ip->dev and ip->inum indicate which i-node an entry // and ip->dev and ip->inum indicate which i-node an entry
// holds, one must hold icache.lock while using any of those fields. // holds, one must hold itable.lock while using any of those fields.
// //
// An ip->lock sleep-lock protects all ip-> fields other than ref, // An ip->lock sleep-lock protects all ip-> fields other than ref,
// dev, and inum. One must hold ip->lock in order to // dev, and inum. One must hold ip->lock in order to
@ -174,16 +174,16 @@ bfree(int dev, uint b)
struct { struct {
struct spinlock lock; struct spinlock lock;
struct inode inode[NINODE]; struct inode inode[NINODE];
} icache; } itable;
void void
iinit() iinit()
{ {
int i = 0; int i = 0;
initlock(&icache.lock, "icache"); initlock(&itable.lock, "itable");
for(i = 0; i < NINODE; i++) { for(i = 0; i < NINODE; i++) {
initsleeplock(&icache.inode[i].lock, "inode"); initsleeplock(&itable.inode[i].lock, "inode");
} }
} }
@ -216,7 +216,7 @@ ialloc(uint dev, short type)
// Copy a modified in-memory inode to disk. // Copy a modified in-memory inode to disk.
// Must be called after every change to an ip->xxx field // Must be called after every change to an ip->xxx field
// that lives on disk, since i-node cache is write-through. // that lives on disk.
// Caller must hold ip->lock. // Caller must hold ip->lock.
void void
iupdate(struct inode *ip) iupdate(struct inode *ip)
@ -244,21 +244,21 @@ iget(uint dev, uint inum)
{ {
struct inode *ip, *empty; struct inode *ip, *empty;
acquire(&icache.lock); acquire(&itable.lock);
// Is the inode already cached? // Is the inode already in the table?
empty = 0; empty = 0;
for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){ for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
ip->ref++; ip->ref++;
release(&icache.lock); release(&itable.lock);
return ip; return ip;
} }
if(empty == 0 && ip->ref == 0) // Remember empty slot. if(empty == 0 && ip->ref == 0) // Remember empty slot.
empty = ip; empty = ip;
} }
// Recycle an inode cache entry. // Recycle an inode entry.
if(empty == 0) if(empty == 0)
panic("iget: no inodes"); panic("iget: no inodes");
@ -267,7 +267,7 @@ iget(uint dev, uint inum)
ip->inum = inum; ip->inum = inum;
ip->ref = 1; ip->ref = 1;
ip->valid = 0; ip->valid = 0;
release(&icache.lock); release(&itable.lock);
return ip; return ip;
} }
@ -277,9 +277,9 @@ iget(uint dev, uint inum)
struct inode* struct inode*
idup(struct inode *ip) idup(struct inode *ip)
{ {
acquire(&icache.lock); acquire(&itable.lock);
ip->ref++; ip->ref++;
release(&icache.lock); release(&itable.lock);
return ip; return ip;
} }
@ -323,7 +323,7 @@ iunlock(struct inode *ip)
} }
// Drop a reference to an in-memory inode. // Drop a reference to an in-memory inode.
// If that was the last reference, the inode cache entry can // If that was the last reference, the inode table entry can
// be recycled. // be recycled.
// If that was the last reference and the inode has no links // If that was the last reference and the inode has no links
// to it, free the inode (and its content) on disk. // to it, free the inode (and its content) on disk.
@ -332,7 +332,7 @@ iunlock(struct inode *ip)
void void
iput(struct inode *ip) iput(struct inode *ip)
{ {
acquire(&icache.lock); acquire(&itable.lock);
if(ip->ref == 1 && ip->valid && ip->nlink == 0){ if(ip->ref == 1 && ip->valid && ip->nlink == 0){
// inode has no links and no other references: truncate and free. // inode has no links and no other references: truncate and free.
@ -341,7 +341,7 @@ iput(struct inode *ip)
// so this acquiresleep() won't block (or deadlock). // so this acquiresleep() won't block (or deadlock).
acquiresleep(&ip->lock); acquiresleep(&ip->lock);
release(&icache.lock); release(&itable.lock);
itrunc(ip); itrunc(ip);
ip->type = 0; ip->type = 0;
@ -350,11 +350,11 @@ iput(struct inode *ip)
releasesleep(&ip->lock); releasesleep(&ip->lock);
acquire(&icache.lock); acquire(&itable.lock);
} }
ip->ref--; ip->ref--;
release(&icache.lock); release(&itable.lock);
} }
// Common idiom: unlock, then put. // Common idiom: unlock, then put.