1 #include <u.h>
2 #include <libc.h>
3 #include "cformat.h"
4 #include "lru.h"
5 #include "bcache.h"
6
7 int
bcinit(Bcache * bc,int f,int bsize)8 bcinit(Bcache *bc, int f, int bsize)
9 {
10 Bbuf *b;
11
12 /*
13 * allocate space for all buffers
14 * point all buffers into outer space
15 */
16 bc->dfirst = 0;
17 bc->bsize = bsize;
18 bc->f = f;
19 lruinit(bc);
20 for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
21 b->inuse = 0;
22 b->next = 0;
23 b->dirty = 0;
24 if(b->data == 0)
25 b->data = (char *)malloc(bc->bsize);
26 if(b->data == 0)
27 return -1;
28 lruadd(bc, b);
29 }
30
31 return 0;
32 }
33
34 /*
35 * Find a buffer for block b. If it's dirty, write it out.
36 */
37 Bbuf *
bcfind(Bcache * bc,ulong bno)38 bcfind(Bcache *bc, ulong bno)
39 {
40 Bbuf *b;
41
42 if(bno == Notabno)
43 error("bcfind: Notabno");
44 bno &= ~Indbno;
45
46 /*
47 * if we already have a buffer for this bno, use it
48 */
49 for(b = bc->bb; b < &bc->bb[Nbcache]; b++)
50 if(b->inuse && b->bno==bno)
51 goto out;
52
53 /*
54 * get least recently used block
55 */
56 b = (Bbuf*)bc->lnext;
57 out:
58 /*
59 * if dirty, write it out
60 */
61 if(b->dirty)
62 if(bcwrite(bc, b) < 0)
63 warning("writing dirty page");
64 lruref(bc, b);
65 return b;
66 }
67
68 /*
69 * allocate a buffer block for a block. it's guaranteed to be there till
70 * the next Nbcache bcread's.
71 */
72 Bbuf *
bcalloc(Bcache * bc,ulong bno)73 bcalloc(Bcache *bc, ulong bno)
74 {
75 Bbuf *b;
76
77 b = bcfind(bc, bno);
78 bno &= ~Indbno;
79 b->bno = bno;
80 b->inuse = 1;
81 return b;
82 }
83
84 /*
85 * read a block into a buffer cache. it's guaranteed to be there till
86 * the next Nbcache bcread's.
87 */
88 Bbuf *
bcread(Bcache * bc,ulong bno)89 bcread(Bcache *bc, ulong bno)
90 {
91 Bbuf *b;
92
93 b = bcfind(bc, bno);
94 bno &= ~Indbno;
95 if(b->bno!=bno || !b->inuse)
96 /*
97 * read in the one we really want
98 */
99 if(bread(bc, bno, b->data) < 0){
100 b->inuse = 0;
101 return 0;
102 }
103 b->bno = bno;
104 b->inuse = 1;
105 return b;
106 }
107
108 /*
109 * mark a page dirty, if it's already dirty force a write
110 *
111 * N.B: ordering is important.
112 */
113 void
bcmark(Bcache * bc,Bbuf * b)114 bcmark(Bcache *bc, Bbuf *b)
115 {
116 lruref(bc, b);
117
118 if(b->dirty){
119 bcwrite(bc, b);
120 return;
121 }
122
123 b->dirty = 1;
124 if(bc->dfirst)
125 bc->dlast->next = b;
126 else
127 bc->dfirst = b;
128 bc->dlast = b;
129 }
130
131 /*
132 * write out a page (and all preceding dirty ones)
133 */
134 int
bcwrite(Bcache * bc,Bbuf * b)135 bcwrite(Bcache *bc, Bbuf *b)
136 {
137 Bbuf *nb;
138
139 /*
140 * write out all preceding pages
141 */
142 while(nb = bc->dfirst){
143 if(bwrite(bc, nb->bno, nb->data) < 0)
144 return -1;
145 nb->dirty = 0;
146 bc->dfirst = nb->next;
147 nb->next = 0;
148 if(nb == b)
149 return 0;
150 }
151
152 /*
153 * write out this page
154 */
155 if(bwrite(bc, b->bno, b->data) < 0)
156 return -1;
157 b->dirty = 0;
158 b->next = 0;
159 return 0;
160 }
161
162 /*
163 * write out all dirty pages (in order)
164 */
165 int
bcsync(Bcache * bc)166 bcsync(Bcache *bc)
167 {
168 if(bc->dfirst)
169 return bcwrite(bc, bc->dlast);
170 return 0;
171 }
172
173 /*
174 * read a block from disk
175 */
176 int
bread(Bcache * bc,ulong bno,void * buf)177 bread(Bcache *bc, ulong bno, void *buf)
178 {
179 uvlong x = (uvlong)bno * bc->bsize;
180
181 if(pread(bc->f, buf, bc->bsize, x) != bc->bsize)
182 return -1;
183 return 0;
184 }
185
186 /*
187 * write a block to disk
188 */
189 int
bwrite(Bcache * bc,ulong bno,void * buf)190 bwrite(Bcache *bc, ulong bno, void *buf)
191 {
192 uvlong x = (uvlong)bno * bc->bsize;
193
194 if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize)
195 return -1;
196 return 0;
197 }
198