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