From 6670d3b5e084d9d900d2ea13e624e72e1e28f84c Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Sun, 11 Sep 2016 17:24:04 -0400 Subject: [PATCH] Straight replacement of B_BUSY with a sleeping lock. --- Makefile | 1 + bio.c | 37 ++++++++++++++++++++----------------- buf.h | 2 +- defs.h | 7 +++++++ exec.c | 3 +++ fs.c | 10 +++++++++- ide.c | 5 +++-- log.c | 1 + 8 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index a635b649c1..84faa486e8 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ OBJS = \ picirq.o\ pipe.o\ proc.o\ + sleeplock.o\ spinlock.o\ string.o\ swtch.o\ diff --git a/bio.c b/bio.c index 6c19a64750..67f85e0d41 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 read from the disk. // * B_DIRTY: the buffer data has been modified // and needs to be written to disk. @@ -24,6 +22,7 @@ #include "defs.h" #include "param.h" #include "spinlock.h" +#include "sleeplock.h" #include "fs.h" #include "buf.h" @@ -51,6 +50,7 @@ binit(void) b->next = bcache.head.next; b->prev = &bcache.head; b->dev = -1; + initsleeplock(&b->lock, "buffer"); bcache.head.next->prev = b; bcache.head.next = b; } @@ -58,7 +58,7 @@ binit(void) // Look through buffer cache for block on device dev. // If not found, allocate a buffer. -// In either case, return B_BUSY buffer. +// In either case, return locked buffer. static struct buf* bget(uint dev, uint blockno) { @@ -66,12 +66,14 @@ bget(uint dev, uint blockno) acquire(&bcache.lock); + //cprintf("bget %d\n", blockno); loop: // Is the block already cached? for(b = bcache.head.next; b != &bcache.head; b = b->next){ if(b->dev == dev && b->blockno == blockno){ - if(!(b->flags & B_BUSY)){ - b->flags |= B_BUSY; + if(!holdingsleep(&b->lock)) { + acquiresleep(&b->lock); + //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno); release(&bcache.lock); return b; } @@ -80,14 +82,16 @@ bget(uint dev, uint blockno) } } - // Not cached; recycle some non-busy and clean buffer. - // "clean" because B_DIRTY and !B_BUSY means log.c + // Not cached; recycle some non-locked and clean buffer. + // "clean" because B_DIRTY and not locked means log.c // hasn't yet committed the changes to the buffer. for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ - if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){ + if(!holdingsleep(&b->lock) && (b->flags & B_DIRTY) == 0){ b->dev = dev; b->blockno = blockno; - b->flags = B_BUSY; + b->flags = 0; // XXX + acquiresleep(&b->lock); + //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno); release(&bcache.lock); return b; } @@ -95,7 +99,7 @@ bget(uint dev, uint blockno) panic("bget: no buffers"); } -// Return a B_BUSY buf with the contents of the indicated block. +// Return a locked buf with the contents of the indicated block. struct buf* bread(uint dev, uint blockno) { @@ -108,22 +112,22 @@ bread(uint dev, uint blockno) return b; } -// Write b's contents to disk. Must be B_BUSY. +// Write b's contents to disk. Must be locked. void bwrite(struct buf *b) { - if((b->flags & B_BUSY) == 0) + if(b->lock.locked == 0) panic("bwrite"); b->flags |= B_DIRTY; iderw(b); } -// Release a B_BUSY buffer. +// Release a locked buffer. // Move to the head of the MRU list. void brelse(struct buf *b) { - if((b->flags & B_BUSY) == 0) + if(b->lock.locked == 0) panic("brelse"); acquire(&bcache.lock); @@ -134,8 +138,7 @@ brelse(struct buf *b) b->prev = &bcache.head; bcache.head.next->prev = b; bcache.head.next = b; - - b->flags &= ~B_BUSY; + releasesleep(&b->lock); wakeup(b); release(&bcache.lock); diff --git a/buf.h b/buf.h index f18fd87686..0745be5091 100644 --- a/buf.h +++ b/buf.h @@ -2,12 +2,12 @@ struct buf { int flags; uint dev; uint blockno; + struct sleeplock lock; struct buf *prev; // LRU cache list struct buf *next; struct buf *qnext; // disk queue uchar data[BSIZE]; }; -#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 diff --git a/defs.h b/defs.h index 34ed633ac0..300c75c664 100644 --- a/defs.h +++ b/defs.h @@ -6,6 +6,7 @@ struct pipe; struct proc; struct rtcdate; struct spinlock; +struct sleeplock; struct stat; struct superblock; @@ -128,6 +129,12 @@ void release(struct spinlock*); void pushcli(void); void popcli(void); +// sleeplock.c +void acquiresleep(struct sleeplock*); +void releasesleep(struct sleeplock*); +int holdingsleep(struct sleeplock*); +void initsleeplock(struct sleeplock*, char*); + // string.c int memcmp(const void*, const void*, uint); void* memmove(void*, const void*, uint); diff --git a/exec.c b/exec.c index d56ee1d5f8..e968d2ffa1 100644 --- a/exec.c +++ b/exec.c @@ -19,6 +19,8 @@ exec(char *path, char **argv) pde_t *pgdir, *oldpgdir; begin_op(); + + cprintf("exec %s\n", path); if((ip = namei(path)) == 0){ end_op(); return -1; @@ -98,6 +100,7 @@ exec(char *path, char **argv) proc->tf->esp = sp; switchuvm(proc); freevm(oldpgdir); + cprintf("exec succeeded\n"); return 0; bad: diff --git a/fs.c b/fs.c index 6887dbc432..26a0b3e579 100644 --- a/fs.c +++ b/fs.c @@ -16,6 +16,7 @@ #include "mmu.h" #include "proc.h" #include "spinlock.h" +#include "sleeplock.h" #include "fs.h" #include "buf.h" #include "file.h" @@ -167,7 +168,7 @@ iinit(int dev) initlock(&icache.lock, "icache"); readsb(dev, &sb); cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\ - inodestart %d bmap start %d\n", sb.size, sb.nblocks, + inodestart %d bmap start %d\n", sb.size, sb.nblocks, sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, sb.bmapstart); } @@ -455,6 +456,13 @@ readi(struct inode *ip, char *dst, uint off, uint n) for(tot=0; totdev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); + /* + cprintf("data off %d:\n", off); + for (int j = 0; j < min(m, 10); j++) { + cprintf("%x ", bp->data[off%BSIZE+j]); + } + cprintf("\n"); + */ memmove(dst, bp->data + off%BSIZE, m); brelse(bp); } diff --git a/ide.c b/ide.c index 7fad55d24d..b3112b9ad6 100644 --- a/ide.c +++ b/ide.c @@ -9,6 +9,7 @@ #include "x86.h" #include "traps.h" #include "spinlock.h" +#include "sleeplock.h" #include "fs.h" #include "buf.h" @@ -139,8 +140,8 @@ iderw(struct buf *b) { struct buf **pp; - if(!(b->flags & B_BUSY)) - panic("iderw: buf not busy"); + if(!holdingsleep(&b->lock)) + panic("iderw: buf not locked"); if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) panic("iderw: nothing to do"); if(b->dev != 0 && !havedisk1) diff --git a/log.c b/log.c index a2f1b5700a..9ba3cedba6 100644 --- a/log.c +++ b/log.c @@ -2,6 +2,7 @@ #include "defs.h" #include "param.h" #include "spinlock.h" +#include "sleeplock.h" #include "fs.h" #include "buf.h"