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 <fcall.h>
4
#define Extern	extern
5
#include "exportfs.h"
6
 
7
char Ebadfid[] = "Bad fid";
8
char Enotdir[] = "Not a directory";
9
char Edupfid[] = "Fid already in use";
10
char Eopen[] = "Fid already opened";
11
char Exmnt[] = "Cannot .. past mount point";
12
char Emip[] = "Mount in progress";
13
char Enopsmt[] = "Out of pseudo mount points";
14
char Enomem[] = "No memory";
15
char Eversion[] = "Bad 9P2000 version";
16
 
17
int iounit(int x)
18
{
19
	return 8*8192+IOHDRSZ;
20
}
21
 
22
void*
23
emallocz(ulong n)
24
{
25
	void *v;
26
 
27
	v = mallocz(n, 1);
28
	if(v == nil)
29
		panic("out of memory");
30
	return v;
31
}
32
 
33
 
34
void
35
Xversion(Fsrpc *t)
36
{
37
	Fcall rhdr;
38
 
39
	if(t->work.msize > messagesize)
40
		t->work.msize = messagesize;
41
	messagesize = t->work.msize;
42
	if(strncmp(t->work.version, "9P2000", 6) != 0){
43
		reply(&t->work, &rhdr, Eversion);
44
		return;
45
	}
46
	rhdr.version = "9P2000";
47
	rhdr.msize = t->work.msize;
48
	reply(&t->work, &rhdr, 0);
49
	t->busy = 0;
50
}
51
 
52
void
53
Xauth(Fsrpc *t)
54
{
55
	Fcall rhdr;
56
 
57
	reply(&t->work, &rhdr, "exportfs: authentication not required");
58
	t->busy = 0;
59
}
60
 
61
void
62
Xflush(Fsrpc *t)
63
{
64
	Fsrpc *w, *e;
65
	Fcall rhdr;
66
 
67
	e = &Workq[Nr_workbufs];
68
 
69
	for(w = Workq; w < e; w++) {
70
		if(w->work.tag == t->work.oldtag) {
71
			DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
72
			if(w->busy && w->pid) {
73
				w->flushtag = t->work.tag;
74
				DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
75
			//	if(w->canint)
76
			//		postnote(PNPROC, w->pid, "flush");
77
				t->busy = 0;
78
				return;
79
			}
80
		}
81
	}
82
 
83
	reply(&t->work, &rhdr, 0);
84
	DEBUG(DFD, "\tflush reply\n");
85
	t->busy = 0;
86
}
87
 
88
void
89
Xattach(Fsrpc *t)
90
{
91
	Fcall rhdr;
92
	Fid *f;
93
 
94
	f = newfid(t->work.fid);
95
	if(f == 0) {
96
		reply(&t->work, &rhdr, Ebadfid);
97
		t->busy = 0;
98
		return;
99
	}
100
 
101
	if(srvfd >= 0){
102
/*
103
		if(psmpt == 0){
104
		Nomount:
105
			reply(&t->work, &rhdr, Enopsmt);
106
			t->busy = 0;
107
			freefid(t->work.fid);
108
			return;
109
		}
110
		for(i=0; i<Npsmpt; i++)
111
			if(psmap[i] == 0)
112
				break;
113
		if(i >= Npsmpt)
114
			goto Nomount;
115
		sprint(buf, "%d", i);
116
		f->f = file(psmpt, buf);
117
		if(f->f == nil)
118
			goto Nomount;
119
		sprint(buf, "/mnt/exportfs/%d", i);
120
		nfd = dup(srvfd, -1);
121
		if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
122
			errstr(buf, sizeof buf);
123
			reply(&t->work, &rhdr, buf);
124
			t->busy = 0;
125
			freefid(t->work.fid);
126
			close(nfd);
127
			return;
128
		}
129
		psmap[i] = 1;
130
		f->mid = i;
131
*/
132
	}else{
133
		f->f = root;
134
		f->f->ref++;
135
	}
136
 
137
	rhdr.qid = f->f->qid;
138
	reply(&t->work, &rhdr, 0);
139
	t->busy = 0;
140
}
141
 
142
Fid*
143
clonefid(Fid *f, int new)
144
{
145
	Fid *n;
146
 
147
	n = newfid(new);
148
	if(n == 0) {
149
		n = getfid(new);
150
		if(n == 0)
151
			fatal("inconsistent fids");
152
		if(n->fid >= 0)
153
			close(n->fid);
154
		freefid(new);
155
		n = newfid(new);
156
		if(n == 0)
157
			fatal("inconsistent fids2");
158
	}
159
	n->f = f->f;
160
	n->f->ref++;
161
	return n;
162
}
163
 
