devmnt.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. #include "dat.h"
  2. #include "fns.h"
  3. #include "error.h"
  4. /*
  5. * References are managed as follows:
  6. * The channel to the server - a network connection or pipe - has one
  7. * reference for every Chan open on the server. The server channel has
  8. * c->mux set to the Mnt used for muxing control to that server. Mnts
  9. * have no reference count; they go away when c goes away.
  10. * Each channel derived from the mount point has mchan set to c,
  11. * and increfs/decrefs mchan to manage references on the server
  12. * connection.
  13. */
  14. #define MAXRPC (IOHDRSZ+8192)
  15. struct Mntrpc
  16. {
  17. Chan* c; /* Channel for whom we are working */
  18. Mntrpc* list; /* Free/pending list */
  19. Fcall request; /* Outgoing file system protocol message */
  20. Fcall reply; /* Incoming reply */
  21. Mnt* m; /* Mount device during rpc */
  22. Rendez r; /* Place to hang out */
  23. uchar* rpc; /* I/O Data buffer */
  24. uint rpclen; /* len of buffer */
  25. Block *b; /* reply blocks */
  26. char done; /* Rpc completed */
  27. uvlong stime; /* start time for mnt statistics */
  28. ulong reqlen; /* request length for mnt statistics */
  29. ulong replen; /* reply length for mnt statistics */
  30. Mntrpc* flushed; /* message this one flushes */
  31. };
  32. enum
  33. {
  34. TAGSHIFT = 5, /* ulong has to be 32 bits */
  35. TAGMASK = (1<<TAGSHIFT)-1,
  36. NMASK = (64*1024)>>TAGSHIFT,
  37. };
  38. struct Mntalloc
  39. {
  40. Lock l;
  41. Mnt* list; /* Mount devices in use */
  42. Mnt* mntfree; /* Free list */
  43. Mntrpc* rpcfree;
  44. int nrpcfree;
  45. int nrpcused;
  46. ulong id;
  47. ulong tagmask[NMASK];
  48. }mntalloc;
  49. void mattach(Mnt*, Chan*, char*);
  50. Mnt* mntchk(Chan*);
  51. void mntdirfix(uchar*, Chan*);
  52. Mntrpc* mntflushalloc(Mntrpc*, ulong);
  53. void mntflushfree(Mnt*, Mntrpc*);
  54. void mntfree(Mntrpc*);
  55. void mntgate(Mnt*);
  56. void mntpntfree(Mnt*);
  57. void mntqrm(Mnt*, Mntrpc*);
  58. Mntrpc* mntralloc(Chan*, ulong);
  59. long mntrdwr(int, Chan*, void*, long, vlong);
  60. int mntrpcread(Mnt*, Mntrpc*);
  61. void mountio(Mnt*, Mntrpc*);
  62. void mountmux(Mnt*, Mntrpc*);
  63. void mountrpc(Mnt*, Mntrpc*);
  64. int rpcattn(void*);
  65. Chan* mntchan(void);
  66. char Esbadstat[] = "invalid directory entry received from server";
  67. char Enoversion[] = "version not established for mount channel";
  68. void (*mntstats)(int, Chan*, uvlong, ulong);
  69. static void
  70. mntinit(void)
  71. {
  72. mntalloc.id = 1;
  73. mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
  74. mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
  75. fmtinstall('F', fcallfmt);
  76. /* fmtinstall('D', dirfmt); */
  77. /* fmtinstall('M', dirmodefmt); */
  78. cinit();
  79. }
  80. /*
  81. * Version is not multiplexed: message sent only once per connection.
  82. */
  83. long
  84. mntversion(Chan *c, char *version, int msize, int returnlen)
  85. {
  86. Fcall f;
  87. uchar *msg;
  88. Mnt *m;
  89. char *v;
  90. long k, l;
  91. uvlong oo;
  92. char buf[128];
  93. qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
  94. if(waserror()){
  95. qunlock(&c->umqlock);
  96. nexterror();
  97. }
  98. /* defaults */
  99. if(msize == 0)
  100. msize = MAXRPC;
  101. if(msize > c->iounit && c->iounit != 0)
  102. msize = c->iounit;
  103. v = version;
  104. if(v == nil || v[0] == '\0')
  105. v = VERSION9P;
  106. /* validity */
  107. if(msize < 0)
  108. error("bad iounit in version call");
  109. if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
  110. error("bad 9P version specification");
  111. m = c->mux;
  112. if(m != nil){
  113. qunlock(&c->umqlock);
  114. poperror();
  115. strecpy(buf, buf+sizeof buf, m->version);
  116. k = strlen(buf);
  117. if(strncmp(buf, v, k) != 0){
  118. snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
  119. error(buf);
  120. }
  121. if(returnlen > 0){
  122. if(returnlen < k)
  123. error(Eshort);
  124. memmove(version, buf, k);
  125. }
  126. return k;
  127. }
  128. f.type = Tversion;
  129. f.tag = NOTAG;
  130. f.msize = msize;
  131. f.version = v;
  132. msg = malloc(8192+IOHDRSZ);
  133. if(msg == nil)
  134. exhausted("version memory");
  135. if(waserror()){
  136. free(msg);
  137. nexterror();
  138. }
  139. k = convS2M(&f, msg, 8192+IOHDRSZ);
  140. if(k == 0)
  141. error("bad fversion conversion on send");
  142. lock(&c->l);
  143. oo = c->offset;
  144. c->offset += k;
  145. unlock(&c->l);
  146. l = devtab[c->type]->write(c, msg, k, oo);
  147. if(l < k){
  148. lock(&c->l);
  149. c->offset -= k - l;
  150. unlock(&c->l);
  151. error("short write in fversion");
  152. }
  153. /* message sent; receive and decode reply */
  154. k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
  155. if(k <= 0)
  156. error("EOF receiving fversion reply");
  157. lock(&c->l);
  158. c->offset += k;
  159. unlock(&c->l);
  160. l = convM2S(msg, k, &f);
  161. if(l != k)
  162. error("bad fversion conversion on reply");
  163. if(f.type != Rversion){
  164. if(f.type == Rerror)
  165. error(f.ename);
  166. error("unexpected reply type in fversion");
  167. }
  168. if(f.msize > msize)
  169. error("server tries to increase msize in fversion");
  170. if(f.msize<256 || f.msize>1024*1024)
  171. error("nonsense value of msize in fversion");
  172. if(strncmp(f.version, v, strlen(f.version)) != 0)
  173. error("bad 9P version returned from server");
  174. /* now build Mnt associated with this connection */
  175. lock(&mntalloc.l);
  176. m = mntalloc.mntfree;
  177. if(m != 0)
  178. mntalloc.mntfree = m->list;
  179. else {
  180. m = malloc(sizeof(Mnt));
  181. if(m == 0) {
  182. unlock(&mntalloc.l);
  183. exhausted("mount devices");
  184. }
  185. }
  186. m->list = mntalloc.list;
  187. mntalloc.list = m;
  188. m->version = nil;
  189. kstrdup(&m->version, f.version);
  190. m->id = mntalloc.id++;
  191. m->q = qopen(10*MAXRPC, 0, nil, nil);
  192. m->msize = f.msize;
  193. unlock(&mntalloc.l);
  194. poperror(); /* msg */
  195. free(msg);
  196. lock(&m->l);
  197. m->queue = 0;
  198. m->rip = 0;
  199. c->flag |= CMSG;
  200. c->mux = m;
  201. m->c = c;
  202. unlock(&m->l);
  203. poperror(); /* c */
  204. qunlock(&c->umqlock);
  205. k = strlen(f.version);
  206. if(returnlen > 0){
  207. if(returnlen < k)
  208. error(Eshort);
  209. memmove(version, f.version, k);
  210. }
  211. return k;
  212. }
  213. Chan*
  214. mntauth(Chan *c, char *spec)
  215. {
  216. Mnt *m;
  217. Mntrpc *r;
  218. m = c->mux;
  219. if(m == nil){
  220. mntversion(c, VERSION9P, MAXRPC, 0);
  221. m = c->mux;
  222. if(m == nil)
  223. error(Enoversion);
  224. }
  225. c = mntchan();
  226. if(waserror()) {
  227. /* Close must not be called since it will
  228. * call mnt recursively
  229. */
  230. chanfree(c);
  231. nexterror();
  232. }
  233. r = mntralloc(0, m->msize);
  234. if(waserror()) {
  235. mntfree(r);
  236. nexterror();
  237. }
  238. r->request.type = Tauth;
  239. r->request.afid = c->fid;
  240. r->request.uname = up->env->user;
  241. r->request.aname = spec;
  242. mountrpc(m, r);
  243. c->qid = r->reply.aqid;
  244. c->mchan = m->c;
  245. incref(&m->c->r);
  246. c->mqid = c->qid;
  247. c->mode = ORDWR;
  248. poperror(); /* r */
  249. mntfree(r);
  250. poperror(); /* c */
  251. return c;
  252. }
  253. static Chan*
  254. mntattach(char *muxattach)
  255. {
  256. Mnt *m;
  257. Chan *c;
  258. Mntrpc *r;
  259. struct bogus{
  260. Chan *chan;
  261. Chan *authchan;
  262. char *spec;
  263. int flags;
  264. }bogus;
  265. bogus = *((struct bogus *)muxattach);
  266. c = bogus.chan;
  267. m = c->mux;
  268. if(m == nil){
  269. mntversion(c, nil, 0, 0);
  270. m = c->mux;
  271. if(m == nil)
  272. error(Enoversion);
  273. }
  274. c = mntchan();
  275. if(waserror()) {
  276. /* Close must not be called since it will
  277. * call mnt recursively
  278. */
  279. chanfree(c);
  280. nexterror();
  281. }
  282. r = mntralloc(0, m->msize);
  283. if(waserror()) {
  284. mntfree(r);
  285. nexterror();
  286. }
  287. r->request.type = Tattach;
  288. r->request.fid = c->fid;
  289. if(bogus.authchan == nil)
  290. r->request.afid = NOFID;
  291. else
  292. r->request.afid = bogus.authchan->fid;
  293. r->request.uname = up->env->user;
  294. r->request.aname = bogus.spec;
  295. mountrpc(m, r);
  296. c->qid = r->reply.qid;
  297. c->mchan = m->c;
  298. incref(&m->c->r);
  299. c->mqid = c->qid;
  300. poperror(); /* r */
  301. mntfree(r);
  302. poperror(); /* c */
  303. if(bogus.flags&MCACHE)
  304. c->flag |= CCACHE;
  305. return c;
  306. }
  307. Chan*
  308. mntchan(void)
  309. {
  310. Chan *c;
  311. c = devattach('M', 0);
  312. lock(&mntalloc.l);
  313. c->dev = mntalloc.id++;
  314. unlock(&mntalloc.l);
  315. if(c->mchan)
  316. panic("mntchan non-zero %p", c->mchan);
  317. return c;
  318. }
  319. static Walkqid*
  320. mntwalk(Chan *c, Chan *nc, char **name, int nname)
  321. {
  322. volatile int alloc;
  323. int i;
  324. Mnt *m;
  325. Mntrpc *r;
  326. Walkqid *wq;
  327. if(nc != nil)
  328. print("mntwalk: nc != nil\n");
  329. if(nname > MAXWELEM)
  330. error("devmnt: too many name elements");
  331. alloc = 0;
  332. wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
  333. if(waserror()){
  334. if(alloc && wq->clone!=nil)
  335. cclose(wq->clone);
  336. free(wq);
  337. return nil;
  338. }
  339. alloc = 0;
  340. m = mntchk(c);
  341. r = mntralloc(c, m->msize);
  342. if(nc == nil){
  343. nc = devclone(c);
  344. /*
  345. * Until the other side accepts this fid, we can't mntclose it.
  346. * Therefore set type to 0 for now; rootclose is known to be safe.
  347. */
  348. nc->type = 0;
  349. alloc = 1;
  350. }
  351. wq->clone = nc;
  352. if(waserror()) {
  353. mntfree(r);
  354. nexterror();
  355. }
  356. r->request.type = Twalk;
  357. r->request.fid = c->fid;
  358. r->request.newfid = nc->fid;
  359. r->request.nwname = nname;
  360. memmove(r->request.wname, name, nname*sizeof(char*));
  361. mountrpc(m, r);
  362. if(r->reply.nwqid > nname)
  363. error("too many QIDs returned by walk");
  364. if(r->reply.nwqid < nname){
  365. if(alloc)
  366. cclose(nc);
  367. wq->clone = nil;
  368. if(r->reply.nwqid == 0){
  369. free(wq);
  370. wq = nil;
  371. goto Return;
  372. }
  373. }
  374. /* move new fid onto mnt device and update its qid */
  375. if(wq->clone != nil){
  376. if(wq->clone != c){
  377. wq->clone->type = c->type;
  378. wq->clone->mchan = c->mchan;
  379. incref(&c->mchan->r);
  380. }
  381. if(r->reply.nwqid > 0)
  382. wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
  383. }
  384. wq->nqid = r->reply.nwqid;
  385. for(i=0; i<wq->nqid; i++)
  386. wq->qid[i] = r->reply.wqid[i];
  387. Return:
  388. poperror();
  389. mntfree(r);
  390. poperror();
  391. return wq;
  392. }
  393. static int
  394. mntstat(Chan *c, uchar *dp, int n)
  395. {
  396. Mnt *m;
  397. Mntrpc *r;
  398. if(n < BIT16SZ)
  399. error(Eshortstat);
  400. m = mntchk(c);
  401. r = mntralloc(c, m->msize);
  402. if(waserror()) {
  403. mntfree(r);
  404. nexterror();
  405. }
  406. r->request.type = Tstat;
  407. r->request.fid = c->fid;
  408. mountrpc(m, r);
  409. if(r->reply.nstat > n){
  410. /* doesn't fit; just patch the count and return */
  411. PBIT16((uchar*)dp, r->reply.nstat);
  412. n = BIT16SZ;
  413. }else{
  414. n = r->reply.nstat;
  415. memmove(dp, r->reply.stat, n);
  416. validstat(dp, n);
  417. mntdirfix(dp, c);
  418. }
  419. poperror();
  420. mntfree(r);
  421. return n;
  422. }
  423. static Chan*
  424. mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
  425. {
  426. Mnt *m;
  427. Mntrpc *r;
  428. m = mntchk(c);
  429. r = mntralloc(c, m->msize);
  430. if(waserror()) {
  431. mntfree(r);
  432. nexterror();
  433. }
  434. r->request.type = type;
  435. r->request.fid = c->fid;
  436. r->request.mode = omode;
  437. if(type == Tcreate){
  438. r->request.perm = perm;
  439. r->request.name = name;
  440. }
  441. mountrpc(m, r);
  442. c->qid = r->reply.qid;
  443. c->offset = 0;
  444. c->mode = openmode(omode);
  445. c->iounit = r->reply.iounit;
  446. if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
  447. c->iounit = m->msize-IOHDRSZ;
  448. c->flag |= COPEN;
  449. poperror();
  450. mntfree(r);
  451. if(c->flag & CCACHE)
  452. copen(c);
  453. return c;
  454. }
  455. static Chan*
  456. mntopen(Chan *c, int omode)
  457. {
  458. return mntopencreate(Topen, c, nil, omode, 0);
  459. }
  460. static void
  461. mntcreate(Chan *c, char *name, int omode, ulong perm)
  462. {
  463. mntopencreate(Tcreate, c, name, omode, perm);
  464. }
  465. static void
  466. mntclunk(Chan *c, int t)
  467. {
  468. Mnt *m;
  469. Mntrpc *r;
  470. m = mntchk(c);
  471. r = mntralloc(c, m->msize);
  472. if(waserror()){
  473. mntfree(r);
  474. nexterror();
  475. }
  476. r->request.type = t;
  477. r->request.fid = c->fid;
  478. mountrpc(m, r);
  479. mntfree(r);
  480. poperror();
  481. }
  482. void
  483. muxclose(Mnt *m)
  484. {
  485. Mntrpc *q, *r;
  486. for(q = m->queue; q; q = r) {
  487. r = q->list;
  488. mntfree(q);
  489. }
  490. m->id = 0;
  491. free(m->version);
  492. m->version = nil;
  493. mntpntfree(m);
  494. }
  495. void
  496. mntpntfree(Mnt *m)
  497. {
  498. Mnt *f, **l;
  499. Queue *q;
  500. lock(&mntalloc.l);
  501. l = &mntalloc.list;
  502. for(f = *l; f; f = f->list) {
  503. if(f == m) {
  504. *l = m->list;
  505. break;
  506. }
  507. l = &f->list;
  508. }
  509. m->list = mntalloc.mntfree;
  510. mntalloc.mntfree = m;
  511. q = m->q;
  512. unlock(&mntalloc.l);
  513. qfree(q);
  514. }
  515. static void
  516. mntclose(Chan *c)
  517. {
  518. mntclunk(c, Tclunk);
  519. }
  520. static void
  521. mntremove(Chan *c)
  522. {
  523. mntclunk(c, Tremove);
  524. }
  525. static int
  526. mntwstat(Chan *c, uchar *dp, int n)
  527. {
  528. Mnt *m;
  529. Mntrpc *r;
  530. m = mntchk(c);
  531. r = mntralloc(c, m->msize);
  532. if(waserror()) {
  533. mntfree(r);
  534. nexterror();
  535. }
  536. r->request.type = Twstat;
  537. r->request.fid = c->fid;
  538. r->request.nstat = n;
  539. r->request.stat = dp;
  540. mountrpc(m, r);
  541. poperror();
  542. mntfree(r);
  543. return n;
  544. }
  545. static long
  546. mntread(Chan *c, void *buf, long n, vlong off)
  547. {
  548. uchar *p, *e;
  549. int nc, cache, isdir, dirlen;
  550. isdir = 0;
  551. cache = c->flag & CCACHE;
  552. if(c->qid.type & QTDIR) {
  553. cache = 0;
  554. isdir = 1;
  555. }
  556. p = buf;
  557. if(cache) {
  558. nc = cread(c, buf, n, off);
  559. if(nc > 0) {
  560. n -= nc;
  561. if(n == 0)
  562. return nc;
  563. p += nc;
  564. off += nc;
  565. }
  566. n = mntrdwr(Tread, c, p, n, off);
  567. cupdate(c, p, n, off);
  568. return n + nc;
  569. }
  570. n = mntrdwr(Tread, c, buf, n, off);
  571. if(isdir) {
  572. for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
  573. dirlen = BIT16SZ+GBIT16(p);
  574. if(p+dirlen > e)
  575. break;
  576. validstat(p, dirlen);
  577. mntdirfix(p, c);
  578. }
  579. if(p != e)
  580. error(Esbadstat);
  581. }
  582. return n;
  583. }
  584. static long
  585. mntwrite(Chan *c, void *buf, long n, vlong off)
  586. {
  587. return mntrdwr(Twrite, c, buf, n, off);
  588. }
  589. long
  590. mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
  591. {
  592. Mnt *m;
  593. Mntrpc *r; /* TO DO: volatile struct { Mntrpc *r; } r; */
  594. char *uba;
  595. int cache;
  596. ulong cnt, nr, nreq;
  597. m = mntchk(c);
  598. uba = buf;
  599. cnt = 0;
  600. cache = c->flag & CCACHE;
  601. if(c->qid.type & QTDIR)
  602. cache = 0;
  603. for(;;) {
  604. r = mntralloc(c, m->msize);
  605. if(waserror()) {
  606. mntfree(r);
  607. nexterror();
  608. }
  609. r->request.type = type;
  610. r->request.fid = c->fid;
  611. r->request.offset = off;
  612. r->request.data = uba;
  613. nr = n;
  614. if(nr > m->msize-IOHDRSZ)
  615. nr = m->msize-IOHDRSZ;
  616. r->request.count = nr;
  617. mountrpc(m, r);
  618. nreq = r->request.count;
  619. nr = r->reply.count;
  620. if(nr > nreq)
  621. nr = nreq;
  622. if(type == Tread)
  623. r->b = bl2mem((uchar*)uba, r->b, nr);
  624. else if(cache)
  625. cwrite(c, (uchar*)uba, nr, off);
  626. poperror();
  627. mntfree(r);
  628. off += nr;
  629. uba += nr;
  630. cnt += nr;
  631. n -= nr;
  632. if(nr != nreq || n == 0 || up->killed)
  633. break;
  634. }
  635. return cnt;
  636. }
  637. void
  638. mountrpc(Mnt *m, Mntrpc *r)
  639. {
  640. char *sn, *cn;
  641. int t;
  642. r->reply.tag = 0;
  643. r->reply.type = Tmax; /* can't ever be a valid message type */
  644. mountio(m, r);
  645. t = r->reply.type;
  646. switch(t) {
  647. case Rerror:
  648. error(r->reply.ename);
  649. case Rflush:
  650. error(Eintr);
  651. default:
  652. if(t == r->request.type+1)
  653. break;
  654. sn = "?";
  655. if(m->c->name != nil)
  656. sn = m->c->name->s;
  657. cn = "?";
  658. if(r->c != nil && r->c->name != nil)
  659. cn = r->c->name->s;
  660. print("mnt: proc %s %lud: mismatch from %s %s rep 0x%p tag %d fid %d T%d R%d rp %d\n",
  661. up->text, up->pid, sn, cn,
  662. r, r->request.tag, r->request.fid, r->request.type,
  663. r->reply.type, r->reply.tag);
  664. error(Emountrpc);
  665. }
  666. }
  667. void
  668. mountio(Mnt *m, Mntrpc *r)
  669. {
  670. int n;
  671. while(waserror()) {
  672. if(m->rip == up)
  673. mntgate(m);
  674. if(strcmp(up->env->errstr, Eintr) != 0){
  675. mntflushfree(m, r);
  676. nexterror();
  677. }
  678. r = mntflushalloc(r, m->msize);
  679. }
  680. lock(&m->l);
  681. r->m = m;
  682. r->list = m->queue;
  683. m->queue = r;
  684. unlock(&m->l);
  685. /* Transmit a file system rpc */
  686. if(m->msize == 0)
  687. panic("msize");
  688. n = convS2M(&r->request, r->rpc, m->msize);
  689. if(n < 0)
  690. panic("bad message type in mountio");
  691. if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
  692. error(Emountrpc);
  693. /* r->stime = fastticks(nil); */
  694. r->reqlen = n;
  695. /* Gate readers onto the mount point one at a time */
  696. for(;;) {
  697. lock(&m->l);
  698. if(m->rip == 0)
  699. break;
  700. unlock(&m->l);
  701. Sleep(&r->r, rpcattn, r);
  702. if(r->done){
  703. poperror();
  704. mntflushfree(m, r);
  705. return;
  706. }
  707. }
  708. m->rip = up;
  709. unlock(&m->l);
  710. while(r->done == 0) {
  711. if(mntrpcread(m, r) < 0)
  712. error(Emountrpc);
  713. mountmux(m, r);
  714. }
  715. mntgate(m);
  716. poperror();
  717. mntflushfree(m, r);
  718. }
  719. static int
  720. doread(Mnt *m, int len)
  721. {
  722. Block *b;
  723. while(qlen(m->q) < len){
  724. b = devtab[m->c->type]->bread(m->c, m->msize, 0);
  725. if(b == nil)
  726. return -1;
  727. if(blocklen(b) == 0){
  728. freeblist(b);
  729. return -1;
  730. }
  731. qaddlist(m->q, b);
  732. }
  733. return 0;
  734. }
  735. int
  736. mntrpcread(Mnt *m, Mntrpc *r)
  737. {
  738. int i, t, len, hlen;
  739. Block *b, **l, *nb;
  740. r->reply.type = 0;
  741. r->reply.tag = 0;
  742. /* read at least length, type, and tag and pullup to a single block */
  743. if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
  744. return -1;
  745. nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
  746. /* read in the rest of the message, avoid ridiculous (for now) message sizes */
  747. len = GBIT32(nb->rp);
  748. if(len > m->msize){
  749. qdiscard(m->q, qlen(m->q));
  750. return -1;
  751. }
  752. if(doread(m, len) < 0)
  753. return -1;
  754. /* pullup the header (i.e. everything except data) */
  755. t = nb->rp[BIT32SZ];
  756. switch(t){
  757. case Rread:
  758. hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
  759. break;
  760. default:
  761. hlen = len;
  762. break;
  763. }
  764. nb = pullupqueue(m->q, hlen);
  765. if(convM2S(nb->rp, len, &r->reply) <= 0){
  766. /* bad message, dump it */
  767. print("mntrpcread: convM2S failed\n");
  768. qdiscard(m->q, len);
  769. return -1;
  770. }
  771. /* hang the data off of the fcall struct */
  772. l = &r->b;
  773. *l = nil;
  774. do {
  775. b = qremove(m->q);
  776. if(hlen > 0){
  777. b->rp += hlen;
  778. len -= hlen;
  779. hlen = 0;
  780. }
  781. i = BLEN(b);
  782. if(i <= len){
  783. len -= i;
  784. *l = b;
  785. l = &(b->next);
  786. } else {
  787. /* split block and put unused bit back */
  788. nb = allocb(i-len);
  789. memmove(nb->wp, b->rp+len, i-len);
  790. b->wp = b->rp+len;
  791. nb->wp += i-len;
  792. qputback(m->q, nb);
  793. *l = b;
  794. return 0;
  795. }
  796. }while(len > 0);
  797. return 0;
  798. }
  799. void
  800. mntgate(Mnt *m)
  801. {
  802. Mntrpc *q;
  803. lock(&m->l);
  804. m->rip = 0;
  805. for(q = m->queue; q; q = q->list) {
  806. if(q->done == 0)
  807. if(Wakeup(&q->r))
  808. break;
  809. }
  810. unlock(&m->l);
  811. }
  812. void
  813. mountmux(Mnt *m, Mntrpc *r)
  814. {
  815. Mntrpc **l, *q;
  816. lock(&m->l);
  817. l = &m->queue;
  818. for(q = *l; q; q = q->list) {
  819. /* look for a reply to a message */
  820. if(q->request.tag == r->reply.tag) {
  821. *l = q->list;
  822. if(q != r) {
  823. /*
  824. * Completed someone else.
  825. * Trade pointers to receive buffer.
  826. */
  827. q->reply = r->reply;
  828. q->b = r->b;
  829. r->b = nil;
  830. }
  831. q->done = 1;
  832. unlock(&m->l);
  833. if(mntstats != nil)
  834. (*mntstats)(q->request.type,
  835. m->c, q->stime,
  836. q->reqlen + r->replen);
  837. if(q != r)
  838. Wakeup(&q->r);
  839. return;
  840. }
  841. l = &q->list;
  842. }
  843. unlock(&m->l);
  844. if(r->reply.type == Rerror)
  845. print("unexpected reply tag %ud; type %d (error %q)\n", r->reply.tag, r->reply.type, r->reply.ename);
  846. else
  847. print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
  848. }
  849. /*
  850. * Create a new flush request and chain the previous
  851. * requests from it
  852. */
  853. Mntrpc*
  854. mntflushalloc(Mntrpc *r, ulong iounit)
  855. {
  856. Mntrpc *fr;
  857. fr = mntralloc(0, iounit);
  858. fr->request.type = Tflush;
  859. if(r->request.type == Tflush)
  860. fr->request.oldtag = r->request.oldtag;
  861. else
  862. fr->request.oldtag = r->request.tag;
  863. fr->flushed = r;
  864. return fr;
  865. }
  866. /*
  867. * Free a chain of flushes. Remove each unanswered
  868. * flush and the original message from the unanswered
  869. * request queue. Mark the original message as done
  870. * and if it hasn't been answered set the reply to to
  871. * Rflush.
  872. */
  873. void
  874. mntflushfree(Mnt *m, Mntrpc *r)
  875. {
  876. Mntrpc *fr;
  877. while(r){
  878. fr = r->flushed;
  879. if(!r->done){
  880. r->reply.type = Rflush;
  881. mntqrm(m, r);
  882. }
  883. if(fr)
  884. mntfree(r);
  885. r = fr;
  886. }
  887. }
  888. static int
  889. alloctag(void)
  890. {
  891. int i, j;
  892. ulong v;
  893. for(i = 0; i < NMASK; i++){
  894. v = mntalloc.tagmask[i];
  895. if(v == ~0UL)
  896. continue;
  897. for(j = 0; j < 1<<TAGSHIFT; j++)
  898. if((v & (1<<j)) == 0){
  899. mntalloc.tagmask[i] |= 1<<j;
  900. return (i<<TAGSHIFT) + j;
  901. }
  902. }
  903. /* panic("no devmnt tags left"); */
  904. return NOTAG;
  905. }
  906. static void
  907. freetag(int t)
  908. {
  909. mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
  910. }
  911. Mntrpc*
  912. mntralloc(Chan *c, ulong msize)
  913. {
  914. Mntrpc *new;
  915. lock(&mntalloc.l);
  916. new = mntalloc.rpcfree;
  917. if(new == nil){
  918. new = malloc(sizeof(Mntrpc));
  919. if(new == nil) {
  920. unlock(&mntalloc.l);
  921. exhausted("mount rpc header");
  922. }
  923. /*
  924. * The header is split from the data buffer as
  925. * mountmux may swap the buffer with another header.
  926. */
  927. new->rpc = mallocz(msize, 0);
  928. if(new->rpc == nil){
  929. free(new);
  930. unlock(&mntalloc.l);
  931. exhausted("mount rpc buffer");
  932. }
  933. new->rpclen = msize;
  934. new->request.tag = alloctag();
  935. if(new->request.tag == NOTAG){
  936. free(new);
  937. unlock(&mntalloc.l);
  938. exhausted("rpc tags");
  939. }
  940. }
  941. else {
  942. mntalloc.rpcfree = new->list;
  943. mntalloc.nrpcfree--;
  944. if(new->rpclen < msize){
  945. free(new->rpc);
  946. new->rpc = mallocz(msize, 0);
  947. if(new->rpc == nil){
  948. free(new);
  949. mntalloc.nrpcused--;
  950. unlock(&mntalloc.l);
  951. exhausted("mount rpc buffer");
  952. }
  953. new->rpclen = msize;
  954. }
  955. }
  956. mntalloc.nrpcused++;
  957. unlock(&mntalloc.l);
  958. new->c = c;
  959. new->done = 0;
  960. new->flushed = nil;
  961. new->b = nil;
  962. return new;
  963. }
  964. void
  965. mntfree(Mntrpc *r)
  966. {
  967. if(r->b != nil)
  968. freeblist(r->b);
  969. lock(&mntalloc.l);
  970. if(mntalloc.nrpcfree >= 10){
  971. free(r->rpc);
  972. freetag(r->request.tag);
  973. free(r);
  974. }
  975. else{
  976. r->list = mntalloc.rpcfree;
  977. mntalloc.rpcfree = r;
  978. mntalloc.nrpcfree++;
  979. }
  980. mntalloc.nrpcused--;
  981. unlock(&mntalloc.l);
  982. }
  983. void
  984. mntqrm(Mnt *m, Mntrpc *r)
  985. {
  986. Mntrpc **l, *f;
  987. lock(&m->l);
  988. r->done = 1;
  989. l = &m->queue;
  990. for(f = *l; f; f = f->list) {
  991. if(f == r) {
  992. *l = r->list;
  993. break;
  994. }
  995. l = &f->list;
  996. }
  997. unlock(&m->l);
  998. }
  999. Mnt*
  1000. mntchk(Chan *c)
  1001. {
  1002. Mnt *m;
  1003. /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
  1004. if(c->mchan == nil)
  1005. panic("mntchk 1: nil mchan c %s\n", c2name(c));
  1006. m = c->mchan->mux;
  1007. if(m == nil)
  1008. print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
  1009. /*
  1010. * Was it closed and reused (was error(Eshutdown); now, it can't happen)
  1011. */
  1012. if(m->id == 0 || m->id >= c->dev)
  1013. panic("mntchk 3: can't happen");
  1014. return m;
  1015. }
  1016. /*
  1017. * Rewrite channel type and dev for in-flight data to
  1018. * reflect local values. These entries are known to be
  1019. * the first two in the Dir encoding after the count.
  1020. */
  1021. void
  1022. mntdirfix(uchar *dirbuf, Chan *c)
  1023. {
  1024. uint r;
  1025. r = devtab[c->type]->dc;
  1026. dirbuf += BIT16SZ; /* skip count */
  1027. PBIT16(dirbuf, r);
  1028. dirbuf += BIT16SZ;
  1029. PBIT32(dirbuf, c->dev);
  1030. }
  1031. int
  1032. rpcattn(void *v)
  1033. {
  1034. Mntrpc *r;
  1035. r = v;
  1036. return r->done || r->m->rip == 0;
  1037. }
  1038. Dev mntdevtab = {
  1039. 'M',
  1040. "mnt",
  1041. mntinit,
  1042. mntattach,
  1043. mntwalk,
  1044. mntstat,
  1045. mntopen,
  1046. mntcreate,
  1047. mntclose,
  1048. mntread,
  1049. devbread,
  1050. mntwrite,
  1051. devbwrite,
  1052. mntremove,
  1053. mntwstat,
  1054. };