1 #include <u.h>
2 #include <libc.h>
3 #include "cformat.h"
4 #include "lru.h"
5 #include "bcache.h"
6 #include "disk.h"
7 #include "inode.h"
8 #include "stats.h"
9
10 extern int readonly;
11
12 /*
13 * read the inode blocks and make sure they
14 * haven't been trashed.
15 *
16 * make the in-core table of qid to inode mappings.
17 * N.B. this is just an array. we need a linear search to find
18 * a particular inode. this could be done faster.
19 *
20 * nab is the first inode block.
21 */
22 int
iinit(Icache * ic,char * mc,int psize,char * name)23 iinit(Icache *ic, char *mc, int psize, char* name)
24 {
25 Ibuf *b;
26 Imap *m;
27 ulong ino;
28 Bbuf *bb;
29 Dinode *bi;
30
31 /*
32 * get basic sizes and allocation info from disk
33 */
34 if(dinit(ic, mc, psize, name) < 0)
35 return -1;
36
37 /*
38 * read first inode block to get number of inodes
39 */
40 bb = bcread(ic, ic->nab);
41 if(bb == 0){
42 fprint(2, "iinit: can't read disk\n");
43 return -1;
44 }
45 bi = (Dinode*)bb->data;
46 if(bi->nino==0 || bi->nino>2048){
47 fprint(2, "iinit: bad nino\n");
48 return -1;
49 }
50 ic->nino = bi->nino;
51
52 /*
53 * set up sizing constants
54 */
55 ic->i2b = (ic->bsize - sizeof(Dihdr))/sizeof(Inode);
56 ic->nib = (ic->nino + ic->i2b - 1)/ic->i2b;
57
58 /*
59 * allocate the in-core qid/inode map, build it's lru
60 */
61 if(ic->map)
62 free(ic->map);
63 ic->map = malloc(sizeof(Imap)*ic->nino);
64 if(ic->map == 0){
65 fprint(2, "iinit: can't alloc map\n");
66 return -1;
67 }
68 lruinit(&ic->mlru);
69 for(m = ic->map; m < &ic->map[ic->nino]; m++){
70 m->inuse = 0;
71 m->b = 0;
72 lruadd(&ic->mlru, m);
73 }
74
75 /*
76 * mark all cache buffers as empty, put them on the lru list
77 */
78 lruinit(&ic->blru);
79 for(b = ic->ib; b < &ic->ib[Nicache]; b++){
80 b->inuse = 0;
81 lruadd(&ic->blru, b);
82 }
83
84 /*
85 * Read all inodes and
86 * build the in-core qid/inode map
87 */
88 for(ino = 0; ino < ic->nino; ino++){
89 b = iread(ic, ino);
90 if(b == 0){
91 fprint(2, "iinit: can't read inode %ld\n", ino);
92 return -1;
93 }
94 if(b->inode.inuse){
95 m = &ic->map[ino];
96 m->inuse = 1;
97 m->qid = b->inode.qid;
98 lruref(&ic->mlru, m);
99 }
100 }
101 return 0;
102 }
103
104 /*
105 * format the inode blocks
106 */
107 int
iformat(Icache * ic,char * mc,ulong nino,char * name,int bsize,int psize)108 iformat(Icache *ic, char *mc, ulong nino, char *name, int bsize, int psize)
109 {
110 int nib;
111 ulong bno, i2b, i;
112 Bbuf *bb;
113 Dinode *bi;
114
115 /*
116 * first format disk allocation
117 */
118 if(dformat(ic, mc, name, bsize, psize) < 0)
119 return -1;
120
121 fprint(2, "formatting inodes in memory\n");
122
123 i2b = (bsize - sizeof(Dihdr))/sizeof(Inode);
124 nib = (nino + i2b - 1)/i2b;
125
126 for(bno = ic->nab; bno < ic->nab + nib; bno++){
127 if(dalloc(ic, 0) == Notabno){
128 fprint(2, "iformat: balloc failed\n");
129 return -1;
130 }
131 bb = bcalloc(ic, bno);
132 if(bb == 0){
133 fprint(2, "iformat: bcalloc failed\n");
134 return -1;
135 }
136 bi = (Dinode*)bb->data;
137 bi->magic = Imagic;
138 bi->nino = nino;
139 for(i = 0; i < i2b; i++)
140 bi->inode[i].inuse = 0;
141 bcmark(ic, bb);
142 }
143
144 bcsync(ic);
145
146 return iinit(ic, mc, psize, name);
147 }
148
149 /*
150 * allocate a cache buffer, use least recently used
151 */
152 Ibuf*
ialloc(Icache * ic,ulong ino)153 ialloc(Icache *ic, ulong ino)
154 {
155 Imap *m;
156 Ibuf *b;
157
158 b = (Ibuf*)ic->blru.lnext;
159 if(b->inuse)
160 ic->map[b->ino].b = 0;
161 b->ino = ino;
162 b->inuse = 1;
163 m = &ic->map[ino];
164 m->b = b;
165 return b;
166 }
167
168 /*
169 * free a cache buffer
170 */
171 void
ifree(Icache * ic,Ibuf * b)172 ifree(Icache *ic, Ibuf *b)
173 {
174 b->inuse = 0;
175 if(b->inuse)
176 ic->map[b->ino].b = 0;
177 lruderef(&ic->blru, b);
178 }
179
180 /*
181 * get an inode into the cache. if no inode exists for this qid, create one
182 * from an unused qid/inode map.
183 */
184 Ibuf *
iget(Icache * ic,Qid qid)185 iget(Icache *ic, Qid qid)
186 {
187 Imap *m, *me;
188 Ibuf *b;
189
190 /*
191 * find map entry with same qid.path
192 */
193 for(m = ic->map, me = &ic->map[ic->nino]; m < me; m++)
194 if(m->inuse && m->qid.path==qid.path){
195 if((m->qid.vers != qid.vers || qid.vers == 0)
196 && !readonly){
197 /*
198 * our info is old or this is likely
199 * a synthetic file, so forget it
200 */
201 DPRINT(2, "updating old file %llud.%lud\n",
202 qid.path, qid.vers);
203 m->qid = qid;
204 iupdate(ic, m - ic->map, qid);
205 }
206 break;
207 }
208
209 /*
210 * if an already existing inode, just get it
211 */
212 if(m != me)
213 return iread(ic, m - ic->map);
214
215 /*
216 * create a new inode, throw out the least recently used inode
217 * if necessary
218 */
219 m = (Imap*)ic->mlru.lnext;
220 if(m->inuse){
221 DPRINT(2, "superceding file %llud.%ld by %llud.%ld\n",
222 m->qid.path, m->qid.vers, qid.path, qid.vers);
223 if(iremove(ic, m - ic->map) < 0)
224 return 0;
225 }
226
227 if(statson)
228 cfsstat.ninsert++;
229 /*
230 * init inode and write to disk
231 */
232 DPRINT(2, "new file %llud.%ld ino %ld\n",
233 qid.path, qid.vers, m - ic->map);
234 b = ialloc(ic, m - ic->map);
235 b->inode.inuse = m->inuse = 1;
236 b->inode.qid = qid;
237 b->inode.length = 0x7fffffffffffffffLL;
238 m->qid = qid;
239 b->inode.ptr.bno = Notabno;
240 iwrite(ic, b);
241 return b;
242 }
243
244 /*
245 * read an inode into the cache
246 *
247 * ASSUMPTION: the inode is valid
248 */
249 Ibuf*
iread(Icache * ic,ulong ino)250 iread(Icache *ic, ulong ino)
251 {
252 Ibuf *b;
253 Imap *m;
254 ulong bno;
255 Bbuf *bb;
256 Dinode *bi;
257
258 /*
259 * first see if we already have it in a cache entry
260 */
261 m = &ic->map[ino];
262 if(m->inuse && m->b){
263 b = m->b;
264 goto out;
265 }
266
267 /*
268 * read it
269 */
270 b = ialloc(ic, ino);
271 bno = ic->nab + ino/ic->i2b;
272 bb = bcread(ic, bno);
273 if(bb == 0){
274 ifree(ic, b);
275 return 0;
276 }
277 bi = (Dinode*)bb->data;
278 b->inode = bi->inode[ino % ic->i2b];
279
280 /*
281 * consistency check
282 */
283 if(bi->nino!=ic->nino || bi->magic!=Imagic){
284 fprint(2, "iread: inconsistent inode block\n");
285 ifree(ic, b);
286 return 0;
287 }
288 out:
289 b->inuse = 1;
290 m->b = b;
291 if(b->inode.inuse)
292 lruref(&ic->mlru, m);
293 lruref(&ic->blru, b);
294 return b;
295 }
296
297 /*
298 * write an inode back to disk
299 */
300 int
iwrite(Icache * ic,Ibuf * b)301 iwrite(Icache *ic, Ibuf *b)
302 {
303 ulong bno;
304 Bbuf *bb;
305 Dinode *bi;
306
307 bno = ic->nab + b->ino/ic->i2b;
308 bb = bcread(ic, bno);
309 if(bb == 0)
310 return 0;
311 bi = (Dinode*)bb->data;
312 bi->inode[b->ino % ic->i2b] = b->inode;
313 bcmark(ic, bb);
314 lruref(&ic->mlru, &ic->map[b->ino]);
315 lruref(&ic->blru, b);
316 return 0;
317 }
318
319 /*
320 * Forget what we know about an inode without removing it
321 *
322 * N.B: ordering of iwrite and dfree is important
323 */
324 int
iupdate(Icache * ic,ulong ino,Qid qid)325 iupdate(Icache *ic, ulong ino, Qid qid)
326 {
327 Ibuf *b;
328 Imap *m;
329 Dptr d;
330
331 if(statson)
332 cfsstat.nupdate++;
333 b = iread(ic, ino);
334 if(b == 0)
335 return -1;
336
337 /*
338 * update inode and map
339 */
340 b->inode.qid = qid;
341 b->inode.length = 0x7fffffffffffffffLL; /* Set to maximum */
342 m = &ic->map[ino];
343 m->qid = qid;
344
345 /*
346 * the free is not done if the write fails!
347 * this is important
348 */
349 d = b->inode.ptr;
350 b->inode.ptr.bno = Notabno;
351 if(iwrite(ic, b) < 0)
352 return -1;
353 dfree(ic, &d);
354 return 0;
355 }
356
357 /*
358 * remove an inode
359 *
360 * N.B: ordering of iwrite and dfree is important
361 */
362 int
iremove(Icache * ic,ulong ino)363 iremove(Icache *ic, ulong ino)
364 {
365 Ibuf *b;
366 Imap *m;
367
368 if(statson)
369 cfsstat.ndelete++;
370 m = &ic->map[ino];
371
372 /*
373 * read in inode
374 */
375 b = iread(ic, ino);
376 if(b == 0)
377 return -1;
378
379 /*
380 * mark it unused on disk
381 */
382 b->inode.inuse = 0;
383 if(iwrite(ic, b) < 0)
384 return -1;
385
386 /*
387 * throw out it's data pages
388 */
389 dfree(ic, &b->inode.ptr);
390
391 /*
392 * free the inode buffer
393 */
394 ifree(ic, b);
395
396 /*
397 * make map entry least recently used
398 */
399 lruderef(&ic->mlru, m);
400 return 0;
401 }
402
403 /*
404 * increment our version number
405 */
406 void
iinc(Icache * ic,Ibuf * b)407 iinc(Icache *ic, Ibuf *b)
408 {
409 b->inode.qid.vers++;
410 ic->map[b->ino].qid = b->inode.qid;
411 iwrite(ic, b);
412 }
413