提交 d065f375 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

rcu-enabled icache, still broken

上级 ba2fdf81
...@@ -18,6 +18,7 @@ struct inode { ...@@ -18,6 +18,7 @@ struct inode {
int ref; // Reference count int ref; // Reference count
int flags; // I_BUSY, I_VALID int flags; // I_BUSY, I_VALID
struct condvar cv; struct condvar cv;
struct spinlock lock;
short type; // copy of disk inode short type; // copy of disk inode
short major; short major;
...@@ -29,6 +30,7 @@ struct inode { ...@@ -29,6 +30,7 @@ struct inode {
#define I_BUSY 0x1 #define I_BUSY 0x1
#define I_VALID 0x2 #define I_VALID 0x2
#define I_FREE 0x4
// device implementations // device implementations
......
...@@ -131,18 +131,19 @@ bfree(int dev, uint b) ...@@ -131,18 +131,19 @@ bfree(int dev, uint b)
// responsibility to lock them before using them. A non-zero // responsibility to lock them before using them. A non-zero
// ip->ref keeps these unlocked inodes in the cache. // ip->ref keeps these unlocked inodes in the cache.
struct { static struct ns *ins;
struct spinlock lock;
struct inode inode[NINODE];
} __attribute__ ((aligned (CACHELINE))) icache;
void void
iinit(void) iinit(void)
{ {
int i; ins = nsalloc(0);
initlock(&icache.lock, "icache"); for (int i = 0; i < NINODE; i++) {
for (i = 0; i < NINODE; i++) { struct inode *ip = kmalloc(sizeof(*ip));
initcondvar(&icache.inode[i].cv, "icache-cv"); memset(ip, 0, sizeof(*ip));
ip->inum = -i-1;
initlock(&ip->lock, "icache-lock");
initcondvar(&ip->cv, "icache-cv");
ns_insert(ins, ip->inum, ip);
} }
} }
...@@ -203,6 +204,17 @@ iupdate(struct inode *ip) ...@@ -203,6 +204,17 @@ iupdate(struct inode *ip)
brelse(bp); brelse(bp);
} }
static void *
evict(uint key, void *p)
{
struct inode *ip = p;
acquire(&ip->lock);
if (ip->ref == 0)
return ip;
release(&ip->lock);
return 0;
}
// Find the inode with number inum on device dev // Find the inode with number inum on device dev
// and return the in-memory copy. // and return the in-memory copy.
// The inode is not locked, so someone else might // The inode is not locked, so someone else might
...@@ -213,35 +225,46 @@ iupdate(struct inode *ip) ...@@ -213,35 +225,46 @@ iupdate(struct inode *ip)
struct inode* struct inode*
iget(uint dev, uint inum) iget(uint dev, uint inum)
{ {
struct inode *ip, *empty; struct inode *ip;
acquire(&icache.lock);
retry:
// Try for cached inode. // Try for cached inode.
empty = 0; ip = ns_lookup(ins, inum); // XXX ignore dev
for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){ if (ip) {
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ if (ip->dev != dev) panic("iget dev mismatch");
ip->ref++; acquire(&ip->lock);
while((ip->flags & I_VALID) == 0) __sync_fetch_and_add(&ip->ref, 1);
cv_sleep(&ip->cv, &icache.lock); if (ip->flags & I_FREE) {
release(&icache.lock); release(&ip->lock);
return ip; goto retry;
} }
if(empty == 0 && ip->ref == 0) // Remember empty slot.
empty = ip; while((ip->flags & I_VALID) == 0)
cv_sleep(&ip->cv, &ip->lock);
release(&ip->lock);
return ip;
} }
// Allocate fresh inode cache slot. // Allocate fresh inode cache slot.
if(empty == 0) struct inode *victim = ns_enumerate(ins, evict);
panic("iget: no inodes"); if (!victim)
panic("iget out of space");
ip = empty; victim->flags |= I_FREE;
release(&victim->lock);
rcu_delayed(victim, kmfree);
ip = kmalloc(sizeof(*ip));
ip->dev = dev; ip->dev = dev;
ip->inum = inum; ip->inum = inum;
ip->ref = 1; ip->ref = 1;
ip->flags = I_BUSY; ip->flags = I_BUSY;
release(&icache.lock); initlock(&ip->lock, "icache-lock");
initcondvar(&ip->cv, "icache-cv");
if (ns_insert(ins, ip->inum, ip) < 0) {
rcu_delayed(ip, kmfree);
goto retry;
}
struct buf *bp = bread(ip->dev, IBLOCK(ip->inum)); struct buf *bp = bread(ip->dev, IBLOCK(ip->inum));
struct dinode *dip = (struct dinode*)bp->data + ip->inum%IPB; struct dinode *dip = (struct dinode*)bp->data + ip->inum%IPB;
ip->type = dip->type; ip->type = dip->type;
...@@ -278,11 +301,11 @@ ilock(struct inode *ip) ...@@ -278,11 +301,11 @@ ilock(struct inode *ip)
if(ip == 0 || ip->ref < 1) if(ip == 0 || ip->ref < 1)
panic("ilock"); panic("ilock");
acquire(&icache.lock); acquire(&ip->lock);
while(ip->flags & I_BUSY) while(ip->flags & I_BUSY)
cv_sleep(&ip->cv, &icache.lock); cv_sleep(&ip->cv, &ip->lock);
ip->flags |= I_BUSY; ip->flags |= I_BUSY;
release(&icache.lock); release(&ip->lock);
if((ip->flags & I_VALID) == 0) if((ip->flags & I_VALID) == 0)
panic("ilock"); panic("ilock");
...@@ -295,10 +318,10 @@ iunlock(struct inode *ip) ...@@ -295,10 +318,10 @@ iunlock(struct inode *ip)
if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1) if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1)
panic("iunlock"); panic("iunlock");
acquire(&icache.lock); acquire(&ip->lock);
ip->flags &= ~I_BUSY; ip->flags &= ~I_BUSY;
cv_wakeup(&ip->cv); cv_wakeup(&ip->cv);
release(&icache.lock); release(&ip->lock);
} }
// Caller holds reference to unlocked ip. Drop reference. // Caller holds reference to unlocked ip. Drop reference.
...@@ -306,26 +329,26 @@ void ...@@ -306,26 +329,26 @@ void
iput(struct inode *ip) iput(struct inode *ip)
{ {
if(__sync_sub_and_fetch(&ip->ref, 1) == 0) { if(__sync_sub_and_fetch(&ip->ref, 1) == 0) {
acquire(&icache.lock); acquire(&ip->lock);
if (ip->nlink == 0){ if (ip->ref == 0 && ip->nlink == 0) {
// inode is no longer used: truncate and free inode. // inode is no longer used: truncate and free inode.
if(ip->flags & I_BUSY) if(ip->flags & I_BUSY)
panic("iput busy"); panic("iput busy");
if((ip->flags & I_VALID) == 0) if((ip->flags & I_VALID) == 0)
panic("iput not valid"); panic("iput not valid");
ip->flags |= I_BUSY; ip->flags |= I_BUSY;
release(&icache.lock); release(&ip->lock);
itrunc(ip); itrunc(ip);
ip->type = 0; ip->type = 0;
ip->major = 0; ip->major = 0;
ip->minor = 0; ip->minor = 0;
ip->gen += 1; ip->gen += 1;
iupdate(ip); iupdate(ip);
acquire(&icache.lock); acquire(&ip->lock);
ip->flags &= ~I_BUSY; ip->flags &= ~I_BUSY;
cv_wakeup(&ip->cv); cv_wakeup(&ip->cv);
} }
release(&icache.lock); release(&ip->lock);
} }
} }
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论