Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * exportfs - Export a plan 9 name space across a network
3
 */
4
#include <u.h>
5
#include <libc.h>
6
#include <fcall.h>
7
#include <libsec.h>
8
#include "drawterm.h"
9
#define Extern
10
#include "exportfs.h"
11
 
12
/* #define QIDPATH	((1LL<<48)-1) */
13
#define QIDPATH	((((vlong)1)<<48)-1)
14
vlong newqid = 0;
15
 
16
void (*fcalls[256])(Fsrpc*);
17
 
18
/* accounting and debugging counters */
19
int	filecnt;
20
int	freecnt;
21
int	qidcnt;
22
int	qfreecnt;
23
int	ncollision;
24
int	netfd;
25
 
26
int
27
exportfs(int fd, int msgsz)
28
{
29
	char buf[ERRMAX], ebuf[ERRMAX];
30
	Fsrpc *r;
31
	int i, n;
32
 
33
	fcalls[Tversion] = Xversion;
34
	fcalls[Tauth] = Xauth;
35
	fcalls[Tflush] = Xflush;
36
	fcalls[Tattach] = Xattach;
37
	fcalls[Twalk] = Xwalk;
38
	fcalls[Topen] = slave;
39
	fcalls[Tcreate] = Xcreate;
40
	fcalls[Tclunk] = Xclunk;
41
	fcalls[Tread] = slave;
42
	fcalls[Twrite] = slave;
43
	fcalls[Tremove] = Xremove;
44
	fcalls[Tstat] = Xstat;
45
	fcalls[Twstat] = Xwstat;
46
 
47
	srvfd = -1;
48
	netfd = fd;
49
	//dbg = 1;
50
 
51
	strcpy(buf, "this is buf");
52
	strcpy(ebuf, "this is ebuf");
53
	DEBUG(DFD, "exportfs: started\n");
54
 
55
//	rfork(RFNOTEG);
56
 
57
	messagesize = msgsz;
58
	if(messagesize == 0){
59
		messagesize = iounit(netfd);
60
		if(messagesize == 0)
61
			messagesize = 8*8192+IOHDRSZ;
62
	}
63
 
64
	Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
65
//	for(i=0; i<Nr_workbufs; i++)
66
//		Workq[i].buf = emallocz(messagesize);
67
	fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
68
 
69
	fmtinstall('F', fcallfmt);
70
 
71
	initroot();
72
 
73
	DEBUG(DFD, "exportfs: %s\n", buf);
74
 
75
	/*
76
	 * Start serving file requests from the network
77
	 */
78
	for(;;) {
79
		r = getsbuf();
80
		if(r == 0)
81
			fatal("Out of service buffers");
82
 
83
		DEBUG(DFD, "read9p...");
84
		n = read9pmsg(netfd, r->buf, messagesize);
85
		if(n <= 0)
86
			fatal("eof: n=%d %r", n);
87
 
88
		if(convM2S(r->buf, n, &r->work) == 0){
89
			iprint("convM2S %d byte message\n", n);
90
			for(i=0; i<n; i++){
91
				iprint(" %.2ux", r->buf[i]);
92
				if(i%16 == 15)
93
					iprint("\n");
94
			}
95
			if(i%16)
96
				iprint("\n");
97
			fatal("convM2S format error");
98
		}
99
 
100
if(0) iprint("<- %F\n", &r->work);
101
		DEBUG(DFD, "%F\n", &r->work);
102
		(fcalls[r->work.type])(r);
103
	}
104
}
105
 
106
void
107
reply(Fcall *r, Fcall *t, char *err)
108
{
109
	uchar *data;
110
	int m, n;
111
 
112
	t->tag = r->tag;
113
	t->fid = r->fid;
114
	if(err) {
115
		t->type = Rerror;
116
		t->ename = err;
117
	}
118
	else 
119
		t->type = r->type + 1;
120
 
121
if(0) iprint("-> %F\n", t);
122
	DEBUG(DFD, "\t%F\n", t);
123
 
124
	data = malloc(messagesize);	/* not mallocz; no need to clear */
125
	if(data == nil)
126
		fatal(Enomem);
127
	n = convS2M(t, data, messagesize);
128
	if((m=write(netfd, data, n))!=n){
129
		iprint("wrote %d got %d (%r)\n", n, m);
130
		fatal("write");
131
	}
132
	free(data);
133
}
134
 
135
Fid *
136
getfid(int nr)
137
{
138
	Fid *f;
139
 
140
	for(f = fidhash(nr); f; f = f->next)
141
		if(f->nr == nr)
142
			return f;
143
 
144
	return 0;
145
}
146
 
