xref: /plan9/sys/src/cmd/cfs/inode.c (revision 7c70c028d2d46a27a61ae88e6df0eb0935d9da7a)
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