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 677