xref: /plan9/sys/src/cmd/usb/lib/fs.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
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 	dprint(2, "%s: fsioproc pid %d\n", argv0, getpid());
340 	while((rpc = recvp(p)) != nil){
341 		t = &rpc->t;
342 		r = &rpc->r;
343 		fid = rpc->fid;
344 		rc = -1;
345 		dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type);
346 		switch(t->type){
347 		case Topen:
348 			rc = fsops->open(fsops, fid, t->mode);
349 			if(rc >= 0){
350 				r->iounit = 0;
351 				r->qid = fid->qid;
352 				fid->omode = t->mode & 3;
353 			}
354 			break;
355 		case Tread:
356 			rc = fsops->read(fsops, fid, r->data, t->count, t->offset);
357 			if(rc >= 0){
358 				if(rc > t->count)
359 					print("%s: bug: read %ld bytes > %ud wanted\n",
360 						argv0, rc, t->count);
361 				r->count = rc;
362 			}
363 			/*
364 			 * TODO: if we encounter a long run of continuous read
365 			 * errors, we should do something more drastic so that
366 			 * our caller doesn't just spin its wheels forever.
367 			 */
368 			break;
369 		case Twrite:
370 			rc = fsops->write(fsops, fid, t->data, t->count, t->offset);
371 			r->count = rc;
372 			break;
373 		default:
374 			sysfatal("fsioproc: bad type");
375 		}
376 		if(rc < 0)
377 			sendp(outc, fserror(rpc, "%r"));
378 		else
379 			sendp(outc, rpc);
380 		sendp(endc, p);
381 	}
382 	chanfree(p);
383 	dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid());
384 	threadexits(nil);
385 }
386 
387 static Rpc*
388 fsopen(Rpc *r)
389 {
390 	Channel *p;
391 
392 	if(r->fid->omode != ONONE)
393 		return fserror(r, Eisopen);
394 	if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0)
395 		return fserror(r, Eperm);
396 	p = recvp(procc);
397 	sendp(p, r);
398 	return nil;
399 }
400 
401 int
402 usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg)
403 {
404 	int i, n, nd;
405 	char name[Namesz];
406 	Dir d;
407 
408 	memset(&d, 0, sizeof(d));
409 	d.name = name;
410 	d.uid = d.gid = d.muid = user;
411 	d.atime = time(nil);
412 	d.mtime = epoch;
413 	d.length = 0;
414 	for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){
415 		if(usbfsdebug > 1)
416 			fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d);
417 		nd = convD2M(&d, (uchar*)data+n, cnt-n);
418 		if(nd <= BIT16SZ)
419 			break;
420 		if(off > 0)
421 			off -= nd;
422 		else
423 			n += nd;
424 		d.name = name;
425 		d.uid = d.gid = d.muid = user;
426 		d.atime = time(nil);
427 		d.mtime = epoch;
428 		d.length = 0;
429 	}
430 	return n;
431 }
432 
433 long
434 usbreadbuf(void *data, long count, vlong offset, void *buf, long n)
435 {
436 	if(offset >= n)
437 		return 0;
438 	if(offset + count > n)
439 		count = n - offset;
440 	memmove(data, (char*)buf + offset, count);
441 	return count;
442 }
443 
444 static Rpc*
445 fsread(Rpc *r)
446 {
447 	Channel *p;
448 
449 	if(r->fid->omode != OREAD && r->fid->omode != ORDWR)
450 		return fserror(r, Eperm);
451 	p = recvp(procc);
452 	sendp(p, r);
453 	return nil;
454 }
455 
456 static Rpc*
457 fswrite(Rpc *r)
458 {
459 	Channel *p;
460 
461 	if(r->fid->omode != OWRITE && r->fid->omode != ORDWR)
462 		return fserror(r, Eperm);
463 	p = recvp(procc);
464 	sendp(p, r);
465 	return nil;
466 }
467 
468 static Rpc*
469 fsclunk(Rpc *r)
470 {
471 	freefid(r->fid);
472 	return r;
473 }
474 
475 static Rpc*
476 fsno(Rpc *r)
477 {
478 	return fserror(r, Eperm);
479 }
480 
481 static Rpc*
482 fsstat(Rpc *r)
483 {
484 	Dir d;
485 	char name[Namesz];
486 
487 	memset(&d, 0, sizeof(d));
488 	d.name = name;
489 	d.uid = d.gid = d.muid = user;
490 	d.atime = time(nil);
491 	d.mtime = epoch;
492 	d.length = 0;
493 	if(fsops->stat(fsops, r->fid->qid, &d) < 0)
494 		return fserror(r, "%r");
495 	r->r.stat = (uchar*)r->data;
496 	r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize);
497 	return r;
498 }
499 
500 static Rpc*
501 fsflush(Rpc *r)
502 {
503 	/*
504 	 * Flag it as flushed and respond.
505 	 * Either outproc will reply to the flushed request
506 	 * before responding to flush, or it will never reply to it.
507 	 * Note that we do NOT abort the ongoing I/O.
508 	 * That might leave the affected endpoints in a failed
509 	 * state. Instead, we pretend the request is aborted.
510 	 *
511 	 * Only open, read, and write are processed
512 	 * by auxiliary processes and other requests wil never be
513 	 * flushed in practice.
514 	 */
515 	flushrpc(r->t.oldtag);
516 	return r;
517 }
518 
519 Rpc* (*fscalls[])(Rpc*) = {
520 	[Tversion]	fsversion,
521 	[Tauth]		fsno,
522 	[Tattach]	fsattach,
523 	[Twalk]		fswalk,
524 	[Topen]		fsopen,
525 	[Tcreate]	fsno,
526 	[Tread]		fsread,
527 	[Twrite]	fswrite,
528 	[Tclunk]	fsclunk,
529 	[Tremove]	fsno,
530 	[Tstat]		fsstat,
531 	[Twstat]	fsno,
532 	[Tflush]	fsflush,
533 };
534 
535 static void
536 outproc(void*)
537 {
538 	static uchar buf[Bufsize];
539 	Rpc *rpc;
540 	int nw;
541 	static int once = 0;
542 
543 	if(once++ != 0)
544 		sysfatal("more than one outproc");
545 	for(;;){
546 		do
547 			rpc = recvp(outc);
548 		while(rpc == nil);		/* a delayed reply */
549 		if(rpc->t.tag == Dietag)
550 			break;
551 		if(rpc->flushed){
552 			dprint(2, "outproc: tag %d flushed\n", rpc->t.tag);
553 			freerpc(rpc);
554 			continue;
555 		}
556 		dprint(2, "-> %F\n", &rpc->r);
557 		nw = convS2M(&rpc->r, buf, sizeof(buf));
558 		if(nw == sizeof(buf))
559 			fprint(2, "%s: outproc: buffer is too small\n", argv0);
560 		if(nw <= BIT16SZ)
561 			fprint(2, "%s: conS2M failed\n", argv0);
562 		else if(write(fsfd, buf, nw) != nw){
563 			fprint(2, "%s: outproc: write: %r", argv0);
564 			/* continue and let the reader abort us */
565 		}
566 		if(usbfsdebug > 1)
567 			dump();
568 		freerpc(rpc);
569 	}
570 	dprint(2, "%s: outproc: exiting\n", argv0);
571 }
572 
573 static void
574 usbfs(void*)
575 {
576 	Rpc *rpc;
577 	int nr;
578 	static int once = 0;
579 
580 	if(once++ != 0)
581 		sysfatal("more than one usbfs proc");
582 
583 	outc = chancreate(sizeof(Rpc*), 1);
584 	procc = chancreate(sizeof(Channel*), 0);
585 	endc = chancreate(sizeof(Channel*), 0);
586 	if(outc == nil || procc == nil || endc == nil)
587 		sysfatal("chancreate: %r");
588 	threadcreate(schedproc, nil, Stack);
589 	proccreate(outproc, nil, Stack);
590 	for(;;){
591 		rpc = newrpc();
592 		do{
593 			nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data));
594 		}while(nr == 0);
595 		if(nr < 0){
596 			dprint(2, "%s: usbfs: read: '%r'", argv0);
597 			if(fsops->end != nil)
598 				fsops->end(fsops);
599 			else
600 				closedev(fsops->dev);
601 			rpc->t.tag = Dietag;
602 			sendp(outc, rpc);
603 			break;
604 		}
605 		if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){
606 			dprint(2, "%s: convM2S failed\n", argv0);
607 			freerpc(rpc);
608 			continue;
609 		}
610 		dprint(2, "<- %F\n", &rpc->t);
611 		rpc->r.tag = rpc->t.tag;
612 		rpc->r.type = rpc->t.type + 1;
613 		rpc->r.fid = rpc->t.fid;
614 		if(fscalls[rpc->t.type] == nil){
615 			sendp(outc, fserror(rpc, Ebadcall));
616 			continue;
617 		}
618 		if(rpc->t.fid != Nofid){
619 			if(rpc->t.type == Tattach)
620 				rpc->fid = getfid(rpc->t.fid, 1);
621 			else
622 				rpc->fid = getfid(rpc->t.fid, 0);
623 			if(rpc->fid == nil){
624 				sendp(outc, fserror(rpc, Ebadfid));
625 				continue;
626 			}
627 		}
628 		sendp(outc, fscalls[rpc->t.type](rpc));
629 	}
630 	dprint(2, "%s: ubfs: eof: exiting\n", argv0);
631 }
632 
633 void
634 usbfsinit(char* srv, char *mnt, Usbfs *f, int flag)
635 {
636 	int fd[2];
637 	int sfd;
638 	int afd;
639 	char sfile[40];
640 
641 	fsops = f;
642 	if(pipe(fd) < 0)
643 		sysfatal("pipe: %r");
644 	user = getuser();
645 	epoch = time(nil);
646 
647 	fmtinstall('D', dirfmt);
648 	fmtinstall('M', dirmodefmt);
649 	fmtinstall('F', fcallfmt);
650 	fsfd = fd[1];
651 	procrfork(usbfs, nil, Stack, RFNAMEG);	/* no RFFDG */
652 	if(srv != nil){
653 		snprint(sfile, sizeof(sfile), "#s/%s", srv);
654 		remove(sfile);
655 		sfd = create(sfile, OWRITE, 0660);
656 		if(sfd < 0)
657 			sysfatal("post: %r");
658 		snprint(sfile, sizeof(sfile), "%d", fd[0]);
659 		if(write(sfd, sfile, strlen(sfile)) != strlen(sfile))
660 			sysfatal("post: %r");
661 		close(sfd);
662 	}
663 	if(mnt != nil){
664 		sfd = dup(fd[0], -1);	/* debug */
665 		afd = fauth(sfd, "");
666 		if(afd >= 0)
667 			sysfatal("authentication required??");
668 		if(mount(sfd, -1, mnt, flag, "") < 0)
669 			sysfatal("mount: %r");
670 	}
671 	close(fd[0]);
672 }
673 
674