147
int
148
freefid(int nr)
149
{
150
	Fid *f, **l;
151
	char buf[128];
152
 
153
	l = &fidhash(nr);
154
	for(f = *l; f; f = f->next) {
155
		if(f->nr == nr) {
156
			if(f->mid) {
157
				sprint(buf, "/mnt/exportfs/%d", f->mid);
158
				unmount(0, buf);
159
				psmap[f->mid] = 0;
160
			}
161
			if(f->f) {
162
				freefile(f->f);
163
				f->f = nil;
164
			}
165
			*l = f->next;
166
			f->next = fidfree;
167
			fidfree = f;
168
			return 1;
169
		}
170
		l = &f->next;
171
	}
172
 
173
	return 0;	
174
}
175
 
176
Fid *
177
newfid(int nr)
178
{
179
	Fid *new, **l;
180
	int i;
181
 
182
	l = &fidhash(nr);
183
	for(new = *l; new; new = new->next)
184
		if(new->nr == nr)
185
			return 0;
186
 
187
	if(fidfree == 0) {
188
		fidfree = emallocz(sizeof(Fid) * Fidchunk);
189
 
190
		for(i = 0; i < Fidchunk-1; i++)
191
			fidfree[i].next = &fidfree[i+1];
192
 
193
		fidfree[Fidchunk-1].next = 0;
194
	}
195
 
196
	new = fidfree;
197
	fidfree = new->next;
198
 
199
	memset(new, 0, sizeof(Fid));
200
	new->next = *l;
201
	*l = new;
202
	new->nr = nr;
203
	new->fid = -1;
204
	new->mid = 0;
205
 
206
	return new;	
207
}
208
 
209
Fsrpc *
210
getsbuf(void)
211
{
212
	static int ap;
213
	int look, rounds;
214
	Fsrpc *wb;
215
	int small_instead_of_fast = 1;
216
 
217
	if(small_instead_of_fast)
218
		ap = 0;	/* so we always start looking at the beginning and reuse buffers */
219
 
220
	for(rounds = 0; rounds < 10; rounds++) {
221
		for(look = 0; look < Nr_workbufs; look++) {
222
			if(++ap == Nr_workbufs)
223
				ap = 0;
224
			if(Workq[ap].busy == 0)
225
				break;
226
		}
227
 
228
		if(look == Nr_workbufs){
229
			sleep(10 * rounds);
230
			continue;
231
		}
232
 
233
		wb = &Workq[ap];
234
		wb->pid = 0;
235
		wb->canint = 0;
236
		wb->flushtag = NOTAG;
237
		wb->busy = 1;
238
		if(wb->buf == nil)	/* allocate buffers dynamically to keep size down */
239
			wb->buf = emallocz(messagesize);
240
		return wb;
241
	}
242
	fatal("No more work buffers");
243
	return nil;
244
}
245
 
246
void
247
freefile(File *f)
248
{
249
	File *parent, *child;
250
 
251
Loop:
252
	f->ref--;
253
	if(f->ref > 0)
254
		return;
255
	freecnt++;
256
	if(f->ref < 0) abort();
257
	DEBUG(DFD, "free %s\n", f->name);
258
	/* delete from parent */
259
	parent = f->parent;
260
	if(parent->child == f)
261
		parent->child = f->childlist;
262
	else{
263
		for(child=parent->child; child->childlist!=f; child=child->childlist)
264
			if(child->childlist == nil)
265
				fatal("bad child list");
266
		child->childlist = f->childlist;
267
	}
268
	freeqid(f->qidt);
269
	free(f->name);
270
	f->name = nil;
271
	free(f);
272
	f = parent;
273
	if(f != nil)
274
		goto Loop;
275
}
276
 
277
File *
278
file(File *parent, char *name)
279
{
280
	Dir *dir;
281
	char *path;
282
	File *f;
283
 
284
	DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
285
 
286
	path = makepath(parent, name);
287
	dir = dirstat(path);
288
	free(path);
289
	if(dir == nil)
290
		return nil;
291
 
292
	for(f = parent->child; f; f = f->childlist)
293
		if(strcmp(name, f->name) == 0)
294
			break;
295
 
296
	if(f == nil){
297
		f = emallocz(sizeof(File));
298
		f->name = estrdup(name);
299
 
300
		f->parent = parent;
301
		f->childlist = parent->child;
302
		parent->child = f;
303
		parent->ref++;
304
		f->ref = 0;
305
		filecnt++;
306
	}
307
	f->ref++;
308
	f->qid.type = dir->qid.type;
309
	f->qid.vers = dir->qid.vers;
310
	f->qidt = uniqueqid(dir);
311
	f->qid.path = f->qidt->uniqpath;
312
 
313
	f->inval = 0;
314
 
315
	free(dir);
316
 
317
	return f;
318
}
319
 
