exportfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  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 = 1,
  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. ed = errdepth(-1);
  275. for(;;){
  276. errdepth(ed);
  277. qlock(&exq.qwait);
  278. if(waserror()){
  279. qunlock(&exq.qwait);
  280. nexterror();
  281. }
  282. rendsleep(&exq.rwait, exwork, nil);
  283. lock(&exq.l);
  284. if(!exq.ref){
  285. unlock(&exq.l);
  286. poperror();
  287. qunlock(&exq.qwait);
  288. break;
  289. }
  290. q = exq.head;
  291. if(q == nil){
  292. unlock(&exq.l);
  293. poperror();
  294. qunlock(&exq.qwait);
  295. continue;
  296. }
  297. exq.head = q->next;
  298. if(exq.head == nil)
  299. exq.tail = nil;
  300. poperror();
  301. qunlock(&exq.qwait);
  302. /*
  303. * put the job on the work queue before it's
  304. * visible as off of the head queue, so it's always
  305. * findable for flushes and shutdown
  306. */
  307. q->slave = up;
  308. q->noresponse = 0;
  309. q->responding = 0;
  310. rendclearintr();
  311. fs = q->export;
  312. lock(&fs->r);
  313. q->next = fs->work;
  314. fs->work = q;
  315. unlock(&fs->r);
  316. unlock(&exq.l);
  317. if(exdebug > 1)
  318. print("exslave dispatch %d %F\n", getpid(), &q->rpc);
  319. if(waserror()){
  320. print("exslave err %r\n");
  321. err = up->error;
  322. }else{
  323. if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
  324. err = "bad fcall type";
  325. else
  326. err = (*fcalls[q->rpc.type])(fs, &q->rpc, &q->buf[IOHDRSZ]);
  327. poperror();
  328. }
  329. q->rpc.type++;
  330. if(err){
  331. q->rpc.type = Rerror;
  332. q->rpc.ename = err;
  333. }
  334. n = convS2M(&q->rpc, q->buf, Maxrpc);
  335. if(exdebug)
  336. print("exslave %d -> %F\n", getpid(), &q->rpc);
  337. lock(&q->lk);
  338. if(!q->noresponse){
  339. q->responding = 1;
  340. unlock(&q->lk);
  341. write(fs->io, q->buf, n);
  342. }else
  343. unlock(&q->lk);
  344. /*
  345. * exflush might set noresponse at this point, but
  346. * setting noresponse means don't send a response now;
  347. * it's okay that we sent a response already.
  348. */
  349. if(exdebug > 1)
  350. print("exslave %d written %d\n", getpid(), q->rpc.tag);
  351. lock(&fs->r);
  352. last = &fs->work;
  353. for(t = fs->work; t != nil; t = t->next){
  354. if(t == q){
  355. *last = q->next;
  356. break;
  357. }
  358. last = &t->next;
  359. }
  360. unlock(&fs->r);
  361. exfree(q->export);
  362. free(q);
  363. lock(&exq.l);
  364. exq.nwaiters++;
  365. unlock(&exq.l);
  366. }
  367. if(exdebug)
  368. fprint(2, "export slaveshutting down\n");
  369. kexit();
  370. }
  371. Fid*
  372. Exmkfid(Export *fs, int fid)
  373. {
  374. ulong h;
  375. Fid *f, *nf;
  376. nf = mallocz(sizeof(Fid), 1);
  377. if(nf == nil)
  378. return nil;
  379. lock(&fs->fidlock);
  380. h = fid % Nfidhash;
  381. for(f = fs->fid[h]; f != nil; f = f->next){
  382. if(f->fid == fid){
  383. unlock(&fs->fidlock);
  384. free(nf);
  385. return nil;
  386. }
  387. }
  388. nf->next = fs->fid[h];
  389. if(nf->next != nil)
  390. nf->next->last = &nf->next;
  391. nf->last = &fs->fid[h];
  392. fs->fid[h] = nf;
  393. nf->fid = fid;
  394. nf->ref = 1;
  395. nf->attached = 1;
  396. nf->offset = 0;
  397. nf->chan = nil;
  398. unlock(&fs->fidlock);
  399. return nf;
  400. }
  401. Fid*
  402. Exgetfid(Export *fs, int fid)
  403. {
  404. Fid *f;
  405. ulong h;
  406. lock(&fs->fidlock);
  407. h = fid % Nfidhash;
  408. for(f = fs->fid[h]; f; f = f->next){
  409. if(f->fid == fid){
  410. if(f->attached == 0)
  411. break;
  412. f->ref++;
  413. unlock(&fs->fidlock);
  414. return f;
  415. }
  416. }
  417. unlock(&fs->fidlock);
  418. return nil;
  419. }
  420. void
  421. Exputfid(Export *fs, Fid *f)
  422. {
  423. lock(&fs->fidlock);
  424. f->ref--;
  425. if(f->ref == 0 && f->attached == 0){
  426. if(f->chan != nil)
  427. cclose(f->chan);
  428. f->chan = nil;
  429. *f->last = f->next;
  430. if(f->next != nil)
  431. f->next->last = f->last;
  432. unlock(&fs->fidlock);
  433. free(f);
  434. return;
  435. }
  436. unlock(&fs->fidlock);
  437. }
  438. static char*
  439. Exversion(Export *fs, Fcall *rpc, uchar *)
  440. {
  441. if(rpc->msize > Maxrpc)
  442. rpc->msize = Maxrpc;
  443. if(strncmp(rpc->version, "9P", 2) != 0){
  444. rpc->version = "unknown";
  445. return nil;
  446. }
  447. fs->iounit = rpc->msize - IOHDRSZ;
  448. rpc->version = "9P2000";
  449. return nil;
  450. }
  451. static char*
  452. Exauth(Export *, Fcall *, uchar *)
  453. {
  454. return "vnc: authentication not required";
  455. }
  456. static char*
  457. Exattach(Export *fs, Fcall *rpc, uchar *)
  458. {
  459. Fid *f;
  460. int w;
  461. w = 0;
  462. if(rpc->aname != nil)
  463. w = strtol(rpc->aname, nil, 10);
  464. if(w < 0 || w > fs->nroots)
  465. error(Ebadspec);
  466. f = Exmkfid(fs, rpc->fid);
  467. if(f == nil)
  468. return Einuse;
  469. if(waserror()){
  470. f->attached = 0;
  471. Exputfid(fs, f);
  472. return up->error;
  473. }
  474. f->chan = cclone(fs->roots[w]);
  475. poperror();
  476. rpc->qid = f->chan->qid;
  477. Exputfid(fs, f);
  478. return nil;
  479. }
  480. static char*
  481. Exclunk(Export *fs, Fcall *rpc, uchar *)
  482. {
  483. Fid *f;
  484. f = Exgetfid(fs, rpc->fid);
  485. if(f != nil){
  486. f->attached = 0;
  487. Exputfid(fs, f);
  488. }
  489. return nil;
  490. }
  491. static char*
  492. Exwalk(Export *fs, Fcall *rpc, uchar *)
  493. {
  494. Fid *volatile f, *volatile nf;
  495. Walkqid *wq;
  496. Chan *c;
  497. int i, nwname;
  498. int volatile isnew;
  499. f = Exgetfid(fs, rpc->fid);
  500. if(f == nil)
  501. return Enofid;
  502. nf = nil;
  503. if(waserror()){
  504. Exputfid(fs, f);
  505. if(nf != nil)
  506. Exputfid(fs, nf);
  507. return up->error;
  508. }
  509. /*
  510. * optional clone, but don't attach it until the walk succeeds.
  511. */
  512. if(rpc->fid != rpc->newfid){
  513. nf = Exmkfid(fs, rpc->newfid);
  514. if(nf == nil)
  515. error(Einuse);
  516. nf->attached = 0;
  517. isnew = 1;
  518. }else{
  519. nf = Exgetfid(fs, rpc->fid);
  520. isnew = 0;
  521. }
  522. /*
  523. * let the device do the work
  524. */
  525. c = f->chan;
  526. nwname = rpc->nwname;
  527. wq = (*devtab[c->type]->walk)(c, nf->chan, rpc->wname, nwname);
  528. if(wq == nil)
  529. error(Enonexist);
  530. poperror();
  531. /*
  532. * copy qid array
  533. */
  534. for(i = 0; i < wq->nqid; i++)
  535. rpc->wqid[i] = wq->qid[i];
  536. rpc->nwqid = wq->nqid;
  537. /*
  538. * update the channel if everything walked correctly.
  539. */
  540. if(isnew && wq->nqid == nwname){
  541. nf->chan = wq->clone;
  542. nf->attached = 1;
  543. }
  544. free(wq);
  545. Exputfid(fs, f);
  546. Exputfid(fs, nf);
  547. return nil;
  548. }
  549. static char*
  550. Exopen(Export *fs, Fcall *rpc, uchar *)
  551. {
  552. Fid *volatile f;
  553. Chan *c;
  554. int iou;
  555. f = Exgetfid(fs, rpc->fid);
  556. if(f == nil)
  557. return Enofid;
  558. if(waserror()){
  559. Exputfid(fs, f);
  560. return up->error;
  561. }
  562. c = f->chan;
  563. c = (*devtab[c->type]->open)(c, rpc->mode);
  564. poperror();
  565. f->chan = c;
  566. f->offset = 0;
  567. rpc->qid = f->chan->qid;
  568. iou = f->chan->iounit;
  569. if(iou > fs->iounit)
  570. iou = fs->iounit;
  571. rpc->iounit = iou;
  572. Exputfid(fs, f);
  573. return nil;
  574. }
  575. static char*
  576. Excreate(Export *fs, Fcall *rpc, uchar *)
  577. {
  578. Fid *f;
  579. Chan *c;
  580. int iou;
  581. f = Exgetfid(fs, rpc->fid);
  582. if(f == nil)
  583. return Enofid;
  584. if(waserror()){
  585. Exputfid(fs, f);
  586. return up->error;
  587. }
  588. c = f->chan;
  589. (*devtab[c->type]->create)(c, rpc->name, rpc->mode, rpc->perm);
  590. poperror();
  591. f->chan = c;
  592. rpc->qid = f->chan->qid;
  593. iou = f->chan->iounit;
  594. if(iou > fs->iounit)
  595. iou = fs->iounit;
  596. rpc->iounit = iou;
  597. Exputfid(fs, f);
  598. return nil;
  599. }
  600. static char*
  601. Exread(Export *fs, Fcall *rpc, uchar *buf)
  602. {
  603. Fid *f;
  604. Chan *c;
  605. long off;
  606. f = Exgetfid(fs, rpc->fid);
  607. if(f == nil)
  608. return Enofid;
  609. c = f->chan;
  610. if(waserror()){
  611. Exputfid(fs, f);
  612. return up->error;
  613. }
  614. rpc->data = (char*)buf;
  615. off = rpc->offset;
  616. c->offset = off;
  617. rpc->count = (*devtab[c->type]->read)(c, rpc->data, rpc->count, off);
  618. poperror();
  619. Exputfid(fs, f);
  620. return nil;
  621. }
  622. static char*
  623. Exwrite(Export *fs, Fcall *rpc, uchar *)
  624. {
  625. Fid *f;
  626. Chan *c;
  627. f = Exgetfid(fs, rpc->fid);
  628. if(f == nil)
  629. return Enofid;
  630. if(waserror()){
  631. Exputfid(fs, f);
  632. return up->error;
  633. }
  634. c = f->chan;
  635. if(c->qid.type & QTDIR)
  636. error(Eisdir);
  637. rpc->count = (*devtab[c->type]->write)(c, rpc->data, rpc->count, rpc->offset);
  638. poperror();
  639. Exputfid(fs, f);
  640. return nil;
  641. }
  642. static char*
  643. Exstat(Export *fs, Fcall *rpc, uchar *buf)
  644. {
  645. Fid *f;
  646. Chan *c;
  647. f = Exgetfid(fs, rpc->fid);
  648. if(f == nil)
  649. return Enofid;
  650. if(waserror()){
  651. Exputfid(fs, f);
  652. return up->error;
  653. }
  654. c = f->chan;
  655. rpc->stat = buf;
  656. rpc->nstat = (*devtab[c->type]->stat)(c, rpc->stat, Maxrpc);
  657. poperror();
  658. Exputfid(fs, f);
  659. return nil;
  660. }
  661. static char*
  662. Exwstat(Export *fs, Fcall *rpc, uchar *)
  663. {
  664. Fid *f;
  665. Chan *c;
  666. f = Exgetfid(fs, rpc->fid);
  667. if(f == nil)
  668. return Enofid;
  669. if(waserror()){
  670. Exputfid(fs, f);
  671. return up->error;
  672. }
  673. c = f->chan;
  674. (*devtab[c->type]->wstat)(c, rpc->stat, rpc->nstat);
  675. poperror();
  676. Exputfid(fs, f);
  677. return nil;
  678. }
  679. static char*
  680. Exremove(Export *fs, Fcall *rpc, uchar *)
  681. {
  682. Fid *f;
  683. Chan *c;
  684. f = Exgetfid(fs, rpc->fid);
  685. if(f == nil)
  686. return Enofid;
  687. if(waserror()){
  688. Exputfid(fs, f);
  689. return up->error;
  690. }
  691. c = f->chan;
  692. (*devtab[c->type]->remove)(c);
  693. poperror();
  694. /*
  695. * chan is already clunked by remove.
  696. * however, we need to recover the chan,
  697. * and follow sysremove's lead in making to point to root.
  698. */
  699. c->type = 0;
  700. f->attached = 0;
  701. Exputfid(fs, f);
  702. return nil;
  703. }