164
void
165
Xwalk(Fsrpc *t)
166
{
167
	char err[ERRMAX], *e;
168
	Fcall rhdr;
169
	Fid *f, *nf;
170
	File *wf;
171
	int i;
172
 
173
	f = getfid(t->work.fid);
174
	if(f == 0) {
175
		reply(&t->work, &rhdr, Ebadfid);
176
		t->busy = 0;
177
		return;
178
	}
179
 
180
	nf = nil;
181
	if(t->work.newfid != t->work.fid){
182
		nf = clonefid(f, t->work.newfid);
183
		f = nf;
184
	}
185
 
186
	rhdr.nwqid = 0;
187
	e = nil;
188
	for(i=0; i<t->work.nwname; i++){
189
		if(i == MAXWELEM){
190
			e = "Too many path elements";
191
			break;
192
		}
193
 
194
		if(strcmp(t->work.wname[i], "..") == 0) {
195
			if(f->f->parent == nil) {
196
				e = Exmnt;
197
				break;
198
			}
199
			wf = f->f->parent;
200
			wf->ref++;
201
			goto Accept;
202
		}
203
 
204
		wf = file(f->f, t->work.wname[i]);
205
		if(wf == 0){
206
			errstr(err, sizeof err);
207
			e = err;
208
			break;
209
		}
210
    Accept:
211
		freefile(f->f);
212
		rhdr.wqid[rhdr.nwqid++] = wf->qid;
213
		f->f = wf;
214
		continue;
215
	}
216
 
217
	if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
218
		freefid(t->work.newfid);
219
	if(rhdr.nwqid > 0)
220
		e = nil;
221
	reply(&t->work, &rhdr, e);
222
	t->busy = 0;
223
}
224
 
225
void
226
Xclunk(Fsrpc *t)
227
{
228
	Fcall rhdr;
229
	Fid *f;
230
 
231
	f = getfid(t->work.fid);
232
	if(f == 0) {
233
		reply(&t->work, &rhdr, Ebadfid);
234
		t->busy = 0;
235
		return;
236
	}
237
 
238
	if(f->fid >= 0)
239
		close(f->fid);
240
 
241
	freefid(t->work.fid);
242
	reply(&t->work, &rhdr, 0);
243
	t->busy = 0;
244
}
245
 
246
void
247
Xstat(Fsrpc *t)
248
{
249
	char err[ERRMAX], *path;
250
	Fcall rhdr;
251
	Fid *f;
252
	Dir *d;
253
	int s;
254
	uchar *statbuf;
255
 
256
	f = getfid(t->work.fid);
257
	if(f == 0) {
258
		reply(&t->work, &rhdr, Ebadfid);
259
		t->busy = 0;
260
		return;
261
	}
262
	if(f->fid >= 0)
263
		d = dirfstat(f->fid);
264
	else {
265
		path = makepath(f->f, "");
266
		d = dirstat(path);
267
		free(path);
268
	}
269
 
270
	if(d == nil) {
271
		errstr(err, sizeof err);
272
		reply(&t->work, &rhdr, err);
273
		t->busy = 0;
274
		return;
275
	}
276
 
277
	d->qid.path = f->f->qidt->uniqpath;
278
	s = sizeD2M(d);
279
	statbuf = emallocz(s);
280
	s = convD2M(d, statbuf, s);
281
	free(d);
282
	rhdr.nstat = s;
283
	rhdr.stat = statbuf;
284
	reply(&t->work, &rhdr, 0);
285
	free(statbuf);
286
	t->busy = 0;
287
}
288
 
289
static int
290
getiounit(int fd)
291
{
292
	int n;
293
 
294
	n = iounit(fd);
295
	if(n > messagesize-IOHDRSZ)
296
		n = messagesize-IOHDRSZ;
297
	return n;
298
}
299
 
300
void
301
Xcreate(Fsrpc *t)
302
{
303
	char err[ERRMAX], *path;
304
	Fcall rhdr;
305
	Fid *f;
306
	File *nf;
307
 
308
	f = getfid(t->work.fid);
309
	if(f == 0) {
310
		reply(&t->work, &rhdr, Ebadfid);
311
		t->busy = 0;
312
		return;
313
	}
314
 
315
 
316
	path = makepath(f->f, t->work.name);
317
	f->fid = create(path, t->work.mode, t->work.perm);
318
	free(path);
319
	if(f->fid < 0) {
320
		errstr(err, sizeof err);
321
		reply(&t->work, &rhdr, err);
322
		t->busy = 0;
323
		return;
324
	}
325
 
326
	nf = file(f->f, t->work.name);
327
	if(nf == 0) {
328
		errstr(err, sizeof err);
329
		reply(&t->work, &rhdr, err);
330
		t->busy = 0;
331
		return;
332
	}
333
 
334
	f->mode = t->work.mode;
335
	freefile(f->f);
336
	f->f = nf;
337
	rhdr.qid = f->f->qid;
338
	rhdr.iounit = getiounit(f->fid);
339
	reply(&t->work, &rhdr, 0);
340
	t->busy = 0;
341
}
342
 
