devmnt.c 21 KB

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