diff src/bio.c @ 0:83c23a36980d

Init
author Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp>
date Fri, 26 May 2017 23:11:05 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bio.c	Fri May 26 23:11:05 2017 +0900
@@ -0,0 +1,143 @@
+// Buffer cache.
+//
+// The buffer cache is a linked list of buf structures holding
+// cached copies of disk block contents.  Caching disk blocks
+// in memory reduces the number of disk reads and also provides
+// a synchronization point for disk blocks used by multiple processes.
+//
+// Interface:
+// * To get a buffer for a particular disk block, call bread.
+// * After changing buffer data, call bwrite to write it to disk.
+// * When done with the buffer, call brelse.
+// * Do not use the buffer after calling brelse.
+// * 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.
+// * 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.
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "spinlock.h"
+#include "buf.h"
+
+struct {
+    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 binit (void)
+{
+    struct buf *b;
+
+    initlock(&bcache.lock, "bcache");
+
+    //PAGEBREAK!
+    // Create linked list of buffers
+    bcache.head.prev = &bcache.head;
+    bcache.head.next = &bcache.head;
+
+    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;
+    }
+}
+
+// Look through buffer cache for sector on device dev.
+// If not found, allocate fresh block.
+// In either case, return B_BUSY buffer.
+static struct buf* bget (uint dev, uint sector)
+{
+    struct buf *b;
+
+    acquire(&bcache.lock);
+
+    loop:
+    // Is the sector already cached?
+    for (b = bcache.head.next; b != &bcache.head; b = b->next) {
+        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;
+        }
+    }
+
+    // Not cached; recycle some non-busy and clean buffer.
+    for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
+        if ((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0) {
+            b->dev = dev;
+            b->sector = sector;
+            b->flags = B_BUSY;
+            release(&bcache.lock);
+            return b;
+        }
+    }
+
+    panic("bget: no buffers");
+}
+
+// Return a B_BUSY buf with the contents of the indicated disk sector.
+struct buf* bread (uint dev, uint sector)
+{
+    struct buf *b;
+
+    b = bget(dev, sector);
+
+    if (!(b->flags & B_VALID)) {
+        iderw(b);
+    }
+
+    return b;
+}
+
+// Write b's contents to disk.  Must be B_BUSY.
+void bwrite (struct buf *b)
+{
+    if ((b->flags & B_BUSY) == 0) {
+        panic("bwrite");
+    }
+
+    b->flags |= B_DIRTY;
+    iderw(b);
+}
+
+// Release a B_BUSY buffer.
+// Move to the head of the MRU list.
+void brelse (struct buf *b)
+{
+    if ((b->flags & B_BUSY) == 0) {
+        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;
+    wakeup(b);
+
+    release(&bcache.lock);
+}
+