xref: /xv6-public/bio.c (revision 6670d3b5)
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 two state flags internally:
17 // * B_VALID: the buffer data has been read from the disk.
18 // * B_DIRTY: the buffer data has been modified
19 //     and needs to be written to disk.
20 
21 #include "types.h"
22 #include "defs.h"
23 #include "param.h"
24 #include "spinlock.h"
25 #include "sleeplock.h"
26 #include "fs.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     initsleeplock(&b->lock, "buffer");
54     bcache.head.next->prev = b;
55     bcache.head.next = b;
56   }
57 }
58 
59 // Look through buffer cache for block on device dev.
60 // If not found, allocate a buffer.
61 // In either case, return locked buffer.
62 static struct buf*
63 bget(uint dev, uint blockno)
64 {
65   struct buf *b;
66 
67   acquire(&bcache.lock);
68 
69   //cprintf("bget %d\n", blockno);
70  loop:
71   // Is the block already cached?
72   for(b = bcache.head.next; b != &bcache.head; b = b->next){
73     if(b->dev == dev && b->blockno == blockno){
74       if(!holdingsleep(&b->lock)) {
75         acquiresleep(&b->lock);
76         //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno);
77         release(&bcache.lock);
78         return b;
79       }
80       sleep(b, &bcache.lock);
81       goto loop;
82     }
83   }
84 
85   // Not cached; recycle some non-locked and clean buffer.
86   // "clean" because B_DIRTY and not locked means log.c
87   // hasn't yet committed the changes to the buffer.
88   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
89     if(!holdingsleep(&b->lock) && (b->flags & B_DIRTY) == 0){
90       b->dev = dev;
91       b->blockno = blockno;
92       b->flags = 0;  // XXX
93       acquiresleep(&b->lock);
94       //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno);
95       release(&bcache.lock);
96       return b;
97     }
98   }
99   panic("bget: no buffers");
100 }
101 
102 // Return a locked buf with the contents of the indicated block.
103 struct buf*
104 bread(uint dev, uint blockno)
105 {
106   struct buf *b;
107 
108   b = bget(dev, blockno);
109   if(!(b->flags & B_VALID)) {
110     iderw(b);
111   }
112   return b;
113 }
114 
115 // Write b's contents to disk.  Must be locked.
116 void
117 bwrite(struct buf *b)
118 {
119   if(b->lock.locked == 0)
120     panic("bwrite");
121   b->flags |= B_DIRTY;
122   iderw(b);
123 }
124 
125 // Release a locked buffer.
126 // Move to the head of the MRU list.
127 void
128 brelse(struct buf *b)
129 {
130   if(b->lock.locked == 0)
131     panic("brelse");
132 
133   acquire(&bcache.lock);
134 
135   b->next->prev = b->prev;
136   b->prev->next = b->next;
137   b->next = bcache.head.next;
138   b->prev = &bcache.head;
139   bcache.head.next->prev = b;
140   bcache.head.next = b;
141   releasesleep(&b->lock);
142   wakeup(b);
143 
144   release(&bcache.lock);
145 }
146 //PAGEBREAK!
147 // Blank page.
148 
149