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 
  17 #include "types.h"
  18 #include "param.h"
  19 #include "spinlock.h"
  20 #include "sleeplock.h"
  21 #include "riscv.h"
  22 #include "defs.h"
  23 #include "fs.h"
  24 #include "buf.h"
  25 
  26 struct {
  27   struct spinlock lock;
  28   struct buf buf[NBUF];
  29 
  30   // Linked list of all buffers, through prev/next.
  31   // Sorted by how recently the buffer was used.
  32   // head.next is most recent, head.prev is least.
  33   struct buf head;
  34 } bcache;
  35 
  36 void
  37 binit(void)
  38 {
  39   struct buf *b;
  40 
  41   initlock(&bcache.lock, "bcache");
  42 
  43   // Create linked list of buffers
  44   bcache.head.prev = &bcache.head;
  45   bcache.head.next = &bcache.head;
  46   for(b = bcache.buf; b < bcache.buf+NBUF; b++){
  47     b->next = bcache.head.next;
  48     b->prev = &bcache.head;
  49     initsleeplock(&b->lock, "buffer");
  50     bcache.head.next->prev = b;
  51     bcache.head.next = b;
  52   }
  53 }
  54 
  55 // Look through buffer cache for block on device dev.
  56 // If not found, allocate a buffer.
  57 // In either case, return locked buffer.
  58 static struct buf*
  59 bget(uint dev, uint blockno)
  60 {
  61   struct buf *b;
  62 
  63   acquire(&bcache.lock);
  64 
  65   // Is the block already cached?
  66   for(b = bcache.head.next; b != &bcache.head; b = b->next){
  67     if(b->dev == dev && b->blockno == blockno){
  68       b->refcnt++;
  69       release(&bcache.lock);
  70       acquiresleep(&b->lock);
  71       return b;
  72     }
  73   }
  74 
  75   // Not cached.
  76   // Recycle the least recently used (LRU) unused buffer.
  77   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
  78     if(b->refcnt == 0) {
  79       b->dev = dev;
  80       b->blockno = blockno;
  81       b->valid = 0;
  82       b->refcnt = 1;
  83       release(&bcache.lock);
  84       acquiresleep(&b->lock);
  85       return b;
  86     }
  87   }
  88   panic("bget: no buffers");
  89 }
  90 
  91 // Return a locked buf with the contents of the indicated block.
  92 struct buf*
  93 bread(uint dev, uint blockno)
  94 {
  95   struct buf *b;
  96 
  97   b = bget(dev, blockno);
  98   if(!b->valid) {
  99     virtio_disk_rw(b, 0);
 100     b->valid = 1;
 101   }
 102   return b;
 103 }
 104 
 105 // Write b's contents to disk.  Must be locked.
 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   acquire(&bcache.lock);
 142   b->refcnt++;
 143   release(&bcache.lock);
 144 }
 145 
 146 void
 147 bunpin(struct buf *b) {
 148   acquire(&bcache.lock);
 149   b->refcnt--;
 150   release(&bcache.lock);
 151 }
 152 
 153 

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