Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/usb/lib/fs.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Framework for USB devices that provide a file tree.
3
 * The main process (usbd or the driver's main proc)
4
 * calls fsinit() to start FS operation.
5
 *
6
 * One or more drivers call fsstart/fsend to register
7
 * or unregister their operations for their subtrees.
8
 *
9
 * root dir has qids with 0 in high 32 bits.
10
 * for other files we keep the device id in there.
11
 * The low 32 bits for directories at / must be 0.
12
 */
13
#include <u.h>
14
#include <libc.h>
15
#include <thread.h>
16
#include <fcall.h>
17
#include "usb.h"
18
#include "usbfs.h"
19
 
20
#undef dprint
21
#define dprint if(usbfsdebug)fprint
22
 
23
typedef struct Rpc Rpc;
24
 
25
enum
26
{
27
	Nproc = 3,		/* max nb. of cached FS procs */
28
 
29
	Nofid = ~0,		/* null value for fid number */
30
	Notag = ~0,		/* null value for tags */
31
	Dietag = 0xdead,		/* fake tag to ask outproc to die */
32
 
33
	Stack = 16 * 1024,
34
 
35
	/* Fsproc requests */
36
	Run = 0,		/* call f(r) */
37
	Exit,			/* terminate */
38
 
39
};
40
 
41
struct Rpc
42
{
43
	Fcall	t;
44
	Fcall	r;
45
	Fid*	fid;
46
	int	flushed;
47
	Rpc*	next;
48
	char	data[Bufsize];
49
};
50
 
51
int usbfsdebug;
52
 
53
char Enotfound[] = "file not found";
54
char Etoosmall[] = "parameter too small";
55
char Eio[] = "i/o error";
56
char Eperm[] = "permission denied";
57
char Ebadcall[] = "unknown fs call";
58
char Ebadfid[] = "fid not found";
59
char Einuse[] = "fid already in use";
60
char Eisopen[] = "it is already open";
61
char Ebadctl[] = "unknown control request";
62
 
63
static char *user;
64
static ulong epoch;
65
static ulong msgsize = Msgsize;
66
static int fsfd = -1;
67
static Channel *outc;	/* of Rpc* */
68
 
69
static QLock rpclck;	/* protect vars in this block */
70
static Fid *freefids;
71
static Fid *fids;
72
static Rpc *freerpcs;
73
static Rpc *rpcs;
74
 
75
static Channel*procc;
76
static Channel*endc;
77
 
78
static Usbfs* fsops;
79
 
80
static void fsioproc(void*);
81
 
82
static void
83
schedproc(void*)
84
{
85
	Channel *proc[Nproc];
86
	int nproc;
87
	Channel *p;
88
 
89
	Alt a[] =
90
	{
91
		{procc, &proc[0], CHANSND},
92
		{endc, &p, CHANRCV},
93
		{nil, nil, CHANEND}
94
	};
95
	memset(proc, 0, sizeof(proc));
96
	nproc = 0;
97
	for(;;){
98
		if(nproc == 0){
99
			proc[0] = chancreate(sizeof(Rpc*), 0);
100
			proccreate(fsioproc, proc[0], Stack);
101
			nproc++;
102
		}
103
		switch(alt(a)){
104
		case 0:
105
			proc[0] = nil;
106
			if(nproc > 1){
107
				proc[0] = proc[nproc-1];
108
				proc[nproc-1] = nil;
109
			}
110
			nproc--;
111
			break;
112
		case 1:
113
			if(nproc < nelem(proc))
114
				proc[nproc++] = p;
115
			else
116
				sendp(p, nil);
117
			break;
118
		default:
119
			sysfatal("alt");
120
		}
121
	}
122
}
123
 
124
static void
125
dump(void)
126
{
127
	Rpc *rpc;
128
	Fid *fid;
129
 
130
	qlock(&rpclck);
131
	fprint(2, "dump:\n");
132
	for(rpc = rpcs; rpc != nil; rpc = rpc->next)
133
		fprint(2, "rpc %#p %F next %#p\n", rpc, &rpc->t, rpc->next);
134
	for(fid = fids; fid != nil; fid = fid->next)
135
		fprint(2, "fid %d qid %#llux omode %d aux %#p\n",
136
			fid->fid, fid->qid.path, fid->omode, fid->aux);
137
	fprint(2, "\n");
138
	qunlock(&rpclck);
139
}
140
 
141
static Rpc*
142
newrpc(void)
143
{
144
	Rpc *r;
145
 
146
	qlock(&rpclck);
147
	r = freerpcs;
148
	if(r != nil)
149
		freerpcs = r->next;
150
	else
151
		r = emallocz(sizeof(Rpc), 0);
152
	r->next = rpcs;
153
	rpcs = r;
154
	r->t.tag = r->r.tag = Notag;
155
	r->t.fid = r->r.fid = Nofid;
156
	r->t.type = r->r.type = 0;
157
	r->flushed = 0;
158
	r->fid = nil;
159
	r->r.data = (char*)r->data;
160
	qunlock(&rpclck);
161
	return r;
162
}
163
 
164
static void
165
freerpc(Rpc *r)
166
{
167
	Rpc **l;
168
	if(r == nil)
169
		return;
170
	qlock(&rpclck);
171
	for(l = &rpcs; *l != nil && *l != r; l = &(*l)->next)
172
		;
173
	assert(*l == r);
174
	*l = r->next;
175
	r->next = freerpcs;
176
	freerpcs = r;
177
	r->t.type = 0;
178
	r->t.tag = 0x77777777;
179
	qunlock(&rpclck);
180
}
181
 
182
static void
183
flushrpc(int tag)
184
{
185
	Rpc *r;
186
 
187
	qlock(&rpclck);
188
	for(r = rpcs; r != nil; r = r->next)
189
		if(r->t.tag == tag){
190
			r->flushed = 1;
191
			break;
192
		}
193
	qunlock(&rpclck);
194
}
195
 
196
static Fid*
197
getfid(int fid, int alloc)
198
{
199
	Fid *f;
200
 
201
	qlock(&rpclck);
202
	for(f = fids; f != nil && f->fid != fid; f = f->next)
203
		;
204
	if(f != nil && alloc != 0){	/* fid in use */
205
		qunlock(&rpclck);
206
		return nil;
207
	}
208
	if(f == nil && alloc != 0){
209
		if(freefids != nil){
210
			f = freefids;
211
			freefids = freefids->next;
212
		}else
213
			f = emallocz(sizeof(Fid), 1);
214
		f->fid = fid;
215
		f->aux = nil;
216
		f->omode = ONONE;
217
		f->next = fids;
218
		fids = f;
219
	}
220
	qunlock(&rpclck);
221
	return f;
222
}
223
 
224
static void
225
freefid(Fid *f)
226
{
227
	Fid **l;
228
 
229
	if(f == nil)
230
		return;
231
	if(fsops->clunk != nil)
232
		fsops->clunk(fsops, f);
233
	qlock(&rpclck);
234
	for(l = &fids; *l != nil && *l != f; l = &(*l)->next)
235
		;
236
	assert(*l == f);
237
	*l = f->next;
238
	f->next = freefids;
239
	freefids = f;
240
	qunlock(&rpclck);
241
}
242
 
243
static Rpc*
244
fserror(Rpc *rpc, char* fmt, ...)
245
{
246
	va_list arg;
247
	char *c;
248
 
249
	va_start(arg, fmt);
250
	c = (char*)rpc->data;
251
	vseprint(c, c+sizeof(rpc->data), fmt, arg);
252
	va_end(arg);
253
	rpc->r.type = Rerror;
254
	rpc->r.ename = (char*)rpc->data;
255
	return rpc;
256
}
257
 
258
static Rpc*
259
fsversion(Rpc *r)
260
{
261
	if(r->t.msize < 256)
262
		return fserror(r, Etoosmall);
263
	if(strncmp(r->t.version, "9P2000", 6) != 0)
264
		return fserror(r, "wrong version");
265
	if(r->t.msize < msgsize)
266
		msgsize = r->t.msize;
267
	r->r.msize = msgsize;
268
	r->r.version = "9P2000";
269
	return r;
270
}
271
 
272
static Rpc*
273
fsattach(Rpc *r)
274
{
275
	static int already;
276
 
277
	/* Reload user because at boot it could be still none */
278
	user=getuser();
279
	if(already++ > 0 && strcmp(r->t.uname, user) != 0)
280
		return fserror(r, Eperm);
281
	if(r->fid == nil)
282
		return fserror(r, Einuse);
283
 
284
	r->r.qid.type = QTDIR;
285
	r->r.qid.path = fsops->qid;
286
	r->r.qid.vers = 0;
287
	r->fid->qid = r->r.qid;
288
	return r;
289
}
290
 
291
static Rpc*
292
fswalk(Rpc *r)
293
{
294
	int i;
295
	Fid *nfid, *ofid;
296
 
297
	if(r->fid->omode != ONONE)
298
		return fserror(r, Eisopen);
299
 
300
	nfid = nil;
301
	ofid = r->fid;
302
	if(r->t.newfid != r->t.fid){
303
		nfid = getfid(r->t.newfid, 1);
304
		if(nfid == nil)
305
			return fserror(r, Einuse);
306
		nfid->qid = r->fid->qid;
307
		if(fsops->clone != nil)
308
			fsops->clone(fsops, ofid, nfid);
309
		else
310
			nfid->aux = r->fid->aux;
311
		r->fid = nfid;
312
	}
313
	r->r.nwqid = 0;
314
	for(i = 0; i < r->t.nwname; i++)
315
		if(fsops->walk(fsops, r->fid, r->t.wname[i]) < 0)
316
			break;
317
		else
318
			r->r.wqid[i] = r->fid->qid;
319
	r->r.nwqid = i;
320
	if(i != r->t.nwname && r->t.nwname > 0){
321
		if(nfid != nil)
322
			freefid(nfid);
323
		r->fid = ofid;
324
	}
325
	if(i == 0 && r->t.nwname > 0)
326
		return fserror(r, "%r");
327
	return r;
328
}
329
 
330
static void
331
fsioproc(void* a)
332
{
333
	long rc;
334
	Channel *p = a;
335
	Rpc *rpc;
336
	Fcall *t, *r;
337
	Fid *fid;
338
 
339
	threadsetname("fsioproc");
340
	dprint(2, "%s: fsioproc pid %d\n", argv0, getpid());
341
	while((rpc = recvp(p)) != nil){
342
		t = &rpc->t;
343
		r = &rpc->r;
344
		fid = rpc->fid;
345
		rc = -1;
346
		dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type);
347
		switch(t->type){
348
		case Topen:
349
			rc = fsops->open(fsops, fid, t->mode);
350
			if(rc >= 0){
351
				r->iounit = 0;
352
				r->qid = fid->qid;
353
				fid->omode = t->mode & 3;
354
			}
355
			break;
356
		case Tread:
357
			rc = fsops->read(fsops, fid, r->data, t->count, t->offset);
358
			if(rc >= 0){
359
				if(rc > t->count)
360
					print("%s: bug: read %ld bytes > %ud wanted\n",
361
						argv0, rc, t->count);
362
				r->count = rc;
363
			}
364
			/*
365
			 * TODO: if we encounter a long run of continuous read
366
			 * errors, we should do something more drastic so that
367
			 * our caller doesn't just spin its wheels forever.
368
			 */
369
			break;
370
		case Twrite:
371
			rc = fsops->write(fsops, fid, t->data, t->count, t->offset);
372
			r->count = rc;
373
			break;
374
		default:
375
			sysfatal("fsioproc: bad type");
376
		}
377
		if(rc < 0)
378
			sendp(outc, fserror(rpc, "%r"));
379
		else
380
			sendp(outc, rpc);
381
		sendp(endc, p);
382
	}
383
	chanfree(p);
384
	dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid());
