devmnt.c 21 KB

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