]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cfs/inode.c
cc: fix void cast crash
[plan9front.git] / sys / src / cmd / cfs / inode.c
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
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
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*
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
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 *
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 %zd\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*
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
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
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
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
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 }