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.
9 // * To get a buffer for a particular disk block, call bread.
10 // * After changing buffer data, call bwrite to flush 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.
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 initialized
20 // with the associated disk block contents.
21 // * B_DIRTY: the buffer data has been modified
22 // and needs to be written to disk.
34 // Linked list of all buffers, through prev/next.
35 // head.next is most recently used.
44 initlock(&bcache
.lock
, "bcache");
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
;
53 bcache
.head
.next
->prev
= b
;
58 // Look through buffer cache for sector on device dev.
59 // If not found, allocate fresh block.
60 // In either case, return locked buffer.
62 bget(uint dev
, uint sector
)
66 acquire(&bcache
.lock
);
69 // Try for cached block.
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
)){
74 release(&bcache
.lock
);
77 sleep(b
, &bcache
.lock
);
82 // Allocate fresh block.
83 for(b
= bcache
.head
.prev
; b
!= &bcache
.head
; b
= b
->prev
){
84 if((b
->flags
& B_BUSY
) == 0){
88 release(&bcache
.lock
);
92 panic("bget: no buffers");
95 // Return a B_BUSY buf with the contents of the indicated disk sector.
97 bread(uint dev
, uint sector
)
101 b
= bget(dev
, sector
);
102 if(!(b
->flags
& B_VALID
))
107 // Write b's contents to disk. Must be locked.
109 bwrite(struct buf
*b
)
111 if((b
->flags
& B_BUSY
) == 0)
117 // Release the buffer b.
119 brelse(struct buf
*b
)
121 if((b
->flags
& B_BUSY
) == 0)
124 acquire(&bcache
.lock
);
126 b
->next
->prev
= b
->prev
;
127 b
->prev
->next
= b
->next
;
128 b
->next
= bcache
.head
.next
;
129 b
->prev
= &bcache
.head
;
130 bcache
.head
.next
->prev
= b
;
131 bcache
.head
.next
= b
;
136 release(&bcache
.lock
);