exportfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <fcall.h>
  4. #include "compat.h"
  5. #include "error.h"
  6. typedef struct Fid Fid;
  7. typedef struct Export Export;
  8. typedef struct Exq Exq;
  9. typedef struct Exwork Exwork;
  10. enum
  11. {
  12. Nfidhash = 32,
  13. Maxfdata = 8192,
  14. Maxrpc = IOHDRSZ + Maxfdata,
  15. };
  16. struct Export
  17. {
  18. Ref r;
  19. Exq* work;
  20. Lock fidlock;
  21. Fid* fid[Nfidhash];
  22. int io; /* fd to read/write */
  23. int iounit;
  24. int nroots;
  25. Chan **roots;
  26. };
  27. struct Fid
  28. {
  29. Fid* next;
  30. Fid** last;
  31. Chan* chan;
  32. long offset;
  33. int fid;
  34. int ref; /* fcalls using the fid; locked by Export.Lock */
  35. int attached; /* fid attached or cloned but not clunked */
  36. };
  37. struct Exq
  38. {
  39. Lock lk;
  40. int responding; /* writing out reply message */
  41. int noresponse; /* don't respond to this one */
  42. Exq* next;
  43. int shut; /* has been noted for shutdown */
  44. Export* export;
  45. void* slave;
  46. Fcall rpc;
  47. uchar buf[Maxrpc];
  48. };
  49. struct Exwork
  50. {
  51. Lock l;
  52. int ref;
  53. int nwaiters; /* queue of slaves waiting for work */
  54. QLock qwait;
  55. Rendez rwait;
  56. Exq *head; /* work waiting for a slave */
  57. Exq *tail;
  58. };
  59. Exwork exq;
  60. static void exshutdown(Export*);
  61. static void exflush(Export*, int, int);
  62. static void exslave(void*);
  63. static void exfree(Export*);
  64. static void exportproc(Export*);
  65. static char* Exattach(Export*, Fcall*, uchar*);
  66. static char* Exauth(Export*, Fcall*, uchar*);
  67. static char* Exclunk(Export*, Fcall*, uchar*);
  68. static char* Excreate(Export*, Fcall*, uchar*);
  69. static char* Exversion(Export*, Fcall*, uchar*);
  70. static char* Exopen(Export*, Fcall*, uchar*);
  71. static char* Exread(Export*, Fcall*, uchar*);
  72. static char* Exremove(Export*, Fcall*, uchar*);
  73. static char* Exsession(Export*, Fcall*, uchar*);
  74. static char* Exstat(Export*, Fcall*, uchar*);
  75. static char* Exwalk(Export*, Fcall*, uchar*);
  76. static char* Exwrite(Export*, Fcall*, uchar*);
  77. static char* Exwstat(Export*, Fcall*, uchar*);
  78. static char *(*fcalls[Tmax])(Export*, Fcall*, uchar*);
  79. static char Enofid[] = "no such fid";
  80. static char Eseekdir[] = "can't seek on a directory";
  81. static char Ereaddir[] = "unaligned read of a directory";
  82. static int exdebug = 0;
  83. int
  84. sysexport(int fd, Chan **roots, int nroots)
  85. {
  86. Export *fs;
  87. fs = smalloc(sizeof(Export));
  88. fs->r.ref = 1;
  89. fs->io = fd;
  90. fs->roots = roots;
  91. fs->nroots = nroots;
  92. exportproc(fs);
  93. return 0;
  94. }
  95. static void
  96. exportinit(void)
  97. {
  98. lock(&exq.l);
  99. exq.ref++;
  100. if(fcalls[Tversion] != nil){
  101. unlock(&exq.l);
  102. return;
  103. }
  104. fmtinstall('F', fcallfmt);
  105. fcalls[Tversion] = Exversion;
  106. fcalls[Tauth] = Exauth;
  107. fcalls[Tattach] = Exattach;
  108. fcalls[Twalk] = Exwalk;
  109. fcalls[Topen] = Exopen;
  110. fcalls[Tcreate] = Excreate;
  111. fcalls[Tread] = Exread;
  112. fcalls[Twrite] = Exwrite;
  113. fcalls[Tclunk] = Exclunk;
  114. fcalls[Tremove] = Exremove;
  115. fcalls[Tstat] = Exstat;
  116. fcalls[Twstat] = Exwstat;
  117. unlock(&exq.l);
  118. }
  119. static void
  120. exportproc(Export *fs)
  121. {
  122. Exq *q;
  123. int n, ed;
  124. exportinit();
  125. ed = errdepth(-1);
  126. for(;;){
  127. errdepth(ed);
  128. q = smalloc(sizeof(Exq));
  129. n = read9pmsg(fs->io, q->buf, Maxrpc);
  130. if(n <= 0 || convM2S(q->buf, n, &q->rpc) != n)
  131. goto bad;
  132. if(exdebug)
  133. print("export %d <- %F\n", getpid(), &q->rpc);
  134. if(q->rpc.type == Tflush){
  135. exflush(fs, q->rpc.tag, q->rpc.oldtag);
  136. free(q);
  137. continue;
  138. }
  139. q->export = fs;
  140. incref(&fs->r);
  141. lock(&exq.l);
  142. if(exq.head == nil)
  143. exq.head = q;
  144. else
  145. exq.tail->next = q;
  146. q->next = nil;
  147. exq.tail = q;
  148. n = exq.nwaiters;
  149. if(n)
  150. exq.nwaiters = n - 1;
  151. unlock(&exq.l);
  152. if(!n)
  153. kproc("exportfs", exslave, nil);
  154. rendwakeup(&exq.rwait);
  155. }
  156. bad:
  157. free(q);
  158. if(exdebug)
  159. fprint(2, "export proc shutting down: %r\n");
  160. exshutdown(fs);
  161. exfree(fs);
  162. }
  163. static void
  164. exflush(Export *fs, int flushtag, int tag)
  165. {
  166. Exq *q, **last;
  167. Fcall fc;
  168. uchar buf[Maxrpc];
  169. int n;
  170. /* hasn't been started? */
  171. lock(&exq.l);
  172. last = &exq.head;
  173. for(q = exq.head; q != nil; q = q->next){
  174. if(q->export == fs && q->rpc.tag == tag){
  175. *last = q->next;
  176. unlock(&exq.l);
  177. exfree(fs);
  178. free(q);
  179. goto Respond;
  180. }
  181. last = &q->next;
  182. }
  183. unlock(&exq.l);
  184. /* in progress? */
  185. lock(&fs->r);
  186. for(q = fs->work; q != nil; q = q->next){
  187. if(q->rpc.tag == tag){
  188. lock(&q->lk);
  189. q->noresponse = 1;
  190. if(!q->responding)
  191. rendintr(q->slave);
  192. unlock(&q->lk);
  193. break;
  194. }
  195. }
  196. unlock(&fs->r);
  197. Respond:
  198. fc.type = Rflush;
  199. fc.tag = flushtag;
  200. n = convS2M(&fc, buf, Maxrpc);
  201. if(n == 0)
  202. panic("convS2M error on write");
  203. if(write(fs->io, buf, n) != n)
  204. panic("mount write");
  205. }
  206. static void
  207. exshutdown(Export *fs)
  208. {
  209. Exq *q, **last;
  210. lock(&exq.l);
  211. last = &exq.head;
  212. for(q = exq.head; q != nil; q = *last){
  213. if(q->export == fs){
  214. *last = q->next;
  215. exfree(fs);
  216. free(q);
  217. continue;
  218. }
  219. last = &q->next;
  220. }
  221. /*
  222. * cleanly shut down the slaves if this is the last fs around
  223. */
  224. exq.ref--;
  225. if(!exq.ref)
  226. rendwakeup(&exq.rwait);
  227. unlock(&exq.l);
  228. /*
  229. * kick any sleepers
  230. */
  231. lock(&fs->r);
  232. for(q = fs->work; q != nil; q = q->next){
  233. lock(&q->lk);
  234. q->noresponse = 1;
  235. if(!q->responding)
  236. rendintr(q->slave);
  237. unlock(&q->lk);
  238. }
  239. unlock(&fs->r);
  240. }
  241. static void
  242. exfree(Export *fs)
  243. {
  244. Fid *f, *n;
  245. int i;
  246. if(decref(&fs->r) != 0)
  247. return;
  248. for(i = 0; i < Nfidhash; i++){
  249. for(f = fs->fid[i]; f != nil; f = n){
  250. if(f->chan != nil)
  251. cclose(f->chan);
  252. n = f->next;
  253. free(f);
  254. }
  255. }
  256. free(fs);
  257. }
  258. static int
  259. exwork(void *)
  260. {
  261. int work;
  262. lock(&exq.l);
  263. work = exq.head != nil || !exq.ref;
  264. unlock(&exq.l);
  265. return work;
  266. }
  267. static void
  268. exslave(void *)
  269. {
  270. Export *fs;
  271. Exq *q, *t, **last;
  272. char *volatile err;
  273. int n, ed;
  274. while(waserror())
  275. fprint(2, "exslave %d errored out of loop -- heading back in!\n", getpid());
  276. ed = errdepth(-1);
  277. for(;;){
  278. errdepth(ed);
  279. qlock(&exq.qwait);
  280. if(waserror()){
  281. qunlock(&exq.qwait);
  282. nexterror();
  283. }
  284. rendsleep(&exq.rwait, exwork, nil);
  285. lock(&exq.l);
  286. if(!exq.ref){
  287. unlock(&exq.l);
  288. poperror();
  289. qunlock(&exq.qwait);
  290. break;
  291. }
  292. q = exq.head;
  293. if(q == nil){
  294. unlock(&exq.l);
  295. poperror();
  296. qunlock(&exq.qwait);
  297. continue;
  298. }
  299. exq.head = q->next;
  300. if(exq.head == nil)
  301. exq.tail = nil;
  302. poperror();
  303. qunlock(&exq.qwait);
  304. /*
  305. * put the job on the work queue before it's
  306. * visible as off of the head queue, so it's always
  307. * findable for flushes and shutdown
  308. */
  309. q->slave = up;
  310. q->noresponse = 0;
  311. q->responding = 0;
  312. rendclearintr();
  313. fs = q->export;
  314. lock(&fs->r);
  315. q->next = fs->work;
  316. fs->work = q;
  317. unlock(&fs->r);
  318. unlock(&exq.l);
  319. if(exdebug > 1)
  320. print("exslave dispatch %d %F\n", getpid(), &q->rpc);
  321. if(waserror()){
  322. print("exslave err %r\n");
  323. err = up->error;
  324. }else{
  325. if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
  326. err = "bad fcall type";
  327. else
  328. err = (*fcalls[q->rpc.type])(fs, &q->rpc, &q->buf[IOHDRSZ]);
  329. poperror();
  330. }
  331. q->rpc.type++;
  332. if(err){
  333. q->rpc.type = Rerror;
  334. q->rpc.ename = err;
  335. }
  336. n = convS2M(&q->rpc, q->buf, Maxrpc);
  337. if(exdebug)
  338. print("exslave %d -> %F\n", getpid(), &q->rpc);
  339. lock(&q->lk);
  340. if(!q->noresponse){
  341. q->responding = 1;
  342. unlock(&q->lk);
  343. write(fs->io, q->buf, n);
  344. }else
  345. unlock(&q->lk);
  346. /*
  347. * exflush might set noresponse at this point, but
  348. * setting noresponse means don't send a response now;
  349. * it's okay that we sent a response already.
  350. */
  351. if(exdebug > 1)
  352. print("exslave %d written %d\n", getpid(), q->rpc.tag);
  353. lock(&fs->r);
  354. last = &fs->work;
  355. for(t = fs->work; t != nil; t = t->next){
  356. if(t == q){
  357. *last = q->next;
  358. break;
  359. }
  360. last = &t->next;
  361. }
  362. unlock(&fs->r);
  363. exfree(q->export);
  364. free(q);
  365. rendclearintr();
  366. lock(&exq.l);
  367. exq.nwaiters++;
  368. unlock(&exq.l);
  369. }
  370. if(exdebug)
  371. fprint(2, "export slaveshutting down\n");
  372. kexit();
  373. }
  374. Fid*
  375. Exmkfid(Export *fs, int fid)
  376. {
  377. ulong h;
  378. Fid *f, *nf;
  379. nf = mallocz(sizeof(Fid), 1);
  380. if(nf == nil)
  381. return nil;
  382. lock(&fs->fidlock);
  383. h = fid % Nfidhash;
  384. for(f = fs->fid[h]; f != nil; f = f->next){
  385. if(f->fid == fid){
  386. unlock(&fs->fidlock);
  387. free(nf);
  388. return nil;
  389. }
  390. }
  391. nf->next = fs->fid[h];
  392. if(nf->next != nil)
  393. nf->next->last = &nf->next;
  394. nf->last = &fs->fid[h];
  395. fs->fid[h] = nf;
  396. nf->fid = fid;
  397. nf->ref = 1;
  398. nf->attached = 1;
  399. nf->offset = 0;
  400. nf->chan = nil;
  401. unlock(&fs->fidlock);
  402. return nf;
  403. }
  404. Fid*
  405. Exgetfid(Export *fs, int fid)
  406. {
  407. Fid *f;
  408. ulong h;
  409. lock(&fs->fidlock);
  410. h = fid % Nfidhash;
  411. for(f = fs->fid[h]; f; f = f->next){
  412. if(f->fid == fid){
  413. if(f->attached == 0)
  414. break;
  415. f->ref++;
  416. unlock(&fs->fidlock);
  417. return f;
  418. }
  419. }
  420. unlock(&fs->fidlock);
  421. return nil;
  422. }
  423. void
  424. Exputfid(Export *fs, Fid *f)
  425. {
  426. lock(&fs->fidlock);
  427. f->ref--;
  428. if(f->ref == 0 && f->attached == 0){
  429. if(f->chan != nil)
  430. cclose(f->chan);
  431. f->chan = nil;
  432. *f->last = f->next;
  433. if(f->next != nil)
  434. f->next->last = f->last;
  435. unlock(&fs->fidlock);
  436. free(f);
  437. return;
  438. }
  439. unlock(&fs->fidlock);
  440. }
  441. static char*
  442. Exversion(Export *fs, Fcall *rpc, uchar *)
  443. {
  444. if(rpc->msize > Maxrpc)
  445. rpc->msize = Maxrpc;
  446. if(strncmp(rpc->version, "9P", 2) != 0){
  447. rpc->version = "unknown";
  448. return nil;
  449. }
  450. fs->iounit = rpc->msize - IOHDRSZ;
  451. rpc->version = "9P2000";
  452. return nil;
  453. }
  454. static char*
  455. Exauth(Export *, Fcall *, uchar *)
  456. {
  457. return "vnc: authentication not required";
  458. }
  459. static char*
  460. Exattach(Export *fs, Fcall *rpc, uchar *)
  461. {
  462. Fid *f;
  463. int w;
  464. w = 0;
  465. if(rpc->aname != nil)
  466. w = strtol(rpc->aname, nil, 10);
  467. if(w < 0 || w > fs->nroots)
  468. error(Ebadspec);
  469. f = Exmkfid(fs, rpc->fid);
  470. if(f == nil)
  471. return Einuse;
  472. if(waserror()){
  473. f->attached = 0;
  474. Exputfid(fs, f);
  475. return up->error;
  476. }
  477. f->chan = cclone(fs->roots[w]);
  478. poperror();
  479. rpc->qid = f->chan->qid;
  480. Exputfid(fs, f);
  481. return nil;
  482. }
  483. static char*
  484. Exclunk(Export *fs, Fcall *rpc, uchar *)
  485. {
  486. Fid *f;
  487. f = Exgetfid(fs, rpc->fid);
  488. if(f != nil){
  489. f->attached = 0;
  490. Exputfid(fs, f);
  491. }
  492. return nil;
  493. }
  494. static char*
  495. Exwalk(Export *fs, Fcall *rpc, uchar *)
  496. {
  497. Fid *volatile f, *volatile nf;
  498. Walkqid *wq;
  499. Chan *c;
  500. int i, nwname;
  501. int volatile isnew;
  502. f = Exgetfid(fs, rpc->fid);
  503. if(f == nil)
  504. return Enofid;
  505. nf = nil;
  506. if(waserror()){
  507. Exputfid(fs, f);
  508. if(nf != nil)
  509. Exputfid(fs, nf);
  510. return up->error;
  511. }
  512. /*
  513. * optional clone, but don't attach it until the walk succeeds.
  514. */
  515. if(rpc->fid != rpc->newfid){
  516. nf = Exmkfid(fs, rpc->newfid);
  517. if(nf == nil)
  518. error(Einuse);
  519. nf->attached = 0;
  520. isnew = 1;
  521. }else{
  522. nf = Exgetfid(fs, rpc->fid);
  523. isnew = 0;
  524. }
  525. /*
  526. * let the device do the work
  527. */
  528. c = f->chan;
  529. nwname = rpc->nwname;
  530. wq = (*devtab[c->type]->walk)(c, nf->chan, rpc->wname, nwname);
  531. if(wq == nil)
  532. error(Enonexist);
  533. poperror();
  534. /*
  535. * copy qid array
  536. */
  537. for(i = 0; i < wq->nqid; i++)
  538. rpc->wqid[i] = wq->qid[i];
  539. rpc->nwqid = wq->nqid;
  540. /*
  541. * update the channel if everything walked correctly.
  542. */
  543. if(isnew && wq->nqid == nwname){
  544. nf->chan = wq->clone;
  545. nf->attached = 1;
  546. }
  547. free(wq);
  548. Exputfid(fs, f);
  549. Exputfid(fs, nf);
  550. return nil;
  551. }
  552. static char*
  553. Exopen(Export *fs, Fcall *rpc, uchar *)
  554. {
  555. Fid *volatile f;
  556. Chan *c;
  557. int iou;
  558. f = Exgetfid(fs, rpc->fid);
  559. if(f == nil)
  560. return Enofid;
  561. if(waserror()){
  562. Exputfid(fs, f);
  563. return up->error;
  564. }
  565. c = f->chan;
  566. c = (*devtab[c->type]->open)(c, rpc->mode);
  567. poperror();
  568. f->chan = c;
  569. f->offset = 0;
  570. rpc->qid = f->chan->qid;
  571. iou = f->chan->iounit;
  572. if(iou > fs->iounit)
  573. iou = fs->iounit;
  574. rpc->iounit = iou;
  575. Exputfid(fs, f);
  576. return nil;
  577. }
  578. static char*
  579. Excreate(Export *fs, Fcall *rpc, uchar *)
  580. {
  581. Fid *f;
  582. Chan *c;
  583. int iou;
  584. f = Exgetfid(fs, rpc->fid);
  585. if(f == nil)
  586. return Enofid;
  587. if(waserror()){
  588. Exputfid(fs, f);
  589. return up->error;
  590. }
  591. c = f->chan;
  592. (*devtab[c->type]->create)(c, rpc->name, rpc->mode, rpc->perm);
  593. poperror();
  594. f->chan = c;
  595. rpc->qid = f->chan->qid;
  596. iou = f->chan->iounit;
  597. if(iou > fs->iounit)
  598. iou = fs->iounit;
  599. rpc->iounit = iou;
  600. Exputfid(fs, f);
  601. return nil;
  602. }
  603. static char*
  604. Exread(Export *fs, Fcall *rpc, uchar *buf)
  605. {
  606. Fid *f;
  607. Chan *c;
  608. long off;
  609. f = Exgetfid(fs, rpc->fid);
  610. if(f == nil)
  611. return Enofid;
  612. c = f->chan;
  613. if(waserror()){
  614. Exputfid(fs, f);
  615. return up->error;
  616. }
  617. rpc->data = (char*)buf;
  618. off = rpc->offset;
  619. c->offset = off;
  620. rpc->count = (*devtab[c->type]->read)(c, rpc->data, rpc->count, off);
  621. poperror();
  622. Exputfid(fs, f);
  623. return nil;
  624. }
  625. static char*
  626. Exwrite(Export *fs, Fcall *rpc, uchar *)
  627. {
  628. Fid *f;
  629. Chan *c;
  630. f = Exgetfid(fs, rpc->fid);
  631. if(f == nil)
  632. return Enofid;
  633. if(waserror()){
  634. Exputfid(fs, f);
  635. return up->error;
  636. }
  637. c = f->chan;
  638. if(c->qid.type & QTDIR)
  639. error(Eisdir);
  640. rpc->count = (*devtab[c->type]->write)(c, rpc->data, rpc->count, rpc->offset);
  641. poperror();
  642. Exputfid(fs, f);
  643. return nil;
  644. }
  645. static char*
  646. Exstat(Export *fs, Fcall *rpc, uchar *buf)
  647. {
  648. Fid *f;
  649. Chan *c;
  650. f = Exgetfid(fs, rpc->fid);
  651. if(f == nil)
  652. return Enofid;
  653. if(waserror()){
  654. Exputfid(fs, f);
  655. return up->error;
  656. }
  657. c = f->chan;
  658. rpc->stat = buf;
  659. rpc->nstat = (*devtab[c->type]->stat)(c, rpc->stat, Maxrpc);
  660. poperror();
  661. Exputfid(fs, f);
  662. return nil;
  663. }
  664. static char*
  665. Exwstat(Export *fs, Fcall *rpc, uchar *)
  666. {
  667. Fid *f;
  668. Chan *c;
  669. f = Exgetfid(fs, rpc->fid);
  670. if(f == nil)
  671. return Enofid;
  672. if(waserror()){
  673. Exputfid(fs, f);
  674. return up->error;
  675. }
  676. c = f->chan;
  677. (*devtab[c->type]->wstat)(c, rpc->stat, rpc->nstat);
  678. poperror();
  679. Exputfid(fs, f);
  680. return nil;
  681. }
  682. static char*
  683. Exremove(Export *fs, Fcall *rpc, uchar *)
  684. {
  685. Fid *f;
  686. Chan *c;
  687. f = Exgetfid(fs, rpc->fid);
  688. if(f == nil)
  689. return Enofid;
  690. if(waserror()){
  691. Exputfid(fs, f);
  692. return up->error;
  693. }
  694. c = f->chan;
  695. (*devtab[c->type]->remove)(c);
  696. poperror();
  697. /*
  698. * chan is already clunked by remove.
  699. * however, we need to recover the chan,
  700. * and follow sysremove's lead in making to point to root.
  701. */
  702. c->type = 0;
  703. f->attached = 0;
  704. Exputfid(fs, f);
  705. return nil;
  706. }