385
	threadexits(nil);
386
}
387
 
388
static Rpc*
389
fsopen(Rpc *r)
390
{
391
	Channel *p;
392
 
393
	if(r->fid->omode != ONONE)
394
		return fserror(r, Eisopen);
395
	if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0)
396
		return fserror(r, Eperm);
397
	p = recvp(procc);
398
	sendp(p, r);
399
	return nil;
400
}
401
 
402
int
403
usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg)
404
{
405
	int i, n, nd;
406
	char name[Namesz];
407
	Dir d;
408
 
409
	memset(&d, 0, sizeof(d));
410
	d.name = name;
411
	d.uid = d.gid = d.muid = user;
412
	d.atime = time(nil);
413
	d.mtime = epoch;
414
	d.length = 0;
415
	for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){
416
		if(usbfsdebug > 1)
417
			fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d);
418
		nd = convD2M(&d, (uchar*)data+n, cnt-n);
419
		if(nd <= BIT16SZ)
420
			break;
421
		if(off > 0)
422
			off -= nd;
423
		else
424
			n += nd;
425
		d.name = name;
426
		d.uid = d.gid = d.muid = user;
427
		d.atime = time(nil);
428
		d.mtime = epoch;
429
		d.length = 0;
430
	}
431
	return n;
432
}
433
 