320
void
321
initroot(void)
322
{
323
	Dir *dir;
324
 
325
	root = emallocz(sizeof(File));
326
	root->name = estrdup(".");
327
 
328
	dir = dirstat(root->name);
329
	if(dir == nil)
330
		fatal("root stat");
331
 
332
	root->ref = 1;
333
	root->qid.vers = dir->qid.vers;
334
	root->qidt = uniqueqid(dir);
335
	root->qid.path = root->qidt->uniqpath;
336
	root->qid.type = QTDIR;
337
	free(dir);
338
 
339
	psmpt = emallocz(sizeof(File));
340
	psmpt->name = estrdup("/");
341
 
342
	dir = dirstat(psmpt->name);
343
	if(dir == nil)
344
		return;
345
 
346
	psmpt->ref = 1;
347
	psmpt->qid.vers = dir->qid.vers;
348
	psmpt->qidt = uniqueqid(dir);
349
	psmpt->qid.path = psmpt->qidt->uniqpath;
350
	free(dir);
351
 
352
	psmpt = file(psmpt, "mnt");
353
	if(psmpt == 0)
354
		return;
355
	psmpt = file(psmpt, "exportfs");
356
}
357
 
358
char*
359
makepath(File *p, char *name)
360
{
361
	int i, n;
362
	char *c, *s, *path, *seg[256];
363
 
364
	seg[0] = name;
365
	n = strlen(name)+2;
366
	for(i = 1; i < 256 && p; i++, p = p->parent){
367
		seg[i] = p->name;
368
		n += strlen(p->name)+1;
369
	}
370
	path = malloc(n);
371
	if(path == nil)
372
		fatal("out of memory");
373
	s = path;
374
 
375
	while(i--) {
376
		for(c = seg[i]; *c; c++)
377
			*s++ = *c;
378
		*s++ = '/';
379
	}
380
	while(s[-1] == '/')
381
		s--;
382
	*s = '\0';
383
 
384
	return path;
385
}
386
 
387
int
388
qidhash(vlong path)
389
{
390
	int h, n;
391
 
392
	h = 0;
393
	for(n=0; n<64; n+=Nqidbits){
394
		h ^= path;
395
		path >>= Nqidbits;
396
	}
397
	return h & (Nqidtab-1);
398
}
399
 
400
void
401
freeqid(Qidtab *q)
402
{
403
	ulong h;
404
	Qidtab *l;
405
 
406
	q->ref--;
407
	if(q->ref > 0)
408
		return;
409
	qfreecnt++;
410
	h = qidhash(q->path);
411
	if(qidtab[h] == q)
412
		qidtab[h] = q->next;
413
	else{
414
		for(l=qidtab[h]; l->next!=q; l=l->next)
415
			if(l->next == nil)
416
				fatal("bad qid list");
417
		l->next = q->next;
418
	}
419
	free(q);
420
}
421
 
422
Qidtab*
423
qidlookup(Dir *d)
424
{
425
	ulong h;
426
	Qidtab *q;
427
 
428
	h = qidhash(d->qid.path);
429
	for(q=qidtab[h]; q!=nil; q=q->next)
430
		if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
431
			return q;
432
	return nil;
433
}
434
 
435
int
436
qidexists(vlong path)
437
{
438
	int h;
439
	Qidtab *q;
440
 
441
	for(h=0; h<Nqidtab; h++)
442
		for(q=qidtab[h]; q!=nil; q=q->next)
443
			if(q->uniqpath == path)
444
				return 1;
445
	return 0;
446
}
447
 
448
Qidtab*
449
uniqueqid(Dir *d)
450
{
451
	ulong h;
452
	vlong path;
453
	Qidtab *q;
454
 
455
	q = qidlookup(d);
456
	if(q != nil){
457
		q->ref++;
458
		return q;
459
	}
460
	path = d->qid.path;
461
	while(qidexists(path)){
462
		DEBUG(DFD, "collision on %s\n", d->name);
463
		/* collision: find a new one */
464
		ncollision++;
465
		path &= QIDPATH;
466
		++newqid;
467
		if(newqid >= (1<<16)){
468
			DEBUG(DFD, "collision wraparound\n");
469
			newqid = 1;
470
		}
471
		path |= newqid<<48;
472
		DEBUG(DFD, "assign qid %.16llux\n", path);
473
	}
474
	q = mallocz(sizeof(Qidtab), 1);
475
	if(q == nil)
476
		fatal("no memory for qid table");
477
	qidcnt++;
478
	q->ref = 1;
479
	q->type = d->type;
480
	q->dev = d->dev;
481
	q->path = d->qid.path;
482
	q->uniqpath = path;
483
	h = qidhash(d->qid.path);
484
	q->next = qidtab[h];
485
	qidtab[h] = q;
486
	return q;
487
}
488
 
489
void
490
fatal(char *s, ...)
491
{
492
	char buf[ERRMAX];
493
	va_list arg;
494
 
495
	if (s) {
496
		va_start(arg, s);
497
		vsnprint(buf, ERRMAX, s, arg);
498
		va_end(arg);
499
	}
500
 
501
	/* Clear away the slave children */
502
//	for(m = Proclist; m; m = m->next)
503
//		postnote(PNPROC, m->pid, "kill");
504
 
505
	DEBUG(DFD, "%s\n", buf);
506
	if (s) 
507
		sysfatal(buf);
508
	else
509
		sysfatal("");
510
}
511