xref: /plan9/sys/src/cmd/cfs/inode.c (revision a84536681645e23c630ce4ef2e5c3b284d4c590b)
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)
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) < 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 	Bbuf *bb;
109 	Dinode *bi;
110 	ulong bno;
111 	ulong i;
112 	ulong i2b;
113 	int nib;
114 
115 	/*
116 	 *  first format disk allocation
117 	 */
118 	if(dformat(ic, f, name, bsize, psize) < 0)
119 		return -1;
120 
121 	fprint(2, "formatting inodes\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, f, psize);
147 }
148 
149 /*
150  *  allocate a cache buffer, use least recently used
151  */
152 Ibuf*
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
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 *
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){
196 				/*
197 				 *  our info is old, forget it
198 				 */
199 				DPRINT(2, "updating old file %llud.%lud\n",
200 					qid.path, qid.vers);
201 				m->qid = qid;
202 				iupdate(ic, m - ic->map, qid);
203 			}
204 			break;
205 		}
206 	}
207 
208 	/*
209  	 *  if an already existing inode, just get it
210 	 */
211 	if(m != me)
212 		return iread(ic, m - ic->map);
213 
214 	/*
215 	 *  create a new inode, throw out the least recently used inode
216 	 *  if necessary
217 	 */
218 	m = (Imap*)ic->mlru.lnext;
219 	if(m->inuse){
220 		DPRINT(2, "superceding file %llud.%ld by %llud.%ld\n", m->qid.path,
221 			m->qid.vers, qid.path, qid.vers);
222 		if(iremove(ic, m - ic->map) < 0)
223 			return 0;
224 	}
225 
226 	if(statson){
227 		cfsstat.ninsert++;
228 	}
229 	/*
230 	 *  init inode and write to disk
231 	 */
232 	DPRINT(2, "new file %llud.%ld ino %ld\n", qid.path, qid.vers, m - ic->map);
233 	b = ialloc(ic, m - ic->map);
234 	b->inode.inuse = m->inuse = 1;
235 	b->inode.qid = qid;
236 	b->inode.length = 0x7fffffffffffffffLL;
237 	m->qid = qid;
238 	b->inode.ptr.bno = Notabno;
239 	iwrite(ic, b);
240 	return b;
241 }
242 
243 /*
244  *  read an inode into the cache
245  *
246  *  ASSUMPTION: the inode is valid
247  */
248 Ibuf*
249 iread(Icache *ic, ulong ino)
250 {
251 	Ibuf *b;
252 	Imap *m;
253 	ulong bno;
254 	Bbuf *bb;
255 	Dinode *bi;
256 
257 	/*
258 	 *  first see if we already have it in a cache entry
259 	 */
260 	m = &ic->map[ino];
261 	if(m->inuse && m->b){
262 		b = m->b;
263 		goto out;
264 	}
265 
266 	/*
267 	 *  read it
268 	 */
269 	b = ialloc(ic, ino);
270 	bno = ic->nab + ino/ic->i2b;
271 	bb = bcread(ic, bno);
272 	if(bb == 0){
273 		ifree(ic, b);
274 		return 0;
275 	}
276 	bi = (Dinode*)bb->data;
277 	b->inode = bi->inode[ino % ic->i2b];
278 
279 	/*
280 	 *  consistency check
281 	 */
282 	if(bi->nino!=ic->nino || bi->magic!=Imagic){
283 		fprint(2, "iread: inconsistent inode block\n");
284 		ifree(ic, b);
285 		return 0;
286 	}
287 out:
288 	b->inuse = 1;
289 	m->b = b;
290 	if(b->inode.inuse)
291 		lruref(&ic->mlru, m);
292 	lruref(&ic->blru, b);
293 	return b;
294 }
295 
296 /*
297  *  write an inode back to disk
298  */
299 int
300 iwrite(Icache *ic, Ibuf *b)
301 {
302 	ulong bno;
303 	Bbuf *bb;
304 	Dinode *bi;
305 
306 	bno = ic->nab + b->ino/ic->i2b;
307 	bb = bcread(ic, bno);
308 	if(bb == 0)
309 		return 0;
310 	bi = (Dinode*)bb->data;
311 	bi->inode[b->ino % ic->i2b] = b->inode;
312 	bcmark(ic, bb);
313 	lruref(&ic->mlru, &ic->map[b->ino]);
314 	lruref(&ic->blru, b);
315 	return 0;
316 }
317 
318 /*
319  *  Forget what we know about an inode without removing it
320  *
321  *	N.B: ordering of iwrite and dfree is important
322  */
323 int
324 iupdate(Icache *ic, ulong ino, Qid qid)
325 {
326 	Ibuf *b;
327 	Imap *m;
328 	Dptr d;
329 
330 	if(statson){
331 		cfsstat.nupdate++;
332 	}
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
363 iremove(Icache *ic, ulong ino)
364 {
365 	Ibuf *b;
366 	Imap *m;
367 
368 	if(statson){
369 		cfsstat.ndelete++;
370 	}
371 	m = &ic->map[ino];
372 
373 	/*
374 	 *  read in inode
375 	 */
376 	b = iread(ic, ino);
377 	if(b == 0)
378 		return -1;
379 
380 	/*
381 	 *  mark it unused on disk
382 	 */
383 	b->inode.inuse = 0;
384 	if(iwrite(ic, b) < 0)
385 		return -1;
386 
387 	/*
388 	 *  throw out it's data pages
389 	 */
390 	dfree(ic, &b->inode.ptr);
391 
392 	/*
393 	 *  free the inode buffer
394 	 */
395 	ifree(ic, b);
396 
397 	/*
398 	 *  make map entry least recently used
399 	 */
400 	lruderef(&ic->mlru, m);
401 	return 0;
402 }
403 
404 /*
405  *  increment our version number
406  */
407 void
408 iinc(Icache *ic, Ibuf *b)
409 {
410 	b->inode.qid.vers++;
411 	ic->map[b->ino].qid = b->inode.qid;
412 	iwrite(ic, b);
413 }
414