Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 %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*
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
}