devmnt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. /*
  8. * References are managed as follows:
  9. * The channel to the server - a network connection or pipe - has one
  10. * reference for every Chan open on the server. The server channel has
  11. * c->mux set to the Mnt used for muxing control to that server. Mnts
  12. * have no reference count; they go away when c goes away.
  13. * Each channel derived from the mount point has mchan set to c,
  14. * and increfs/decrefs mchan to manage references on the server
  15. * connection.
  16. */
  17. #define MAXRPC (IOHDRSZ+8192)
  18. struct Mntrpc
  19. {
  20. Chan* c; /* Channel for whom we are working */
  21. Mntrpc* list; /* Free/pending list */
  22. Fcall request; /* Outgoing file system protocol message */
  23. Fcall reply; /* Incoming reply */
  24. Mnt* m; /* Mount device during rpc */
  25. Rendez r; /* Place to hang out */
  26. uchar* rpc; /* I/O Data buffer */
  27. uint rpclen; /* len of buffer */
  28. Block *b; /* reply blocks */
  29. char done; /* Rpc completed */
  30. uvlong stime; /* start time for mnt statistics */
  31. ulong reqlen; /* request length for mnt statistics */
  32. ulong replen; /* reply length for mnt statistics */
  33. Mntrpc* flushed; /* message this one flushes */
  34. };
  35. enum
  36. {
  37. TAGSHIFT = 5, /* ulong has to be 32 bits */
  38. TAGMASK = (1<<TAGSHIFT)-1,
  39. NMASK = (64*1024)>>TAGSHIFT,
  40. };
  41. struct Mntalloc
  42. {
  43. Lock;
  44. Mnt* list; /* Mount devices in use */
  45. Mnt* mntfree; /* Free list */
  46. Mntrpc* rpcfree;
  47. int nrpcfree;
  48. int nrpcused;
  49. ulong id;
  50. ulong tagmask[NMASK];
  51. }mntalloc;
  52. Mnt* mntchk(Chan*);
  53. void mntdirfix(uchar*, Chan*);
  54. Mntrpc* mntflushalloc(Mntrpc*, ulong);
  55. void mntflushfree(Mnt*, Mntrpc*);
  56. void mntfree(Mntrpc*);
  57. void mntgate(Mnt*);
  58. void mntpntfree(Mnt*);
  59. void mntqrm(Mnt*, Mntrpc*);
  60. Mntrpc* mntralloc(Chan*, ulong);
  61. long mntrdwr(int, Chan*, void*, long, vlong);
  62. int mntrpcread(Mnt*, Mntrpc*);
  63. void mountio(Mnt*, Mntrpc*);
  64. void mountmux(Mnt*, Mntrpc*);
  65. void mountrpc(Mnt*, Mntrpc*);
  66. int rpcattn(void*);
  67. Chan* mntchan(void);
  68. char Esbadstat[] = "invalid directory entry received from server";
  69. char Enoversion[] = "version not established for mount channel";
  70. void (*mntstats)(int, Chan*, uvlong, ulong);
  71. static void
  72. mntreset(void)
  73. {
  74. mntalloc.id = 1;
  75. mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
  76. mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
  77. fmtinstall('F', fcallfmt);
  78. fmtinstall('D', dirfmt);
  79. /* We can't install %M since eipfmt does and is used in the kernel [sape] */
  80. cinit();
  81. }
  82. /*
  83. * Version is not multiplexed: message sent only once per connection.
  84. */
  85. long
  86. mntversion(Chan *c, char *version, int msize, int returnlen)
  87. {
  88. Fcall f;
  89. uchar *msg;
  90. Mnt *m;
  91. char *v;
  92. long k, l;
  93. uvlong oo;
  94. char buf[128];
  95. qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
  96. if(waserror()){
  97. qunlock(&c->umqlock);
  98. nexterror();
  99. }
  100. /* defaults */
  101. if(msize == 0)
  102. msize = MAXRPC;
  103. if(msize > c->iounit && c->iounit != 0)
  104. msize = c->iounit;
  105. v = version;
  106. if(v == nil || v[0] == '\0')
  107. v = VERSION9P;
  108. /* validity */
  109. if(msize < 0)
  110. error("bad iounit in version call");
  111. if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
  112. error("bad 9P version specification");
  113. m = c->mux;
  114. if(m != nil){
  115. qunlock(&c->umqlock);
  116. poperror();
  117. strecpy(buf, buf+sizeof buf, m->version);
  118. k = strlen(buf);
  119. if(strncmp(buf, v, k) != 0){
  120. snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
  121. error(buf);
  122. }
  123. if(returnlen > 0){
  124. if(returnlen < k)
  125. error(Eshort);
  126. memmove(version, buf, k);
  127. }
  128. return k;
  129. }
  130. f.type = Tversion;
  131. f.tag = NOTAG;
  132. f.msize = msize;
  133. f.version = v;
  134. msg = malloc(8192+IOHDRSZ);
  135. if(msg == nil)
  136. exhausted("version memory");
  137. if(waserror()){
  138. free(msg);
  139. nexterror();
  140. }
  141. k = convS2M(&f, msg, 8192+IOHDRSZ);
  142. if(k == 0)
  143. error("bad fversion conversion on send");
  144. lock(c);
  145. oo = c->offset;
  146. c->offset += k;
  147. unlock(c);
  148. l = devtab[c->type]->write(c, msg, k, oo);
  149. if(l < k){
  150. lock(c);
  151. c->offset -= k - l;
  152. unlock(c);
  153. error("short write in fversion");
  154. }
  155. /* message sent; receive and decode reply */
  156. k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
  157. if(k <= 0)
  158. error("EOF receiving fversion reply");
  159. lock(c);
  160. c->offset += k;
  161. unlock(c);
  162. l = convM2S(msg, k, &f);
  163. if(l != k)
  164. error("bad fversion conversion on reply");
  165. if(f.type != Rversion){
  166. if(f.type == Rerror)
  167. error(f.ename);
  168. error("unexpected reply type in fversion");
  169. }
  170. if(f.msize > msize)
  171. error("server tries to increase msize in fversion");
  172. if(f.msize<256 || f.msize>1024*1024)
  173. error("nonsense value of msize in fversion");
  174. k = strlen(f.version);
  175. if(strncmp(f.version, v, k) != 0)
  176. error("bad 9P version returned from server");
  177. /* now build Mnt associated with this connection */
  178. lock(&mntalloc);
  179. m = mntalloc.mntfree;
  180. if(m != 0)
  181. mntalloc.mntfree = m->list;
  182. else {
  183. m = malloc(sizeof(Mnt));
  184. if(m == 0) {
  185. unlock(&mntalloc);
  186. exhausted("mount devices");
  187. }
  188. }
  189. m->list = mntalloc.list;
  190. mntalloc.list = m;
  191. m->version = nil;
  192. kstrdup(&m->version, f.version);
  193. m->id = mntalloc.id++;
  194. m->q = qopen(10*MAXRPC, 0, nil, nil);
  195. m->msize = f.msize;
  196. unlock(&mntalloc);
  197. if(returnlen > 0){
  198. if(returnlen < k)
  199. error(Eshort);
  200. memmove(version, f.version, k);
  201. }
  202. poperror(); /* msg */
  203. free(msg);
  204. lock(m);
  205. m->queue = 0;
  206. m->rip = 0;
  207. c->flag |= CMSG;
  208. c->mux = m;
  209. m->c = c;
  210. unlock(m);
  211. poperror(); /* c */
  212. qunlock(&c->umqlock);
  213. return k;
  214. }
  215. Chan*
  216. mntauth(Chan *c, char *spec)
  217. {
  218. Mnt *m;
  219. Mntrpc *r;
  220. m = c->mux;
  221. if(m == nil){
  222. mntversion(c, VERSION9P, MAXRPC, 0);
  223. m = c->mux;
  224. if(m == nil)
  225. error(Enoversion);
  226. }
  227. c = mntchan();
  228. if(waserror()) {
  229. /* Close must not be called since it will
  230. * call mnt recursively
  231. */
  232. chanfree(c);
  233. nexterror();
  234. }
  235. r = mntralloc(0, m->msize);
  236. if(waserror()) {
  237. mntfree(r);
  238. nexterror();
  239. }
  240. r->request.type = Tauth;
  241. r->request.afid = c->fid;
  242. r->request.uname = up->user;
  243. r->request.aname = spec;
  244. mountrpc(m, r);
  245. c->qid = r->reply.aqid;
  246. c->mchan = m->c;
  247. incref(m->c);
  248. c->mqid = c->qid;
  249. c->mode = ORDWR;
  250. poperror(); /* r */
  251. mntfree(r);
  252. poperror(); /* c */
  253. return c;
  254. }
  255. static Chan*
  256. mntattach(char *muxattach)
  257. {
  258. Mnt *m;
  259. Chan *c;
  260. Mntrpc *r;
  261. struct bogus{
  262. Chan *chan;
  263. Chan *authchan;
  264. char *spec;
  265. int flags;
  266. }bogus;
  267. bogus = *((struct bogus *)muxattach);
  268. c = bogus.chan;
  269. m = c->mux;
  270. if(m == nil){
  271. mntversion(c, nil, 0, 0);
  272. m = c->mux;
  273. if(m == nil)
  274. error(Enoversion);
  275. }
  276. c = mntchan();
  277. if(waserror()) {
  278. /* Close must not be called since it will
  279. * call mnt recursively
  280. */
  281. chanfree(c);
  282. nexterror();
  283. }
  284. r = mntralloc(0, m->msize);
  285. if(waserror()) {
  286. mntfree(r);
  287. nexterror();
  288. }
  289. r->request.type = Tattach;
  290. r->request.fid = c->fid;
  291. if(bogus.authchan == nil)
  292. r->request.afid = NOFID;
  293. else
  294. r->request.afid = bogus.authchan->fid;
  295. r->request.uname = up->user;
  296. r->request.aname = bogus.spec;
  297. mountrpc(m, r);
  298. c->qid = r->reply.qid;
  299. c->mchan = m->c;
  300. incref(m->c);
  301. c->mqid = c->qid;
  302. poperror(); /* r */
  303. mntfree(r);
  304. poperror(); /* c */
  305. if(bogus.flags&MCACHE)
  306. c->flag |= CCACHE;
  307. return c;
  308. }
  309. Chan*
  310. mntchan(void)
  311. {
  312. Chan *c;
  313. c = devattach('M', 0);
  314. lock(&mntalloc);
  315. c->dev = mntalloc.id++;
  316. unlock(&mntalloc);
  317. if(c->mchan)
  318. panic("mntchan non-zero %p", c->mchan);
  319. return c;
  320. }
  321. static Walkqid*
  322. mntwalk(Chan *c, Chan *nc, char **name, int nname)
  323. {
  324. int i, alloc;
  325. Mnt *m;
  326. Mntrpc *r;
  327. Walkqid *wq;
  328. if(nc != nil)
  329. print("mntwalk: nc != nil\n");
  330. if(nname > MAXWELEM)
  331. error("devmnt: too many name elements");
  332. alloc = 0;
  333. wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
  334. if(waserror()){
  335. if(alloc && wq->clone!=nil)
  336. cclose(wq->clone);
  337. free(wq);
  338. return nil;
  339. }
  340. alloc = 0;
  341. m = mntchk(c);
  342. r = mntralloc(c, m->msize);
  343. if(nc == nil){
  344. nc = devclone(c);
  345. /*
  346. * Until the other side accepts this fid, we can't mntclose it.
  347. * Therefore set type to 0 for now; rootclose is known to be safe.
  348. */
  349. nc->type = 0;
  350. alloc = 1;
  351. }
  352. wq->clone = nc;
  353. if(waserror()) {
  354. mntfree(r);
  355. nexterror();
  356. }
  357. r->request.type = Twalk;
  358. r->request.fid = c->fid;
  359. r->request.newfid = nc->fid;
  360. r->request.nwname = nname;
  361. memmove(r->request.wname, name, nname*sizeof(char*));
  362. mountrpc(m, r);
  363. if(r->reply.nwqid > nname)
  364. error("too many QIDs returned by walk");
  365. if(r->reply.nwqid < nname){
  366. if(alloc)
  367. cclose(nc);
  368. wq->clone = nil;
  369. if(r->reply.nwqid == 0){
  370. free(wq);
  371. wq = nil;
  372. goto Return;
  373. }
  374. }
  375. /* move new fid onto mnt device and update its qid */
  376. if(wq->clone != nil){
  377. if(wq->clone != c){
  378. wq->clone->type = c->type;
  379. wq->clone->mchan = c->mchan;
  380. incref(c->mchan);
  381. }
  382. if(r->reply.nwqid > 0)
  383. wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
  384. }
  385. wq->nqid = r->reply.nwqid;
  386. for(i=0; i<wq->nqid; i++)
  387. wq->qid[i] = r->reply.wqid[i];
  388. Return:
  389. poperror();
  390. mntfree(r);
  391. poperror();
  392. return wq;
  393. }
  394. static int
  395. mntstat(Chan *c, uchar *dp, int n)
  396. {
  397. Mnt *m;
  398. Mntrpc *r;
  399. if(n < BIT16SZ)
  400. error(Eshortstat);
  401. m = mntchk(c);
  402. r = mntralloc(c, m->msize);
  403. if(waserror()) {
  404. mntfree(r);
  405. nexterror();
  406. }
  407. r->request.type = Tstat;
  408. r->request.fid = c->fid;
  409. mountrpc(m, r);
  410. if(r->reply.nstat > n){
  411. n = BIT16SZ;
  412. PBIT16((uchar*)dp, r->reply.nstat-2);
  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);
  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);
  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;
  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->nnote)
  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->path != nil)
  656. sn = m->c->path->s;
  657. cn = "?";
  658. if(r->c != nil && r->c->path != nil)
  659. cn = r->c->path->s;
  660. print("mnt: proc %s %lud: mismatch from %s %s rep 0x%lux 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->errstr, Eintr) != 0){
  675. mntflushfree(m, r);
  676. nexterror();
  677. }
  678. r = mntflushalloc(r, m->msize);
  679. }
  680. lock(m);
  681. r->m = m;
  682. r->list = m->queue;
  683. m->queue = r;
  684. unlock(m);
  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);
  698. if(m->rip == 0)
  699. break;
  700. unlock(m);
  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);
  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);
  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);
  811. }
  812. void
  813. mountmux(Mnt *m, Mntrpc *r)
  814. {
  815. Mntrpc **l, *q;
  816. lock(m);
  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);
  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);
  844. print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
  845. }
  846. /*
  847. * Create a new flush request and chain the previous
  848. * requests from it
  849. */
  850. Mntrpc*
  851. mntflushalloc(Mntrpc *r, ulong iounit)
  852. {
  853. Mntrpc *fr;
  854. fr = mntralloc(0, iounit);
  855. fr->request.type = Tflush;
  856. if(r->request.type == Tflush)
  857. fr->request.oldtag = r->request.oldtag;
  858. else
  859. fr->request.oldtag = r->request.tag;
  860. fr->flushed = r;
  861. return fr;
  862. }
  863. /*
  864. * Free a chain of flushes. Remove each unanswered
  865. * flush and the original message from the unanswered
  866. * request queue. Mark the original message as done
  867. * and if it hasn't been answered set the reply to to
  868. * Rflush.
  869. */
  870. void
  871. mntflushfree(Mnt *m, Mntrpc *r)
  872. {
  873. Mntrpc *fr;
  874. while(r){
  875. fr = r->flushed;
  876. if(!r->done){
  877. r->reply.type = Rflush;
  878. mntqrm(m, r);
  879. }
  880. if(fr)
  881. mntfree(r);
  882. r = fr;
  883. }
  884. }
  885. int
  886. alloctag(void)
  887. {
  888. int i, j;
  889. ulong v;
  890. for(i = 0; i < NMASK; i++){
  891. v = mntalloc.tagmask[i];
  892. if(v == ~0UL)
  893. continue;
  894. for(j = 0; j < 1<<TAGSHIFT; j++)
  895. if((v & (1<<j)) == 0){
  896. mntalloc.tagmask[i] |= 1<<j;
  897. return (i<<TAGSHIFT) + j;
  898. }
  899. }
  900. panic("no friggin tags left");
  901. return NOTAG;
  902. }
  903. void
  904. freetag(int t)
  905. {
  906. mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
  907. }
  908. Mntrpc*
  909. mntralloc(Chan *c, ulong msize)
  910. {
  911. Mntrpc *new;
  912. lock(&mntalloc);
  913. new = mntalloc.rpcfree;
  914. if(new == nil){
  915. new = malloc(sizeof(Mntrpc));
  916. if(new == nil) {
  917. unlock(&mntalloc);
  918. exhausted("mount rpc header");
  919. }
  920. /*
  921. * The header is split from the data buffer as
  922. * mountmux may swap the buffer with another header.
  923. */
  924. new->rpc = mallocz(msize, 0);
  925. if(new->rpc == nil){
  926. free(new);
  927. unlock(&mntalloc);
  928. exhausted("mount rpc buffer");
  929. }
  930. new->rpclen = msize;
  931. new->request.tag = alloctag();
  932. }
  933. else {
  934. mntalloc.rpcfree = new->list;
  935. mntalloc.nrpcfree--;
  936. if(new->rpclen < msize){
  937. free(new->rpc);
  938. new->rpc = mallocz(msize, 0);
  939. if(new->rpc == nil){
  940. free(new);
  941. mntalloc.nrpcused--;
  942. unlock(&mntalloc);
  943. exhausted("mount rpc buffer");
  944. }
  945. new->rpclen = msize;
  946. }
  947. }
  948. mntalloc.nrpcused++;
  949. unlock(&mntalloc);
  950. new->c = c;
  951. new->done = 0;
  952. new->flushed = nil;
  953. new->b = nil;
  954. return new;
  955. }
  956. void
  957. mntfree(Mntrpc *r)
  958. {
  959. if(r->b != nil)
  960. freeblist(r->b);
  961. lock(&mntalloc);
  962. if(mntalloc.nrpcfree >= 10){
  963. free(r->rpc);
  964. free(r);
  965. freetag(r->request.tag);
  966. }
  967. else{
  968. r->list = mntalloc.rpcfree;
  969. mntalloc.rpcfree = r;
  970. mntalloc.nrpcfree++;
  971. }
  972. mntalloc.nrpcused--;
  973. unlock(&mntalloc);
  974. }
  975. void
  976. mntqrm(Mnt *m, Mntrpc *r)
  977. {
  978. Mntrpc **l, *f;
  979. lock(m);
  980. r->done = 1;
  981. l = &m->queue;
  982. for(f = *l; f; f = f->list) {
  983. if(f == r) {
  984. *l = r->list;
  985. break;
  986. }
  987. l = &f->list;
  988. }
  989. unlock(m);
  990. }
  991. Mnt*
  992. mntchk(Chan *c)
  993. {
  994. Mnt *m;
  995. /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
  996. if(c->mchan == nil)
  997. panic("mntchk 1: nil mchan c %s\n", chanpath(c));
  998. m = c->mchan->mux;
  999. if(m == nil)
  1000. print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
  1001. /*
  1002. * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
  1003. */
  1004. if(m->id == 0 || m->id >= c->dev)
  1005. panic("mntchk 3: can't happen");
  1006. return m;
  1007. }
  1008. /*
  1009. * Rewrite channel type and dev for in-flight data to
  1010. * reflect local values. These entries are known to be
  1011. * the first two in the Dir encoding after the count.
  1012. */
  1013. void
  1014. mntdirfix(uchar *dirbuf, Chan *c)
  1015. {
  1016. uint r;
  1017. r = devtab[c->type]->dc;
  1018. dirbuf += BIT16SZ; /* skip count */
  1019. PBIT16(dirbuf, r);
  1020. dirbuf += BIT16SZ;
  1021. PBIT32(dirbuf, c->dev);
  1022. }
  1023. int
  1024. rpcattn(void *v)
  1025. {
  1026. Mntrpc *r;
  1027. r = v;
  1028. return r->done || r->m->rip == 0;
  1029. }
  1030. Dev mntdevtab = {
  1031. 'M',
  1032. "mnt",
  1033. mntreset,
  1034. devinit,
  1035. devshutdown,
  1036. mntattach,
  1037. mntwalk,
  1038. mntstat,
  1039. mntopen,
  1040. mntcreate,
  1041. mntclose,
  1042. mntread,
  1043. devbread,
  1044. mntwrite,
  1045. devbwrite,
  1046. mntremove,
  1047. mntwstat,
  1048. };