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

read-write locks for buffer cache

上级 9f969fb4
......@@ -54,7 +54,7 @@ evict(uint key, void *bp)
{
struct buf *b = bp;
acquire(&b->lock);
if ((b->flags & (B_BUSY | B_VALID)) == 0)
if ((b->flags & (B_BUSYR | B_BUSYW | B_VALID)) == 0)
return b;
release(&b->lock);
return 0;
......@@ -65,7 +65,7 @@ evict_valid(uint key, void *bp)
{
struct buf *b = bp;
acquire(&b->lock);
if ((b->flags & B_BUSY) == 0)
if ((b->flags & (B_BUSYR | B_BUSYW)) == 0)
return b;
release(&b->lock);
return 0;
......@@ -75,7 +75,7 @@ evict_valid(uint key, void *bp)
// If not found, allocate fresh block.
// In either case, return locked buffer.
static struct buf*
bget(uint dev, uint sector)
bget(uint dev, uint sector, int writer)
{
struct buf *b;
......@@ -88,8 +88,9 @@ bget(uint dev, uint sector)
acquire(&b->lock);
if (b->dev != dev)
panic("dev mismatch");
if (!(b->flags & B_BUSY)) {
b->flags |= B_BUSY;
if (!(b->flags & (B_BUSYW | (writer ? B_BUSYR : 0)))) {
b->flags |= B_BUSYR | (writer ? B_BUSYW : 0);
__sync_fetch_and_add(&b->readbusy, 1);
release(&b->lock);
rcu_end_read();
return b;
......@@ -108,7 +109,8 @@ bget(uint dev, uint sector)
victim = ns_enumerate(bufns, evict_valid);
if (victim == 0)
panic("bget all busy");
victim->flags |= B_BUSY;
victim->flags |= B_BUSYR | B_BUSYW;
__sync_fetch_and_add(&victim->readbusy, 1);
ns_remove(bufns, victim->sector, victim);
release(&victim->lock);
rcu_delayed(victim, kmfree);
......@@ -116,7 +118,8 @@ bget(uint dev, uint sector)
b = kmalloc(sizeof(*b));
b->dev = dev;
b->sector = sector;
b->flags = B_BUSY;
b->flags = B_BUSYR | B_BUSYW;
b->readbusy = 1;
initlock(&b->lock, "bcache-lock");
initcondvar(&b->cv, "bcache-cv");
if (ns_insert(bufns, b->sector, b) < 0) {
......@@ -128,11 +131,11 @@ bget(uint dev, uint sector)
// Return a B_BUSY buf with the contents of the indicated disk sector.
struct buf*
bread(uint dev, uint sector)
bread(uint dev, uint sector, int writer)
{
struct buf *b;
b = bget(dev, sector);
b = bget(dev, sector, writer);
if(!(b->flags & B_VALID))
iderw(b);
return b;
......@@ -142,7 +145,7 @@ bread(uint dev, uint sector)
void
bwrite(struct buf *b)
{
if((b->flags & B_BUSY) == 0)
if((b->flags & B_BUSYW) == 0)
panic("bwrite");
b->flags |= B_DIRTY;
if (writeback)
......@@ -154,9 +157,10 @@ void
brelse(struct buf *b)
{
acquire(&b->lock);
if((b->flags & B_BUSY) == 0)
if((b->flags & (B_BUSYR | B_BUSYW)) == 0)
panic("brelse");
b->flags &= ~B_BUSY;
int lastreader = __sync_sub_and_fetch(&b->readbusy, 1);
b->flags &= ~(B_BUSYW | ((lastreader==0) ? B_BUSYR : 0));
release(&b->lock);
cv_wakeup(&b->cv);
}
......
......@@ -2,6 +2,7 @@ struct buf {
int flags;
uint dev;
uint sector;
int readbusy;
struct buf *prev; // LRU cache list
struct buf *next;
struct buf *qnext; // disk queue
......@@ -9,7 +10,8 @@ struct buf {
struct spinlock lock;
uchar data[512];
};
#define B_BUSY 0x1 // buffer is locked by some process
#define B_VALID 0x2 // buffer has been read from disk
#define B_DIRTY 0x4 // buffer needs to be written to disk
#define B_BUSYR 0x1 // buffer is locked by some process
#define B_BUSYW 0x2 // buffer is locked by some process
#define B_VALID 0x4 // buffer has been read from disk
#define B_DIRTY 0x8 // buffer needs to be written to disk
......@@ -14,7 +14,7 @@ struct ns;
// bio.c
void binit(void);
struct buf* bread(uint, uint);
struct buf* bread(uint, uint, int writer);
void brelse(struct buf*);
void bwrite(struct buf*);
......
......@@ -32,7 +32,7 @@ readsb(int dev, struct superblock *sb)
{
struct buf *bp;
bp = bread(dev, 1);
bp = bread(dev, 1, 0);
memmove(sb, bp->data, sizeof(*sb));
brelse(bp);
}
......@@ -43,7 +43,7 @@ bzero(int dev, int bno)
{
struct buf *bp;
bp = bread(dev, bno);
bp = bread(dev, bno, 1);
memset(bp->data, 0, BSIZE);
bwrite(bp);
brelse(bp);
......@@ -62,7 +62,7 @@ balloc(uint dev)
bp = 0;
readsb(dev, &sb);
for(b = 0; b < sb.size; b += BPB){
bp = bread(dev, BBLOCK(b, sb.ninodes));
bp = bread(dev, BBLOCK(b, sb.ninodes), 1);
for(bi = 0; bi < BPB; bi++){
m = 1 << (bi % 8);
if((bp->data[bi/8] & m) == 0){ // Is block free?
......@@ -88,7 +88,7 @@ bfree(int dev, uint b)
bzero(dev, b);
readsb(dev, &sb);
bp = bread(dev, BBLOCK(b, sb.ninodes));
bp = bread(dev, BBLOCK(b, sb.ninodes), 1);
bi = b % BPB;
m = 1 << (bi % 8);
if((bp->data[bi/8] & m) == 0)
......@@ -160,7 +160,7 @@ ialloc(uint dev, short type)
readsb(dev, &sb);
for(inum = 1; inum < sb.ninodes; inum++){ // loop over inode blocks
bp = bread(dev, IBLOCK(inum));
bp = bread(dev, IBLOCK(inum), 1);
dip = (struct dinode*)bp->data + inum%IPB;
int seemsfree = (dip->type == 0);
brelse(bp);
......@@ -191,7 +191,7 @@ iupdate(struct inode *ip)
struct buf *bp;
struct dinode *dip;
bp = bread(ip->dev, IBLOCK(ip->inum));
bp = bread(ip->dev, IBLOCK(ip->inum), 1);
dip = (struct dinode*)bp->data + ip->inum%IPB;
dip->type = ip->type;
dip->major = ip->major;
......@@ -268,7 +268,7 @@ iget(uint dev, uint inum)
goto retry;
}
struct buf *bp = bread(ip->dev, IBLOCK(ip->inum));
struct buf *bp = bread(ip->dev, IBLOCK(ip->inum), 0);
struct dinode *dip = (struct dinode*)bp->data + ip->inum%IPB;
ip->type = dip->type;
ip->major = dip->major;
......@@ -394,7 +394,7 @@ bmap(struct inode *ip, uint bn)
// Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
bp = bread(ip->dev, addr, 1);
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
......@@ -425,7 +425,7 @@ itrunc(struct inode *ip)
}
if(ip->addrs[NDIRECT]){
bp = bread(ip->dev, ip->addrs[NDIRECT]);
bp = bread(ip->dev, ip->addrs[NDIRECT], 0);
a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
if(a[j])
......@@ -471,7 +471,7 @@ readi(struct inode *ip, char *dst, uint off, uint n)
n = ip->size - off;
for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
bp = bread(ip->dev, bmap(ip, off/BSIZE));
bp = bread(ip->dev, bmap(ip, off/BSIZE), 0);
m = min(n - tot, BSIZE - off%BSIZE);
memmove(dst, bp->data + off%BSIZE, m);
brelse(bp);
......@@ -499,7 +499,7 @@ writei(struct inode *ip, char *src, uint off, uint n)
n = MAXFILE*BSIZE - off;
for(tot=0; tot<n; tot+=m, off+=m, src+=m){
bp = bread(ip->dev, bmap(ip, off/BSIZE));
bp = bread(ip->dev, bmap(ip, off/BSIZE), 1);
m = min(n - tot, BSIZE - off%BSIZE);
memmove(bp->data + off%BSIZE, src, m);
bwrite(bp);
......@@ -536,7 +536,7 @@ dirlookup(struct inode *dp, char *name, uint *poff)
panic("dirlookup not DIR");
for(off = 0; off < dp->size; off += BSIZE){
bp = bread(dp->dev, bmap(dp, off / BSIZE));
bp = bread(dp->dev, bmap(dp, off / BSIZE), 0);
for(de = (struct dirent*)bp->data;
de < (struct dirent*)(bp->data + BSIZE);
de++){
......
......@@ -130,7 +130,7 @@ iderw(struct buf *b)
{
struct buf **pp;
if(!(b->flags & B_BUSY))
if(!(b->flags & (B_BUSYR | B_BUSYW)))
panic("iderw: buf not busy");
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
panic("iderw: nothing to do");
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论