434
long
435
usbreadbuf(void *data, long count, vlong offset, void *buf, long n)
436
{
437
	if(offset >= n)
438
		return 0;
439
	if(offset + count > n)
440
		count = n - offset;
441
	memmove(data, (char*)buf + offset, count);
442
	return count;
443
}
444
 
445
static Rpc*
446
fsread(Rpc *r)
447
{
448
	Channel *p;
449
 
450
	if(r->fid->omode != OREAD && r->fid->omode != ORDWR)
451
		return fserror(r, Eperm);
452
	p = recvp(procc);
453
	sendp(p, r);
454
	return nil;
455
}
456
 
457
static Rpc*
458
fswrite(Rpc *r)
459
{
460
	Channel *p;
461
 
462
	if(r->fid->omode != OWRITE && r->fid->omode != ORDWR)
463
		return fserror(r, Eperm);
464
	p = recvp(procc);
465
	sendp(p, r);
466
	return nil;
467
}
468
 
469
static Rpc*
470
fsclunk(Rpc *r)
471
{
472
	freefid(r->fid);
473
	return r;
474
}
475
 
476
static Rpc*
477
fsno(Rpc *r)
478
{
479
	return fserror(r, Eperm);
480
}
481
 
482
static Rpc*
483
fsstat(Rpc *r)
484
{
485
	Dir d;
486
	char name[Namesz];
487
 
488
	memset(&d, 0, sizeof(d));
489
	d.name = name;
490
	d.uid = d.gid = d.muid = user;
491
	d.atime = time(nil);
492
	d.mtime = epoch;
493
	d.length = 0;
494
	if(fsops->stat(fsops, r->fid->qid, &d) < 0)
495
		return fserror(r, "%r");
496
	r->r.stat = (uchar*)r->data;
497
	r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize);
