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

use namespaces for buffer cache (possibly broken)

上级 27e046f9
...@@ -28,36 +28,47 @@ ...@@ -28,36 +28,47 @@
#include "condvar.h" #include "condvar.h"
#include "buf.h" #include "buf.h"
struct { static struct ns *bufns;
struct spinlock lock;
struct buf buf[NBUF];
// Linked list of all buffers, through prev/next.
// head.next is most recently used.
struct buf head;
} bcache;
void void
binit(void) binit(void)
{ {
struct buf *b; bufns = nsalloc(0);
initlock(&bcache.lock, "bcache"); for (uint i = 0; i < NBUF; i++) {
struct buf *b = kmalloc(sizeof(*b));
//PAGEBREAK! b->dev = 0xdeadbeef;
// Create linked list of buffers b->sector = -i; /* dummy to pre-allocate NBUF spaces for evict */
bcache.head.prev = &bcache.head; b->flags = 0;
bcache.head.next = &bcache.head; initlock(&b->lock, "bcache-lock");
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
b->next = bcache.head.next;
b->prev = &bcache.head;
b->dev = -1;
bcache.head.next->prev = b;
bcache.head.next = b;
initcondvar(&b->cv, "bcache-cv"); initcondvar(&b->cv, "bcache-cv");
if (ns_insert(bufns, b->sector, b) < 0)
panic("binit ns_insert");
} }
} }
static void *
evict(uint key, void *bp)
{
struct buf *b = bp;
acquire(&b->lock);
if ((b->flags & (B_BUSY | B_VALID)) == 0)
return b;
release(&b->lock);
return 0;
}
static void *
evict_valid(uint key, void *bp)
{
struct buf *b = bp;
acquire(&b->lock);
if ((b->flags & B_BUSY) == 0)
return b;
release(&b->lock);
return 0;
}
// Look through buffer cache for sector on device dev. // Look through buffer cache for sector on device dev.
// If not found, allocate fresh block. // If not found, allocate fresh block.
// In either case, return locked buffer. // In either case, return locked buffer.
...@@ -66,33 +77,50 @@ bget(uint dev, uint sector) ...@@ -66,33 +77,50 @@ bget(uint dev, uint sector)
{ {
struct buf *b; struct buf *b;
acquire(&bcache.lock);
loop: loop:
// Try for cached block. // Try for cached block.
for(b = bcache.head.next; b != &bcache.head; b = b->next){ // XXX ignore dev
if(b->dev == dev && b->sector == sector){ rcu_begin_read();
if(!(b->flags & B_BUSY)){ b = ns_lookup(bufns, sector);
b->flags |= B_BUSY; if (b) {
release(&bcache.lock); acquire(&b->lock);
return b; if (b->dev != dev)
} panic("dev mismatch");
cv_sleep(&b->cv, &bcache.lock); if (!(b->flags & B_BUSY)) {
goto loop; b->flags |= B_BUSY;
release(&b->lock);
rcu_end_read();
return b;
} }
cv_sleep(&b->cv, &b->lock);
release(&b->lock);
goto loop;
} }
rcu_end_read();
// Allocate fresh block. // Allocate fresh block.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ struct buf *victim = ns_enumerate(bufns, evict);
if((b->flags & B_BUSY) == 0){ if (victim == 0)
b->dev = dev; victim = ns_enumerate(bufns, evict_valid);
b->sector = sector; if (victim == 0)
b->flags = B_BUSY; panic("bget all busy");
release(&bcache.lock); victim->flags |= B_BUSY;
return b; ns_remove(bufns, victim->sector, victim);
} release(&victim->lock);
rcu_delayed(victim, kmfree);
b = kmalloc(sizeof(*b));
b->dev = dev;
b->sector = sector;
b->flags = B_BUSY;
initlock(&b->lock, "bcache-lock");
initcondvar(&b->cv, "bcache-cv");
if (ns_insert(bufns, b->sector, b) < 0) {
rcu_delayed(b, kmfree);
goto loop;
} }
panic("bget: no buffers"); return b;
} }
// Return a B_BUSY buf with the contents of the indicated disk sector. // Return a B_BUSY buf with the contents of the indicated disk sector.
...@@ -121,21 +149,11 @@ bwrite(struct buf *b) ...@@ -121,21 +149,11 @@ bwrite(struct buf *b)
void void
brelse(struct buf *b) brelse(struct buf *b)
{ {
acquire(&b->lock);
if((b->flags & B_BUSY) == 0) if((b->flags & B_BUSY) == 0)
panic("brelse"); panic("brelse");
acquire(&bcache.lock);
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head.next;
b->prev = &bcache.head;
bcache.head.next->prev = b;
bcache.head.next = b;
b->flags &= ~B_BUSY; b->flags &= ~B_BUSY;
release(&b->lock);
cv_wakeup(&b->cv); cv_wakeup(&b->cv);
release(&bcache.lock);
} }
...@@ -6,6 +6,7 @@ struct buf { ...@@ -6,6 +6,7 @@ struct buf {
struct buf *next; struct buf *next;
struct buf *qnext; // disk queue struct buf *qnext; // disk queue
struct condvar cv; struct condvar cv;
struct spinlock lock;
uchar data[512]; uchar data[512];
}; };
#define B_BUSY 0x1 // buffer is locked by some process #define B_BUSY 0x1 // buffer is locked by some process
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论