devmnt.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  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. if(strncmp(f.version, v, strlen(f.version)) != 0)
  175. error("bad 9P version returned from server");
  176. /* now build Mnt associated with this connection */
  177. lock(&mntalloc);
  178. m = mntalloc.mntfree;
  179. if(m != 0)
  180. mntalloc.mntfree = m->list;
  181. else {
  182. m = malloc(sizeof(Mnt));
  183. if(m == 0) {
  184. unlock(&mntalloc);
  185. exhausted("mount devices");
  186. }
  187. }
  188. m->list = mntalloc.list;
  189. mntalloc.list = m;
  190. m->version = nil;
  191. kstrdup(&m->version, f.version);
  192. m->id = mntalloc.id++;
  193. m->q = qopen(10*MAXRPC, 0, nil, nil);
  194. m->msize = f.msize;
  195. unlock(&mntalloc);
  196. poperror(); /* msg */
  197. free(msg);
  198. lock(m);
  199. m->queue = 0;
  200. m->rip = 0;
  201. c->flag |= CMSG;
  202. c->mux = m;
  203. m->c = c;
  204. unlock(m);
  205. poperror(); /* c */
  206. qunlock(&c->umqlock);
  207. k = strlen(f.version);
  208. if(returnlen > 0){
  209. if(returnlen < k)
  210. error(Eshort);
  211. memmove(version, f.version, k);
  212. }
  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 >= 1<<(8*BIT16SZ))
  411. error("returned stat buffer count too large");
  412. if(r->reply.nstat > n){
  413. /*
  414. * 12/31/2002 RSC
  415. *
  416. * This should be nstat-2, which is the first two
  417. * bytes of the stat buffer. But dirstat and dirfstat
  418. * depended on getting the full nstat (they didn't
  419. * add BIT16SZ themselves). I fixed dirstat and dirfstat
  420. * but am leaving this unchanged for now. After a
  421. * few months, once enough of the relevant binaries
  422. * have been recompiled for other reasons, we can
  423. * change this to nstat-2. Devstat gets this right
  424. * (via convD2M).
  425. */
  426. /* doesn't fit; just patch the count and return */
  427. PBIT16((uchar*)dp, r->reply.nstat);
  428. n = BIT16SZ;
  429. }else{
  430. n = r->reply.nstat;
  431. memmove(dp, r->reply.stat, n);
  432. validstat(dp, n);
  433. mntdirfix(dp, c);
  434. }
  435. poperror();
  436. mntfree(r);
  437. return n;
  438. }
  439. static Chan*
  440. mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
  441. {
  442. Mnt *m;
  443. Mntrpc *r;
  444. m = mntchk(c);
  445. r = mntralloc(c, m->msize);
  446. if(waserror()) {
  447. mntfree(r);
  448. nexterror();
  449. }
  450. r->request.type = type;
  451. r->request.fid = c->fid;
  452. r->request.mode = omode;
  453. if(type == Tcreate){
  454. r->request.perm = perm;
  455. r->request.name = name;
  456. }
  457. mountrpc(m, r);
  458. c->qid = r->reply.qid;
  459. c->offset = 0;
  460. c->mode = openmode(omode);
  461. c->iounit = r->reply.iounit;
  462. if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
  463. c->iounit = m->msize-IOHDRSZ;
  464. c->flag |= COPEN;
  465. poperror();
  466. mntfree(r);
  467. if(c->flag & CCACHE)
  468. copen(c);
  469. return c;
  470. }
  471. static Chan*
  472. mntopen(Chan *c, int omode)
  473. {
  474. return mntopencreate(Topen, c, nil, omode, 0);
  475. }
  476. static void
  477. mntcreate(Chan *c, char *name, int omode, ulong perm)
  478. {
  479. mntopencreate(Tcreate, c, name, omode, perm);
  480. }
  481. static void
  482. mntclunk(Chan *c, int t)
  483. {
  484. Mnt *m;
  485. Mntrpc *r;
  486. m = mntchk(c);
  487. r = mntralloc(c, m->msize);
  488. if(waserror()){
  489. mntfree(r);
  490. nexterror();
  491. }
  492. r->request.type = t;
  493. r->request.fid = c->fid;
  494. mountrpc(m, r);
  495. mntfree(r);
  496. poperror();
  497. }
  498. void
  499. muxclose(Mnt *m)
  500. {
  501. Mntrpc *q, *r;
  502. for(q = m->queue; q; q = r) {
  503. r = q->list;
  504. mntfree(q);
  505. }
  506. m->id = 0;
  507. free(m->version);
  508. m->version = nil;
  509. mntpntfree(m);
  510. }
  511. void
  512. mntpntfree(Mnt *m)
  513. {
  514. Mnt *f, **l;
  515. Queue *q;
  516. lock(&mntalloc);
  517. l = &mntalloc.list;
  518. for(f = *l; f; f = f->list) {
  519. if(f == m) {
  520. *l = m->list;
  521. break;
  522. }
  523. l = &f->list;
  524. }
  525. m->list = mntalloc.mntfree;
  526. mntalloc.mntfree = m;
  527. q = m->q;
  528. unlock(&mntalloc);
  529. qfree(q);
  530. }
  531. static void
  532. mntclose(Chan *c)
  533. {
  534. mntclunk(c, Tclunk);
  535. }
  536. static void
  537. mntremove(Chan *c)
  538. {
  539. mntclunk(c, Tremove);
  540. }
  541. static int
  542. mntwstat(Chan *c, uchar *dp, int n)
  543. {
  544. Mnt *m;
  545. Mntrpc *r;
  546. m = mntchk(c);
  547. r = mntralloc(c, m->msize);
  548. if(waserror()) {
  549. mntfree(r);
  550. nexterror();
  551. }
  552. r->request.type = Twstat;
  553. r->request.fid = c->fid;
  554. r->request.nstat = n;
  555. r->request.stat = dp;
  556. mountrpc(m, r);
  557. poperror();
  558. mntfree(r);
  559. return n;
  560. }
  561. static long
  562. mntread(Chan *c, void *buf, long n, vlong off)
  563. {
  564. uchar *p, *e;
  565. int nc, cache, isdir, dirlen;
  566. isdir = 0;
  567. cache = c->flag & CCACHE;
  568. if(c->qid.type & QTDIR) {
  569. cache = 0;
  570. isdir = 1;
  571. }
  572. p = buf;
  573. if(cache) {
  574. nc = cread(c, buf, n, off);
  575. if(nc > 0) {
  576. n -= nc;
  577. if(n == 0)
  578. return nc;
  579. p += nc;
  580. off += nc;
  581. }
  582. n = mntrdwr(Tread, c, p, n, off);
  583. cupdate(c, p, n, off);
  584. return n + nc;
  585. }
  586. n = mntrdwr(Tread, c, buf, n, off);
  587. if(isdir) {
  588. for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
  589. dirlen = BIT16SZ+GBIT16(p);
  590. if(p+dirlen > e)
  591. break;
  592. validstat(p, dirlen);
  593. mntdirfix(p, c);
  594. }
  595. if(p != e)
  596. error(Esbadstat);
  597. }
  598. return n;
  599. }
  600. static long
  601. mntwrite(Chan *c, void *buf, long n, vlong off)
  602. {
  603. return mntrdwr(Twrite, c, buf, n, off);
  604. }
  605. long
  606. mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
  607. {
  608. Mnt *m;
  609. Mntrpc *r;
  610. char *uba;
  611. int cache;
  612. ulong cnt, nr, nreq;
  613. m = mntchk(c);
  614. uba = buf;
  615. cnt = 0;
  616. cache = c->flag & CCACHE;
  617. if(c->qid.type & QTDIR)
  618. cache = 0;
  619. for(;;) {
  620. r = mntralloc(c, m->msize);
  621. if(waserror()) {
  622. mntfree(r);
  623. nexterror();
  624. }
  625. r->request.type = type;
  626. r->request.fid = c->fid;
  627. r->request.offset = off;
  628. r->request.data = uba;
  629. nr = n;
  630. if(nr > m->msize-IOHDRSZ)
  631. nr = m->msize-IOHDRSZ;
  632. r->request.count = nr;
  633. mountrpc(m, r);
  634. nreq = r->request.count;
  635. nr = r->reply.count;
  636. if(nr > nreq)
  637. nr = nreq;
  638. if(type == Tread)
  639. r->b = bl2mem((uchar*)uba, r->b, nr);
  640. else if(cache)
  641. cwrite(c, (uchar*)uba, nr, off);
  642. poperror();
  643. mntfree(r);
  644. off += nr;
  645. uba += nr;
  646. cnt += nr;
  647. n -= nr;
  648. if(nr != nreq || n == 0 || up->nnote)
  649. break;
  650. }
  651. return cnt;
  652. }
  653. void
  654. mountrpc(Mnt *m, Mntrpc *r)
  655. {
  656. char *sn, *cn;
  657. int t;
  658. r->reply.tag = 0;
  659. r->reply.type = Tmax; /* can't ever be a valid message type */
  660. mountio(m, r);
  661. t = r->reply.type;
  662. switch(t) {
  663. case Rerror:
  664. error(r->reply.ename);
  665. case Rflush:
  666. error(Eintr);
  667. default:
  668. if(t == r->request.type+1)
  669. break;
  670. sn = "?";
  671. if(m->c->name != nil)
  672. sn = m->c->name->s;
  673. cn = "?";
  674. if(r->c != nil && r->c->name != nil)
  675. cn = r->c->name->s;
  676. print("mnt: proc %s %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
  677. up->text, up->pid, sn, cn,
  678. r, r->request.tag, r->request.fid, r->request.type,
  679. r->reply.type, r->reply.tag);
  680. error(Emountrpc);
  681. }
  682. }
  683. void
  684. mountio(Mnt *m, Mntrpc *r)
  685. {
  686. int n;
  687. while(waserror()) {
  688. if(m->rip == up)
  689. mntgate(m);
  690. if(strcmp(up->errstr, Eintr) != 0){
  691. mntflushfree(m, r);
  692. nexterror();
  693. }
  694. r = mntflushalloc(r, m->msize);
  695. }
  696. lock(m);
  697. r->m = m;
  698. r->list = m->queue;
  699. m->queue = r;
  700. unlock(m);
  701. /* Transmit a file system rpc */
  702. if(m->msize == 0)
  703. panic("msize");
  704. n = convS2M(&r->request, r->rpc, m->msize);
  705. if(n < 0)
  706. panic("bad message type in mountio");
  707. if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
  708. error(Emountrpc);
  709. r->stime = fastticks(nil);
  710. r->reqlen = n;
  711. /* Gate readers onto the mount point one at a time */
  712. for(;;) {
  713. lock(m);
  714. if(m->rip == 0)
  715. break;
  716. unlock(m);
  717. sleep(&r->r, rpcattn, r);
  718. if(r->done){
  719. poperror();
  720. mntflushfree(m, r);
  721. return;
  722. }
  723. }
  724. m->rip = up;
  725. unlock(m);
  726. while(r->done == 0) {
  727. if(mntrpcread(m, r) < 0)
  728. error(Emountrpc);
  729. mountmux(m, r);
  730. }
  731. mntgate(m);
  732. poperror();
  733. mntflushfree(m, r);
  734. }
  735. static int
  736. doread(Mnt *m, int len)
  737. {
  738. Block *b;
  739. while(qlen(m->q) < len){
  740. b = devtab[m->c->type]->bread(m->c, m->msize, 0);
  741. if(b == nil)
  742. return -1;
  743. if(BLEN(b) == 0){
  744. freeblist(b);
  745. return -1;
  746. }
  747. qaddlist(m->q, b);
  748. }
  749. return 0;
  750. }
  751. int
  752. mntrpcread(Mnt *m, Mntrpc *r)
  753. {
  754. int i, t, len, hlen;
  755. Block *b, **l, *nb;
  756. r->reply.type = 0;
  757. r->reply.tag = 0;
  758. /* read at least length, type, and tag and pullup to a single block */
  759. if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
  760. return -1;
  761. nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
  762. /* read in the rest of the message, avoid ridiculous (for now) message sizes */
  763. len = GBIT32(nb->rp);
  764. if(len > m->msize){
  765. qdiscard(m->q, qlen(m->q));
  766. return -1;
  767. }
  768. if(doread(m, len) < 0)
  769. return -1;
  770. /* pullup the header (i.e. everything except data) */
  771. t = nb->rp[BIT32SZ];
  772. switch(t){
  773. case Rread:
  774. hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
  775. break;
  776. default:
  777. hlen = len;
  778. break;
  779. }
  780. nb = pullupqueue(m->q, hlen);
  781. if(convM2S(nb->rp, len, &r->reply) <= 0){
  782. /* bad message, dump it */
  783. print("mntrpcread: convM2S failed\n");
  784. qdiscard(m->q, len);
  785. return -1;
  786. }
  787. /* hang the data off of the fcall struct */
  788. l = &r->b;
  789. *l = nil;
  790. do {
  791. b = qremove(m->q);
  792. if(hlen > 0){
  793. b->rp += hlen;
  794. len -= hlen;
  795. hlen = 0;
  796. }
  797. i = BLEN(b);
  798. if(i <= len){
  799. len -= i;
  800. *l = b;
  801. l = &(b->next);
  802. } else {
  803. /* split block and put unused bit back */
  804. nb = allocb(i-len);
  805. memmove(nb->wp, b->rp+len, i-len);
  806. b->wp = b->rp+len;
  807. nb->wp += i-len;
  808. qputback(m->q, nb);
  809. *l = b;
  810. return 0;
  811. }
  812. }while(len > 0);
  813. return 0;
  814. }
  815. void
  816. mntgate(Mnt *m)
  817. {
  818. Mntrpc *q;
  819. lock(m);
  820. m->rip = 0;
  821. for(q = m->queue; q; q = q->list) {
  822. if(q->done == 0)
  823. if(wakeup(&q->r))
  824. break;
  825. }
  826. unlock(m);
  827. }
  828. void
  829. mountmux(Mnt *m, Mntrpc *r)
  830. {
  831. Mntrpc **l, *q;
  832. lock(m);
  833. l = &m->queue;
  834. for(q = *l; q; q = q->list) {
  835. /* look for a reply to a message */
  836. if(q->request.tag == r->reply.tag) {
  837. *l = q->list;
  838. if(q != r) {
  839. /*
  840. * Completed someone else.
  841. * Trade pointers to receive buffer.
  842. */
  843. q->reply = r->reply;
  844. q->b = r->b;
  845. r->b = nil;
  846. }
  847. q->done = 1;
  848. unlock(m);
  849. if(mntstats != nil)
  850. (*mntstats)(q->request.type,
  851. m->c, q->stime,
  852. q->reqlen + r->replen);
  853. if(q != r)
  854. wakeup(&q->r);
  855. return;
  856. }
  857. l = &q->list;
  858. }
  859. unlock(m);
  860. print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
  861. }
  862. /*
  863. * Create a new flush request and chain the previous
  864. * requests from it
  865. */
  866. Mntrpc*
  867. mntflushalloc(Mntrpc *r, ulong iounit)
  868. {
  869. Mntrpc *fr;
  870. fr = mntralloc(0, iounit);
  871. fr->request.type = Tflush;
  872. if(r->request.type == Tflush)
  873. fr->request.oldtag = r->request.oldtag;
  874. else
  875. fr->request.oldtag = r->request.tag;
  876. fr->flushed = r;
  877. return fr;
  878. }
  879. /*
  880. * Free a chain of flushes. Remove each unanswered
  881. * flush and the original message from the unanswered
  882. * request queue. Mark the original message as done
  883. * and if it hasn't been answered set the reply to to
  884. * Rflush.
  885. */
  886. void
  887. mntflushfree(Mnt *m, Mntrpc *r)
  888. {
  889. Mntrpc *fr;
  890. while(r){
  891. fr = r->flushed;
  892. if(!r->done){
  893. r->reply.type = Rflush;
  894. mntqrm(m, r);
  895. }
  896. if(fr)
  897. mntfree(r);
  898. r = fr;
  899. }
  900. }
  901. int
  902. alloctag(void)
  903. {
  904. int i, j;
  905. ulong v;
  906. for(i = 0; i < NMASK; i++){
  907. v = mntalloc.tagmask[i];
  908. if(v == ~0UL)
  909. continue;
  910. for(j = 0; j < 1<<TAGSHIFT; j++)
  911. if((v & (1<<j)) == 0){
  912. mntalloc.tagmask[i] |= 1<<j;
  913. return (i<<TAGSHIFT) + j;
  914. }
  915. }
  916. panic("no friggin tags left");
  917. return NOTAG;
  918. }
  919. void
  920. freetag(int t)
  921. {
  922. mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
  923. }
  924. Mntrpc*
  925. mntralloc(Chan *c, ulong msize)
  926. {
  927. Mntrpc *new;
  928. lock(&mntalloc);
  929. new = mntalloc.rpcfree;
  930. if(new == nil){
  931. new = malloc(sizeof(Mntrpc));
  932. if(new == nil) {
  933. unlock(&mntalloc);
  934. exhausted("mount rpc header");
  935. }
  936. /*
  937. * The header is split from the data buffer as
  938. * mountmux may swap the buffer with another header.
  939. */
  940. new->rpc = mallocz(msize, 0);
  941. if(new->rpc == nil){
  942. free(new);
  943. unlock(&mntalloc);
  944. exhausted("mount rpc buffer");
  945. }
  946. new->rpclen = msize;
  947. new->request.tag = alloctag();
  948. }
  949. else {
  950. mntalloc.rpcfree = new->list;
  951. mntalloc.nrpcfree--;
  952. if(new->rpclen < msize){
  953. free(new->rpc);
  954. new->rpc = mallocz(msize, 0);
  955. if(new->rpc == nil){
  956. free(new);
  957. mntalloc.nrpcused--;
  958. unlock(&mntalloc);
  959. exhausted("mount rpc buffer");
  960. }
  961. new->rpclen = msize;
  962. }
  963. }
  964. mntalloc.nrpcused++;
  965. unlock(&mntalloc);
  966. new->c = c;
  967. new->done = 0;
  968. new->flushed = nil;
  969. new->b = nil;
  970. return new;
  971. }
  972. void
  973. mntfree(Mntrpc *r)
  974. {
  975. if(r->b != nil)
  976. freeblist(r->b);
  977. lock(&mntalloc);
  978. if(mntalloc.nrpcfree >= 10){
  979. free(r->rpc);
  980. free(r);
  981. freetag(r->request.tag);
  982. }
  983. else{
  984. r->list = mntalloc.rpcfree;
  985. mntalloc.rpcfree = r;
  986. mntalloc.nrpcfree++;
  987. }
  988. mntalloc.nrpcused--;
  989. unlock(&mntalloc);
  990. }
  991. void
  992. mntqrm(Mnt *m, Mntrpc *r)
  993. {
  994. Mntrpc **l, *f;
  995. lock(m);
  996. r->done = 1;
  997. l = &m->queue;
  998. for(f = *l; f; f = f->list) {
  999. if(f == r) {
  1000. *l = r->list;
  1001. break;
  1002. }
  1003. l = &f->list;
  1004. }
  1005. unlock(m);
  1006. }
  1007. Mnt*
  1008. mntchk(Chan *c)
  1009. {
  1010. Mnt *m;
  1011. /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
  1012. if(c->mchan == nil)
  1013. panic("mntchk 1: nil mchan c %s\n", channame(c));
  1014. m = c->mchan->mux;
  1015. if(m == nil)
  1016. print("mntchk 2: nil mux c %s c->mchan %s \n", channame(c), channame(c->mchan));
  1017. /*
  1018. * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
  1019. */
  1020. if(m->id == 0 || m->id >= c->dev)
  1021. panic("mntchk 3: can't happen");
  1022. return m;
  1023. }
  1024. /*
  1025. * Rewrite channel type and dev for in-flight data to
  1026. * reflect local values. These entries are known to be
  1027. * the first two in the Dir encoding after the count.
  1028. */
  1029. void
  1030. mntdirfix(uchar *dirbuf, Chan *c)
  1031. {
  1032. uint r;
  1033. r = devtab[c->type]->dc;
  1034. dirbuf += BIT16SZ; /* skip count */
  1035. PBIT16(dirbuf, r);
  1036. dirbuf += BIT16SZ;
  1037. PBIT32(dirbuf, c->dev);
  1038. }
  1039. int
  1040. rpcattn(void *v)
  1041. {
  1042. Mntrpc *r;
  1043. r = v;
  1044. return r->done || r->m->rip == 0;
  1045. }
  1046. Dev mntdevtab = {
  1047. 'M',
  1048. "mnt",
  1049. mntreset,
  1050. devinit,
  1051. devshutdown,
  1052. mntattach,
  1053. mntwalk,
  1054. mntstat,
  1055. mntopen,
  1056. mntcreate,
  1057. mntclose,
  1058. mntread,
  1059. devbread,
  1060. mntwrite,
  1061. devbwrite,
  1062. mntremove,
  1063. mntwstat,
  1064. };