comparison src/bio.c @ 0:83c23a36980d

Init
author Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp>
date Fri, 26 May 2017 23:11:05 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:83c23a36980d
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 binit (void)
39 {
40 struct buf *b;
41
42 initlock(&bcache.lock, "bcache");
43
44 //PAGEBREAK!
45 // Create linked list of buffers
46 bcache.head.prev = &bcache.head;
47 bcache.head.next = &bcache.head;
48
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* bget (uint dev, uint sector)
62 {
63 struct buf *b;
64
65 acquire(&bcache.lock);
66
67 loop:
68 // Is the sector already cached?
69 for (b = bcache.head.next; b != &bcache.head; b = b->next) {
70 if (b->dev == dev && b->sector == sector) {
71 if (!(b->flags & B_BUSY)) {
72 b->flags |= B_BUSY;
73 release(&bcache.lock);
74 return b;
75 }
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
93 panic("bget: no buffers");
94 }
95
96 // Return a B_BUSY buf with the contents of the indicated disk sector.
97 struct buf* bread (uint dev, uint sector)
98 {
99 struct buf *b;
100
101 b = bget(dev, sector);
102
103 if (!(b->flags & B_VALID)) {
104 iderw(b);
105 }
106
107 return b;
108 }
109
110 // Write b's contents to disk. Must be B_BUSY.
111 void bwrite (struct buf *b)
112 {
113 if ((b->flags & B_BUSY) == 0) {
114 panic("bwrite");
115 }
116
117 b->flags |= B_DIRTY;
118 iderw(b);
119 }
120
121 // Release a B_BUSY buffer.
122 // Move to the head of the MRU list.
123 void brelse (struct buf *b)
124 {
125 if ((b->flags & B_BUSY) == 0) {
126 panic("brelse");
127 }
128
129 acquire(&bcache.lock);
130
131 b->next->prev = b->prev;
132 b->prev->next = b->next;
133 b->next = bcache.head.next;
134 b->prev = &bcache.head;
135 bcache.head.next->prev = b;
136 bcache.head.next = b;
137
138 b->flags &= ~B_BUSY;
139 wakeup(b);
140
141 release(&bcache.lock);
142 }
143