summaryrefslogtreecommitdiff
path: root/bio.c
diff options
context:
space:
mode:
authorFrans Kaashoek <[email protected]>2011-08-26 10:08:29 -0400
committerFrans Kaashoek <[email protected]>2011-08-26 10:08:29 -0400
commit3a5fa7ed9020eaf8ab843a16d26db7393b2ec072 (patch)
treebfa4ad4ae03d7d21796bacaa7eab8e3d3e4ab365 /bio.c
parent8a9b6dbd4468f6312f1d07226a623879f970bd4b (diff)
downloadxv6-labs-3a5fa7ed9020eaf8ab843a16d26db7393b2ec072.tar.gz
xv6-labs-3a5fa7ed9020eaf8ab843a16d26db7393b2ec072.tar.bz2
xv6-labs-3a5fa7ed9020eaf8ab843a16d26db7393b2ec072.zip
Introduce and use sleeplocks instead of BUSY flags
Remove I_BUSY, B_BUSY, and intrans defs and usages One spinlock per buf to avoid ugly loop in bget fix race in filewrite (don't update f->off after releasing lock)
Diffstat (limited to 'bio.c')
-rw-r--r--bio.c45
1 files changed, 23 insertions, 22 deletions
diff --git a/bio.c b/bio.c
index 6a3968b..f11328d 100644
--- a/bio.c
+++ b/bio.c
@@ -13,9 +13,7 @@
// * Only one process at a time can use a buffer,
// so do not keep them longer than necessary.
//
-// The implementation uses three state flags internally:
-// * B_BUSY: the block has been returned from bread
-// and has not been passed back to brelse.
+// The implementation uses two state flags internally:
// * B_VALID: the buffer data has been initialized
// with the associated disk block contents.
// * B_DIRTY: the buffer data has been modified
@@ -51,6 +49,8 @@ binit(void)
b->next = bcache.head.next;
b->prev = &bcache.head;
b->dev = -1;
+ initlock(&b->lock, "buf");
+ initsleeplock(&b->sleeplock);
bcache.head.next->prev = b;
bcache.head.next = b;
}
@@ -58,42 +58,43 @@ binit(void)
// Look through buffer cache for sector on device dev.
// If not found, allocate fresh block.
-// In either case, return locked buffer.
+// In either case, return sleep-locked buffer.
static struct buf*
bget(uint dev, uint sector)
{
struct buf *b;
acquire(&bcache.lock);
-
- loop:
// Try for cached block.
for(b = bcache.head.next; b != &bcache.head; b = b->next){
+ acquire(&b->lock);
if(b->dev == dev && b->sector == sector){
- if(!(b->flags & B_BUSY)){
- b->flags |= B_BUSY;
- release(&bcache.lock);
- return b;
- }
- sleep(b, &bcache.lock);
- goto loop;
+ release(&bcache.lock);
+ acquire_sleeplock(&b->sleeplock, &b->lock);
+ release(&b->lock);
+ return b;
}
+ release(&b->lock);
}
// Allocate fresh block.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
- if((b->flags & B_BUSY) == 0){
+ acquire(&b->lock);
+ if (!acquired_sleeplock(&b->sleeplock)) {
+ release(&bcache.lock);
b->dev = dev;
b->sector = sector;
- b->flags = B_BUSY;
- release(&bcache.lock);
+ b->flags = 0;
+ acquire_sleeplock(&b->sleeplock, &b->lock);
+ release(&b->lock);
return b;
}
+ release(&b->lock);
}
panic("bget: no buffers");
}
-// Return a B_BUSY buf with the contents of the indicated disk sector.
+// Return a locked buf with the contents of the indicated disk sector.
struct buf*
bread(uint dev, uint sector)
{
@@ -109,7 +110,7 @@ bread(uint dev, uint sector)
void
bwrite(struct buf *b)
{
- if((b->flags & B_BUSY) == 0)
+ if(!acquired_sleeplock(&b->sleeplock))
panic("bwrite");
b->flags |= B_DIRTY;
iderw(b);
@@ -119,11 +120,11 @@ bwrite(struct buf *b)
void
brelse(struct buf *b)
{
- if((b->flags & B_BUSY) == 0)
+ if(!acquired_sleeplock(&b->sleeplock))
panic("brelse");
acquire(&bcache.lock);
-
+ acquire(&b->lock);
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head.next;
@@ -131,8 +132,8 @@ brelse(struct buf *b)
bcache.head.next->prev = b;
bcache.head.next = b;
- b->flags &= ~B_BUSY;
- wakeup(b);
+ release_sleeplock(&b->sleeplock);
+ release(&b->lock);
release(&bcache.lock);
}