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

read-write locks for buffer cache

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