343
void
344
Xremove(Fsrpc *t)
345
{
346
	char err[ERRMAX], *path;
347
	Fcall rhdr;
348
	Fid *f;
349
 
350
	f = getfid(t->work.fid);
351
	if(f == 0) {
352
		reply(&t->work, &rhdr, Ebadfid);
353
		t->busy = 0;
354
		return;
355
	}
356
 
357
	path = makepath(f->f, "");
358
	DEBUG(DFD, "\tremove: %s\n", path);
359
	if(remove(path) < 0) {
360
		free(path);
361
		errstr(err, sizeof err);
362
		reply(&t->work, &rhdr, err);
363
		t->busy = 0;
364
		return;
365
	}
366
	free(path);
367
 
368
	f->f->inval = 1;
369
	if(f->fid >= 0)
370
		close(f->fid);
371
	freefid(t->work.fid);
372
 
373
	reply(&t->work, &rhdr, 0);
374
	t->busy = 0;
375
}
376
 
377
void
378
Xwstat(Fsrpc *t)
379
{
380
	char err[ERRMAX], *path;
381
	Fcall rhdr;
382
	Fid *f;
383
	int s;
384
	char *strings;
385
	Dir d;
386
 
387
	f = getfid(t->work.fid);
388
	if(f == 0) {
389
		reply(&t->work, &rhdr, Ebadfid);
390
		t->busy = 0;
391
		return;
392
	}
393
	strings = emallocz(t->work.nstat);	/* ample */
394
	if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
395
		rerrstr(err, sizeof err);
396
		reply(&t->work, &rhdr, err);
397
		t->busy = 0;
398
		free(strings);
399
		return;
400
	}
401
 
402
	if(f->fid >= 0)
403
		s = dirfwstat(f->fid, &d);
404
	else {
405
		path = makepath(f->f, "");
406
		s = dirwstat(path, &d);
407
		free(path);
408
	}
409
	if(s < 0) {
410
		rerrstr(err, sizeof err);
411
		reply(&t->work, &rhdr, err);
412
	}
413
	else {
414
		/* wstat may really be rename */
415
		if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
416
			free(f->f->name);
417
			f->f->name = estrdup(d.name);
418
		}
419
		reply(&t->work, &rhdr, 0);
420
	}
421
	free(strings);
422
	t->busy = 0;
423
}
424
 
425
void
426
slave(Fsrpc *f)
427
{
428
	Proc *p;
429
	int pid;
430
	static int nproc;
431
 
432
	for(;;) {
433
		for(p = Proclist; p; p = p->next) {
434
			if(p->busy == 0) {
435
				f->pid = p->pid;
436
				p->busy = 1;
437
				pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f);
438
				if(pid != p->pid)
439
					fatal("rendezvous sync fail");
440
				return;
441
			}	
442
		}
443
 
444
		if(++nproc > MAXPROC)
445
			fatal("too many procs");
446
 
447
		pid = kproc("slave", blockingslave, nil);
448
		DEBUG(DFD, "slave pid %d\n", pid);
449
		if(pid == -1)
450
			fatal("kproc");
451
 
452
		p = malloc(sizeof(Proc));
453
		if(p == 0)
454
			fatal("out of memory");
455
 
456
		p->busy = 0;
457
		p->pid = pid;
458
		p->next = Proclist;
459
		Proclist = p;
460
 
461
DEBUG(DFD, "parent %d rendez\n", pid);
462
		rendezvous((void*)(uintptr)pid, p);
463
DEBUG(DFD, "parent %d went\n", pid);
464
	}
465
}
466
 
467
void
468
blockingslave(void *x)
469
{
470
	Fsrpc *p;
471
	Fcall rhdr;
472
	Proc *m;
473
	int pid;
474
 
475
	USED(x);
476
 
477
	notify(flushaction);
478
 
479
	pid = getpid();
480
 
481
DEBUG(DFD, "blockingslave %d rendez\n", pid);
482
	m = (Proc*)rendezvous((void*)(uintptr)pid, 0);
483
DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
484
 
485
	for(;;) {
486
		p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid);
487
		if((uintptr)p == ~(uintptr)0)			/* Interrupted */
488
			continue;
489
 
490
		DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
491
		if(p->flushtag != NOTAG)
492
			goto flushme;
493
 
494
		switch(p->work.type) {
495
		case Tread:
496
			slaveread(p);
497
			break;
498
 
499
		case Twrite:
500
			slavewrite(p);
501
			break;
502
 
503
		case Topen:
504
			slaveopen(p);
505
			break;
506
 
507
		default:
508
			reply(&p->work, &rhdr, "exportfs: slave type error");
509
		}
510
		if(p->flushtag != NOTAG) {
511
flushme:
512
			p->work.type = Tflush;
513
			p->work.tag = p->flushtag;
514
			reply(&p->work, &rhdr, 0);
515
		}
516
		p->busy = 0;
517
		m->busy = 0;
518
	}
