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