498
	return r;
499
}
500
 
501
static Rpc*
502
fsflush(Rpc *r)
503
{
504
	/*
505
	 * Flag it as flushed and respond.
506
	 * Either outproc will reply to the flushed request
507
	 * before responding to flush, or it will never reply to it.
508
	 * Note that we do NOT abort the ongoing I/O.
509
	 * That might leave the affected endpoints in a failed
510
	 * state. Instead, we pretend the request is aborted.
511
	 *
512
	 * Only open, read, and write are processed
513
	 * by auxiliary processes and other requests wil never be
514
	 * flushed in practice.
515
	 */
516
	flushrpc(r->t.oldtag);
517
	return r;
518
}
519
 
520
Rpc* (*fscalls[])(Rpc*) = {
521
	[Tversion]	fsversion,
522
	[Tauth]		fsno,
523
	[Tattach]	fsattach,
524
	[Twalk]		fswalk,
525
	[Topen]		fsopen,
526
	[Tcreate]	fsno,
527
	[Tread]		fsread,
528
	[Twrite]	fswrite,
529
	[Tclunk]	fsclunk,
530
	[Tremove]	fsno,
531
	[Tstat]		fsstat,
532
	[Twstat]	fsno,
533
	[Tflush]	fsflush,
534
};
535
 
536
static void
537
outproc(void*)
538
{
539
	static uchar buf[Bufsize];
540
	Rpc *rpc;
541
	int nw;
542
	static int once = 0;
543
 
544
	if(once++ != 0)
545
		sysfatal("more than one outproc");
546
	threadsetname("outproc");
547
	for(;;){
548
		do
549
			rpc = recvp(outc);
550
		while(rpc == nil);		/* a delayed reply */
551
		if(rpc->t.tag == Dietag)
552
			break;
553
		if(rpc->flushed){
554
			dprint(2, "outproc: tag %d flushed\n", rpc->t.tag);
555
			freerpc(rpc);
556
			continue;
557
		}
558
		dprint(2, "-> %F\n", &rpc->r);
559
		nw = convS2M(&rpc->r, buf, sizeof(buf));
560
		if(nw == sizeof(buf))
561
			fprint(2, "%s: outproc: buffer is too small\n", argv0);
562
		if(nw <= BIT16SZ)
563
			fprint(2, "%s: conS2M failed\n", argv0);
564
		else if(write(fsfd, buf, nw) != nw){
565
			fprint(2, "%s: outproc: write: %r", argv0);
566
			/* continue and let the reader abort us */
567
		}
568
		if(usbfsdebug > 1)
569
			dump();
570
		freerpc(rpc);
571
	}
572
	dprint(2, "%s: outproc: exiting\n", argv0);
573
}
574
 
