root/kernel/bio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. binit
  2. bget
  3. bread
  4. bwrite
  5. brelse
  6. bpin
  7. bunpin

   1 // Buffer cache.
   2 //
   3 // The buffer cache is a linked list of buf structures holding
   4 // cached copies of disk block contents.  Caching disk blocks
   5 // in memory reduces the number of disk reads and also provides
   6 // a synchronization point for disk blocks used by multiple processes.
   7 //
   8 // Interface:
   9 // * To get a buffer for a particular disk block, call bread.
  10 // * After changing buffer data, call bwrite to write it to disk.
  11 // * When done with the buffer, call brelse.
  12 // * Do not use the buffer after calling brelse.
  13 // * Only one process at a time can use a buffer,
  14 //     so do not keep them longer than necessary.
  15 
  16 #include "types.h"
  17 #include "param.h"
  18 #include "spinlock.h"
  19 #include "sleeplock.h"
  20 #include "riscv.h"
  21 #include "defs.h"
  22 #include "fs.h"
  23 #include "buf.h"
  24 
  25 struct {
  26   struct spinlock lock;
  27   struct buf buf[NBUF];
  28 
  29   // Linked list of all buffers, through prev/next.
  30   // Sorted by how recently the buffer was used.
  31   // head.next is most recent, head.prev is least.
  32   struct buf head;
  33 } bcache;
  34 
  35 void
  36 binit(void)
  37 {
  38   struct buf *b;
  39 
  40   initlock(&bcache.lock, "bcache");
  41 
  42   // Create linked list of buffers
  43   bcache.head.prev = &bcache.head;
  44   bcache.head.next = &bcache.head;
  45   for (b = bcache.buf; b < bcache.buf + NBUF; b++) {
  46     b->next = bcache.head.next;
  47     b->prev = &bcache.head;
  48     initsleeplock(&b->lock, "buffer");
  49     bcache.head.next->prev = b;
  50     bcache.head.next = b;
  51   }
  52 }
  53 
  54 // Look through buffer cache for block on device dev.
  55 // If not found, allocate a buffer.
  56 // In either case, return locked buffer.
  57 static struct buf *
  58 bget(uint dev, uint blockno)
  59 {
  60   struct buf *b;
  61 
  62   acquire(&bcache.lock);
  63 
  64   // Is the block already cached?
  65   for (b = bcache.head.next; b != &bcache.head; b = b->next) {
  66     if (b->dev == dev && b->blockno == blockno) {
  67       b->refcnt++;
  68       release(&bcache.lock);
  69       acquiresleep(&b->lock);
  70       return b;
  71     }
  72   }
  73 
  74   // Not cached.
  75   // Recycle the least recently used (LRU) unused buffer.
  76   for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
  77     if (b->refcnt == 0) {
  78       b->dev = dev;
  79       b->blockno = blockno;
  80       b->valid = 0;
  81       b->refcnt = 1;
  82       release(&bcache.lock);
  83       acquiresleep(&b->lock);
  84       return b;
  85     }
  86   }
  87   panic("bget: no buffers");
  88 }
  89 
  90 // Return a locked buf with the contents of the indicated block.
  91 struct buf *
  92 bread(uint dev, uint blockno)
  93 {
  94   struct buf *b;
  95 
  96   b = bget(dev, blockno);
  97   if (!b->valid) {
  98     virtio_disk_rw(b, 0);
  99     b->valid = 1;
 100   }
 101   return b;
 102 }
 103 
 104 // Write b's contents to disk.  Must be locked.
 105 // Only the log calls bwrite.
 106 void
 107 bwrite(struct buf *b)
 108 {
 109   if (!holdingsleep(&b->lock))
 110     panic("bwrite");
 111   virtio_disk_rw(b, 1);
 112 }
 113 
 114 // Release a locked buffer.
 115 // Move to the head of the most-recently-used list.
 116 void
 117 brelse(struct buf *b)
 118 {
 119   if (!holdingsleep(&b->lock))
 120     panic("brelse");
 121 
 122   releasesleep(&b->lock);
 123 
 124   acquire(&bcache.lock);
 125   b->refcnt--;
 126   if (b->refcnt == 0) {
 127     // no one is waiting for it.
 128     b->next->prev = b->prev;
 129     b->prev->next = b->next;
 130     b->next = bcache.head.next;
 131     b->prev = &bcache.head;
 132     bcache.head.next->prev = b;
 133     bcache.head.next = b;
 134   }
 135 
 136   release(&bcache.lock);
 137 }
 138 
 139 void
 140 bpin(struct buf *b)
 141 {
 142   acquire(&bcache.lock);
 143   b->refcnt++;
 144   release(&bcache.lock);
 145 }
 146 
 147 void
 148 bunpin(struct buf *b)
 149 {
 150   acquire(&bcache.lock);
 151   b->refcnt--;
 152   release(&bcache.lock);
 153 }

/* [<][>][^][v][top][bottom][index][help] */