519
}
520
 
521
int
522
openmount(int sfd)
523
{
524
	werrstr("openmount not implemented");
525
	return -1;
526
}
527
 
528
void
529
slaveopen(Fsrpc *p)
530
{
531
	char err[ERRMAX], *path;
532
	Fcall *work, rhdr;
533
	Fid *f;
534
	Dir *d;
535
 
536
	work = &p->work;
537
 
538
	f = getfid(work->fid);
539
	if(f == 0) {
540
		reply(work, &rhdr, Ebadfid);
541
		return;
542
	}
543
	if(f->fid >= 0) {
544
		close(f->fid);
545
		f->fid = -1;
546
	}
547
 
548
	path = makepath(f->f, "");
549
	DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
550
 
551
	p->canint = 1;
552
	if(p->flushtag != NOTAG){
553
		free(path);
554
		return;
555
	}
556
	/* There is a race here I ignore because there are no locks */
557
	f->fid = open(path, work->mode);
558
	free(path);
559
	p->canint = 0;
560
	if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
561
	Error:
562
		errstr(err, sizeof err);
563
		reply(work, &rhdr, err);
564
		return;
565
	}
566
	f->f->qid = d->qid;
567
	free(d);
568
	if(f->f->qid.type & QTMOUNT){	/* fork new exportfs for this */
569
		f->fid = openmount(f->fid);
570
		if(f->fid < 0)
571
			goto Error;
572
	}
573
 
574
	DEBUG(DFD, "\topen: fd %d\n", f->fid);
575
	f->mode = work->mode;
576
	rhdr.iounit = getiounit(f->fid);
577
	rhdr.qid = f->f->qid;
578
	reply(work, &rhdr, 0);
579
}
580
 
581
void
582
slaveread(Fsrpc *p)
583
{
584
	Fid *f;
585
	int n, r;
586
	Fcall *work, rhdr;
587
	char *data, err[ERRMAX];
588
 
589
	work = &p->work;
590
 
591
	f = getfid(work->fid);
592
	if(f == 0) {
593
		reply(work, &rhdr, Ebadfid);
594
		return;
595
	}
596
 
597
	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
598
	p->canint = 1;
599
	if(p->flushtag != NOTAG)
600
		return;
601
	data = malloc(n);
602
	if(data == nil)
603
		fatal(Enomem);
604
 
605
	/* can't just call pread, since directories must update the offset */
606
	r = pread(f->fid, data, n, work->offset);
607
	p->canint = 0;
608
	if(r < 0) {
609
		free(data);
610
		errstr(err, sizeof err);
611
		reply(work, &rhdr, err);
612
		return;
613
	}
614
 
615
	DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
616
 
617
	rhdr.data = data;
618
	rhdr.count = r;
619
	reply(work, &rhdr, 0);
620
	free(data);
621
}
622
 
623
void
624
slavewrite(Fsrpc *p)
625
{
626
	char err[ERRMAX];
627
	Fcall *work, rhdr;
628
	Fid *f;
629
	int n;
630
 
631
	work = &p->work;
632
 
633
	f = getfid(work->fid);
634
	if(f == 0) {
635
		reply(work, &rhdr, Ebadfid);
636
		return;
637
	}
638
 
639
	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
640
	p->canint = 1;
641
	if(p->flushtag != NOTAG)
642
		return;
643
	n = pwrite(f->fid, work->data, n, work->offset);
644
	p->canint = 0;
645
	if(n < 0) {
646
		errstr(err, sizeof err);
647
		reply(work, &rhdr, err);
648
		return;
649
	}
650
 
651
	DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
652
 
653
	rhdr.count = n;
654
	reply(work, &rhdr, 0);
655
}
656
 
657
void
658
reopen(Fid *f)
659
{
660
	USED(f);
661
	fatal("reopen");
662
}
663
 
664
void
665
flushaction(void *a, char *cause)
666
{
667
	USED(a);
668
	if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
669
		fprint(2, "exportsrv: note: %s\n", cause);
670
		exits("noted");
671
	}
672
	if(strncmp(cause, "kill", 4) == 0)
673
		noted(NDFLT);
674
 
675
	noted(NCONT);
676
}