xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

bio.c (3262B)


      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 // The implementation uses three state flags internally:
     17 // * B_BUSY: the block has been returned from bread
     18 //     and has not been passed back to brelse.  
     19 // * B_VALID: the buffer data has been read from the disk.
     20 // * B_DIRTY: the buffer data has been modified
     21 //     and needs to be written to disk.
     22 
     23 #include "types.h"
     24 #include "defs.h"
     25 #include "param.h"
     26 #include "spinlock.h"
     27 #include "buf.h"
     28 
     29 struct {
     30   struct spinlock lock;
     31   struct buf buf[NBUF];
     32 
     33   // Linked list of all buffers, through prev/next.
     34   // head.next is most recently used.
     35   struct buf head;
     36 } bcache;
     37 
     38 void
     39 binit(void)
     40 {
     41   struct buf *b;
     42 
     43   initlock(&bcache.lock, "bcache");
     44 
     45 //PAGEBREAK!
     46   // Create linked list of buffers
     47   bcache.head.prev = &bcache.head;
     48   bcache.head.next = &bcache.head;
     49   for(b = bcache.buf; b < bcache.buf+NBUF; b++){
     50     b->next = bcache.head.next;
     51     b->prev = &bcache.head;
     52     b->dev = -1;
     53     bcache.head.next->prev = b;
     54     bcache.head.next = b;
     55   }
     56 }
     57 
     58 // Look through buffer cache for sector on device dev.
     59 // If not found, allocate fresh block.
     60 // In either case, return B_BUSY buffer.
     61 static struct buf*
     62 bget(uint dev, uint sector)
     63 {
     64   struct buf *b;
     65 
     66   acquire(&bcache.lock);
     67 
     68  loop:
     69   // Is the sector already cached?
     70   for(b = bcache.head.next; b != &bcache.head; b = b->next){
     71     if(b->dev == dev && b->sector == sector){
     72       if(!(b->flags & B_BUSY)){
     73         b->flags |= B_BUSY;
     74         release(&bcache.lock);
     75         return b;
     76       }
     77       sleep(b, &bcache.lock);
     78       goto loop;
     79     }
     80   }
     81 
     82   // Not cached; recycle some non-busy and clean buffer.
     83   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
     84     if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){
     85       b->dev = dev;
     86       b->sector = sector;
     87       b->flags = B_BUSY;
     88       release(&bcache.lock);
     89       return b;
     90     }
     91   }
     92   panic("bget: no buffers");
     93 }
     94 
     95 // Return a B_BUSY buf with the contents of the indicated disk sector.
     96 struct buf*
     97 bread(uint dev, uint sector)
     98 {
     99   struct buf *b;
    100 
    101   b = bget(dev, sector);
    102   if(!(b->flags & B_VALID))
    103     iderw(b);
    104   return b;
    105 }
    106 
    107 // Write b's contents to disk.  Must be B_BUSY.
    108 void
    109 bwrite(struct buf *b)
    110 {
    111   if((b->flags & B_BUSY) == 0)
    112     panic("bwrite");
    113   b->flags |= B_DIRTY;
    114   iderw(b);
    115 }
    116 
    117 // Release a B_BUSY buffer.
    118 // Move to the head of the MRU list.
    119 void
    120 brelse(struct buf *b)
    121 {
    122   if((b->flags & B_BUSY) == 0)
    123     panic("brelse");
    124 
    125   acquire(&bcache.lock);
    126 
    127   b->next->prev = b->prev;
    128   b->prev->next = b->next;
    129   b->next = bcache.head.next;
    130   b->prev = &bcache.head;
    131   bcache.head.next->prev = b;
    132   bcache.head.next = b;
    133 
    134   b->flags &= ~B_BUSY;
    135   wakeup(b);
    136 
    137   release(&bcache.lock);
    138 }
    139