575
static void
576
usbfs(void*)
577
{
578
	Rpc *rpc;
579
	int nr;
580
	static int once = 0;
581
 
582
	if(once++ != 0)
583
		sysfatal("more than one usbfs proc");
584
 
585
	threadsetname("usbfs");
586
	outc = chancreate(sizeof(Rpc*), 1);
587
	procc = chancreate(sizeof(Channel*), 0);
588
	endc = chancreate(sizeof(Channel*), 0);
589
	if(outc == nil || procc == nil || endc == nil)
590
		sysfatal("chancreate: %r");
591
	threadcreate(schedproc, nil, Stack);
592
	proccreate(outproc, nil, Stack);
593
	for(;;){
594
		rpc = newrpc();
595
		do{
596
			nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data));
597
		}while(nr == 0);
598
		if(nr < 0){
599
			dprint(2, "%s: usbfs: read: '%r'", argv0);
600
			if(fsops->end != nil)
601
				fsops->end(fsops);
602
			else
603
				closedev(fsops->dev);
604
			rpc->t.tag = Dietag;
605
			sendp(outc, rpc);
606
			break;
607
		}
608
		if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){
609
			dprint(2, "%s: convM2S failed\n", argv0);
610
			freerpc(rpc);
611
			continue;
612
		}
613
		dprint(2, "<- %F\n", &rpc->t);
614
		rpc->r.tag = rpc->t.tag;
615
		rpc->r.type = rpc->t.type + 1;
616
		rpc->r.fid = rpc->t.fid;
617
		if(fscalls[rpc->t.type] == nil){
618
			sendp(outc, fserror(rpc, Ebadcall));
619
			continue;
620
		}
621
		if(rpc->t.fid != Nofid){
622
			if(rpc->t.type == Tattach)
623
				rpc->fid = getfid(rpc->t.fid, 1);
624
			else
625
				rpc->fid = getfid(rpc->t.fid, 0);
626
			if(rpc->fid == nil){
627
				sendp(outc, fserror(rpc, Ebadfid));
628
				continue;
629
			}
630
		}
631
		sendp(outc, fscalls[rpc->t.type](rpc));
632
	}
633
	dprint(2, "%s: ubfs: eof: exiting\n", argv0);
634
}
635
 
636
void
637
usbfsinit(char* srv, char *mnt, Usbfs *f, int flag)
638
{
639
	int fd[2];
640
	int sfd;
641
	int afd;
642
	char sfile[40];
643
 
644
	fsops = f;
645
	if(pipe(fd) < 0)
646
		sysfatal("pipe: %r");
647
	user = getuser();
648
	epoch = time(nil);
649
 
650
	fmtinstall('D', dirfmt);
651
	fmtinstall('M', dirmodefmt);
652
	fmtinstall('F', fcallfmt);
653
	fsfd = fd[1];
654
	procrfork(usbfs, nil, Stack, RFNAMEG);	/* no RFFDG */
655
	if(srv != nil){
656
		snprint(sfile, sizeof(sfile), "#s/%s", srv);
657
		remove(sfile);
658
		sfd = create(sfile, OWRITE, 0660);
659
		if(sfd < 0)
660
			sysfatal("post: %r");
661
		snprint(sfile, sizeof(sfile), "%d", fd[0]);
662
		if(write(sfd, sfile, strlen(sfile)) != strlen(sfile))
663
			sysfatal("post: %r");
664
		close(sfd);
665
	}
666
	if(mnt != nil){
667
		sfd = dup(fd[0], -1);	/* debug */
668
		afd = fauth(sfd, "");
669
		if(afd >= 0)
670
			sysfatal("authentication required??");
671
		if(mount(sfd, -1, mnt, flag, "") < 0)
672
			sysfatal("mount: %r");
673
	}
674
	close(fd[0]);
675
}
676