cfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <auth.h>
  12. #include <fcall.h>
  13. #include "cformat.h"
  14. #include "lru.h"
  15. #include "bcache.h"
  16. #include "disk.h"
  17. #include "inode.h"
  18. #include "file.h"
  19. #include "stats.h"
  20. enum
  21. {
  22. Nfid= 10240,
  23. };
  24. /* maximum length of a file */
  25. enum { MAXLEN = ~0ULL >> 1 };
  26. typedef struct Mfile Mfile;
  27. typedef struct Ram Ram;
  28. typedef struct P9fs P9fs;
  29. struct Mfile
  30. {
  31. Qid qid;
  32. char busy;
  33. };
  34. Mfile mfile[Nfid];
  35. Icache ic;
  36. int debug, statson, noauth, openserver;
  37. struct P9fs
  38. {
  39. int fd[2];
  40. Fcall rhdr;
  41. Fcall thdr;
  42. int32_t len;
  43. char *name;
  44. };
  45. P9fs c; /* client conversation */
  46. P9fs s; /* server conversation */
  47. struct Cfsstat cfsstat, cfsprev;
  48. char statbuf[2048];
  49. int statlen;
  50. #define MAXFDATA 8192 /* i/o size for read/write */
  51. int messagesize = MAXFDATA+IOHDRSZ;
  52. uint8_t datasnd[MAXFDATA + IOHDRSZ];
  53. uint8_t datarcv[MAXFDATA + IOHDRSZ];
  54. Qid rootqid;
  55. Qid ctlqid = {0x5555555555555555LL, 0, 0};
  56. void rversion(void);
  57. void rauth(Mfile*);
  58. void rflush(void);
  59. void rattach(Mfile*);
  60. void rwalk(Mfile*);
  61. void ropen(Mfile*);
  62. void rcreate(Mfile*);
  63. void rread(Mfile*);
  64. void rwrite(Mfile*);
  65. void rclunk(Mfile*);
  66. void rremove(Mfile*);
  67. void rstat(Mfile*);
  68. void rwstat(Mfile*);
  69. void error(char*, ...);
  70. void warning(char*);
  71. void mountinit(char*, char*);
  72. void io(void);
  73. void sendreply(char*);
  74. void sendmsg(P9fs*, Fcall*);
  75. void rcvmsg(P9fs*, Fcall*);
  76. int delegate(void);
  77. int askserver(void);
  78. void cachesetup(int, char*, char*);
  79. int ctltest(Mfile*);
  80. void genstats(void);
  81. char *mname[]={
  82. [Tversion] "Tversion",
  83. [Tauth] "Tauth",
  84. [Tflush] "Tflush",
  85. [Tattach] "Tattach",
  86. [Twalk] "Twalk",
  87. [Topen] "Topen",
  88. [Tcreate] "Tcreate",
  89. [Tclunk] "Tclunk",
  90. [Tread] "Tread",
  91. [Twrite] "Twrite",
  92. [Tremove] "Tremove",
  93. [Tstat] "Tstat",
  94. [Twstat] "Twstat",
  95. [Rversion] "Rversion",
  96. [Rauth] "Rauth",
  97. [Rerror] "Rerror",
  98. [Rflush] "Rflush",
  99. [Rattach] "Rattach",
  100. [Rwalk] "Rwalk",
  101. [Ropen] "Ropen",
  102. [Rcreate] "Rcreate",
  103. [Rclunk] "Rclunk",
  104. [Rread] "Rread",
  105. [Rwrite] "Rwrite",
  106. [Rremove] "Rremove",
  107. [Rstat] "Rstat",
  108. [Rwstat] "Rwstat",
  109. 0,
  110. };
  111. void
  112. usage(void)
  113. {
  114. fprint(2, "usage:\tcfs -s [-dknrS] [-f partition]\n");
  115. fprint(2, "\tcfs [-a netaddr | -F srv] [-dknrS] [-f partition] [mntpt]\n");
  116. exits("usage");
  117. }
  118. void
  119. main(int argc, char *argv[])
  120. {
  121. int std, format, chkid;
  122. char *part, *server, *mtpt;
  123. NetConnInfo *snci;
  124. std = 0;
  125. format = 0;
  126. chkid = 1;
  127. part = "/dev/sdC0/cache";
  128. server = "tcp!fs";
  129. mtpt = "/tmp";
  130. ARGBEGIN{
  131. case 'a':
  132. server = EARGF(usage());
  133. break;
  134. case 'd':
  135. debug = 1;
  136. break;
  137. case 'f':
  138. part = EARGF(usage());
  139. break;
  140. case 'F':
  141. server = EARGF(usage());
  142. openserver = 1;
  143. break;
  144. case 'k':
  145. chkid = 0;
  146. break;
  147. case 'n':
  148. noauth = 1;
  149. break;
  150. case 'r':
  151. format = 1;
  152. break;
  153. case 'S':
  154. statson = 1;
  155. break;
  156. case 's':
  157. std = 1;
  158. break;
  159. default:
  160. usage();
  161. }ARGEND
  162. if(argc && *argv)
  163. mtpt = *argv;
  164. if(debug)
  165. fmtinstall('F', fcallfmt);
  166. c.name = "client";
  167. s.name = "server";
  168. if(std){
  169. c.fd[0] = c.fd[1] = 1;
  170. s.fd[0] = s.fd[1] = 0;
  171. }else
  172. mountinit(server, mtpt);
  173. if(chkid){
  174. if((snci = getnetconninfo(nil, s.fd[0])) == nil)
  175. /* Failed to lookup information; format */
  176. cachesetup(1, nil, part);
  177. else
  178. /* Do partition check */
  179. cachesetup(0, snci->raddr, part);
  180. }else
  181. /* Obey -f w/o regard to cache vs. remote server */
  182. cachesetup(format, nil, part);
  183. switch(fork()){
  184. case 0:
  185. io();
  186. exits("");
  187. case -1:
  188. error("fork");
  189. default:
  190. exits("");
  191. }
  192. }
  193. void
  194. cachesetup(int format, char *name, char *partition)
  195. {
  196. int f;
  197. int secsize;
  198. int inodes;
  199. int blocksize;
  200. secsize = 512;
  201. inodes = 1024;
  202. blocksize = 4*1024;
  203. f = open(partition, ORDWR);
  204. if(f < 0)
  205. error("opening partition");
  206. if(format || iinit(&ic, f, secsize, name) < 0){
  207. /*
  208. * If we need to format and don't have a name, fall
  209. * back to our old behavior of using "bootes"
  210. */
  211. name = (name == nil? "bootes": name);
  212. if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0)
  213. error("formatting failed");
  214. }
  215. }
  216. void
  217. mountinit(char *server, char *mountpoint)
  218. {
  219. int err;
  220. int p[2];
  221. /*
  222. * grab a channel and call up the file server
  223. */
  224. if (openserver)
  225. s.fd[0] = open(server, ORDWR);
  226. else
  227. s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
  228. if(s.fd[0] < 0)
  229. error("opening data: %r");
  230. s.fd[1] = s.fd[0];
  231. /*
  232. * mount onto name space
  233. */
  234. if(pipe(p) < 0)
  235. error("pipe failed");
  236. switch(fork()){
  237. case 0:
  238. break;
  239. default:
  240. if (noauth)
  241. err = mount(p[1], -1, mountpoint, MREPL|MCREATE, "",
  242. 'M');
  243. else
  244. err = amount(p[1], mountpoint, MREPL|MCREATE, "");
  245. if (err < 0)
  246. error("mount failed: %r");
  247. exits(0);
  248. case -1:
  249. error("fork failed\n");
  250. /*BUG: no wait!*/
  251. }
  252. c.fd[0] = c.fd[1] = p[0];
  253. }
  254. void
  255. io(void)
  256. {
  257. int type;
  258. Mfile *mf;
  259. loop:
  260. rcvmsg(&c, &c.thdr);
  261. type = c.thdr.type;
  262. if(statson){
  263. cfsstat.cm[type].n++;
  264. cfsstat.cm[type].s = nsec();
  265. }
  266. mf = &mfile[c.thdr.fid];
  267. switch(type){
  268. default:
  269. error("type");
  270. break;
  271. case Tversion:
  272. rversion();
  273. break;
  274. case Tauth:
  275. mf = &mfile[c.thdr.afid];
  276. rauth(mf);
  277. break;
  278. case Tflush:
  279. rflush();
  280. break;
  281. case Tattach:
  282. rattach(mf);
  283. break;
  284. case Twalk:
  285. rwalk(mf);
  286. break;
  287. case Topen:
  288. ropen(mf);
  289. break;
  290. case Tcreate:
  291. rcreate(mf);
  292. break;
  293. case Tread:
  294. rread(mf);
  295. break;
  296. case Twrite:
  297. rwrite(mf);
  298. break;
  299. case Tclunk:
  300. rclunk(mf);
  301. break;
  302. case Tremove:
  303. rremove(mf);
  304. break;
  305. case Tstat:
  306. rstat(mf);
  307. break;
  308. case Twstat:
  309. rwstat(mf);
  310. break;
  311. }
  312. if(statson){
  313. cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s;
  314. }
  315. goto loop;
  316. }
  317. void
  318. rversion(void)
  319. {
  320. if(messagesize > c.thdr.msize)
  321. messagesize = c.thdr.msize;
  322. c.thdr.msize = messagesize; /* set downstream size */
  323. delegate();
  324. }
  325. void
  326. rauth(Mfile *mf)
  327. {
  328. if(mf->busy)
  329. error("auth to used channel");
  330. if(delegate() == 0){
  331. mf->qid = s.rhdr.aqid;
  332. mf->busy = 1;
  333. }
  334. }
  335. void
  336. rflush(void) /* synchronous so easy */
  337. {
  338. sendreply(0);
  339. }
  340. void
  341. rattach(Mfile *mf)
  342. {
  343. if(delegate() == 0){
  344. mf->qid = s.rhdr.qid;
  345. mf->busy = 1;
  346. if (statson == 1){
  347. statson++;
  348. rootqid = mf->qid;
  349. }
  350. }
  351. }
  352. void
  353. rwalk(Mfile *mf)
  354. {
  355. Mfile *nmf;
  356. nmf = nil;
  357. if(statson
  358. && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path
  359. && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){
  360. /* This is the ctl file */
  361. nmf = &mfile[c.thdr.newfid];
  362. if(c.thdr.newfid != c.thdr.fid && nmf->busy)
  363. error("clone to used channel");
  364. nmf = &mfile[c.thdr.newfid];
  365. nmf->qid = ctlqid;
  366. nmf->busy = 1;
  367. c.rhdr.nwqid = 1;
  368. c.rhdr.wqid[0] = ctlqid;
  369. sendreply(0);
  370. return;
  371. }
  372. if(c.thdr.newfid != c.thdr.fid){
  373. if(c.thdr.newfid >= Nfid)
  374. error("clone nfid out of range");
  375. nmf = &mfile[c.thdr.newfid];
  376. if(nmf->busy)
  377. error("clone to used channel");
  378. nmf = &mfile[c.thdr.newfid];
  379. nmf->qid = mf->qid;
  380. nmf->busy = 1;
  381. mf = nmf; /* Walk mf */
  382. }
  383. if(delegate() < 0){ /* complete failure */
  384. if(nmf)
  385. nmf->busy = 0;
  386. return;
  387. }
  388. if(s.rhdr.nwqid == c.thdr.nwname){ /* complete success */
  389. if(s.rhdr.nwqid > 0)
  390. mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];
  391. return;
  392. }
  393. /* partial success; release fid */
  394. if(nmf)
  395. nmf->busy = 0;
  396. }
  397. void
  398. ropen(Mfile *mf)
  399. {
  400. if(statson && ctltest(mf)){
  401. /* Opening ctl file */
  402. if(c.thdr.mode != OREAD){
  403. sendreply("does not exist");
  404. return;
  405. }
  406. c.rhdr.qid = ctlqid;
  407. c.rhdr.iounit = 0;
  408. sendreply(0);
  409. genstats();
  410. return;
  411. }
  412. if(delegate() == 0){
  413. mf->qid = s.rhdr.qid;
  414. if(c.thdr.mode & OTRUNC)
  415. iget(&ic, mf->qid);
  416. }
  417. }
  418. void
  419. rcreate(Mfile *mf)
  420. {
  421. if(statson && ctltest(mf)){
  422. sendreply("exists");
  423. return;
  424. }
  425. if(delegate() == 0){
  426. mf->qid = s.rhdr.qid;
  427. mf->qid.vers++;
  428. }
  429. }
  430. void
  431. rclunk(Mfile *mf)
  432. {
  433. if(!mf->busy){
  434. sendreply(0);
  435. return;
  436. }
  437. mf->busy = 0;
  438. delegate();
  439. }
  440. void
  441. rremove(Mfile *mf)
  442. {
  443. if(statson && ctltest(mf)){
  444. sendreply("not removed");
  445. return;
  446. }
  447. mf->busy = 0;
  448. delegate();
  449. }
  450. void
  451. rread(Mfile *mf)
  452. {
  453. int cnt, done;
  454. int32_t n;
  455. int64_t off, first;
  456. char *cp;
  457. char data[MAXFDATA];
  458. Ibuf *b;
  459. off = c.thdr.offset;
  460. first = off;
  461. cnt = c.thdr.count;
  462. if(statson && ctltest(mf)){
  463. if(cnt > statlen-off)
  464. c.rhdr.count = statlen-off;
  465. else
  466. c.rhdr.count = cnt;
  467. if((int)c.rhdr.count < 0){
  468. sendreply("eof");
  469. return;
  470. }
  471. c.rhdr.data = statbuf + off;
  472. sendreply(0);
  473. return;
  474. }
  475. if(mf->qid.type & (QTDIR|QTAUTH)){
  476. delegate();
  477. if (statson) {
  478. cfsstat.ndirread++;
  479. if(c.rhdr.count > 0){
  480. cfsstat.bytesread += c.rhdr.count;
  481. cfsstat.bytesfromdirs += c.rhdr.count;
  482. }
  483. }
  484. return;
  485. }
  486. b = iget(&ic, mf->qid);
  487. if(b == 0){
  488. DPRINT(2, "delegating read\n");
  489. delegate();
  490. if (statson){
  491. cfsstat.ndelegateread++;
  492. if(c.rhdr.count > 0){
  493. cfsstat.bytesread += c.rhdr.count;
  494. cfsstat.bytesfromserver += c.rhdr.count;
  495. }
  496. }
  497. return;
  498. }
  499. cp = data;
  500. done = 0;
  501. while(cnt>0 && !done){
  502. if(off >= b->inode.length){
  503. DPRINT(2, "offset %lld greater than length %lld\n",
  504. off, b->inode.length);
  505. break;
  506. }
  507. n = fread(&ic, b, cp, off, cnt);
  508. if(n <= 0){
  509. n = -n;
  510. if(n==0 || n>cnt)
  511. n = cnt;
  512. DPRINT(2,
  513. "fetch %ld bytes of data from server at offset %lld\n",
  514. n, off);
  515. s.thdr.type = c.thdr.type;
  516. s.thdr.fid = c.thdr.fid;
  517. s.thdr.tag = c.thdr.tag;
  518. s.thdr.offset = off;
  519. s.thdr.count = n;
  520. if(statson)
  521. cfsstat.ndelegateread++;
  522. if(askserver() < 0){
  523. sendreply(s.rhdr.ename);
  524. return;
  525. }
  526. if(s.rhdr.count != n)
  527. done = 1;
  528. n = s.rhdr.count;
  529. if(n == 0){
  530. /* end of file */
  531. if(b->inode.length > off){
  532. DPRINT(2, "file %llu.%ld, length %lld\n",
  533. b->inode.qid.path,
  534. b->inode.qid.vers, off);
  535. b->inode.length = off;
  536. }
  537. break;
  538. }
  539. memmove(cp, s.rhdr.data, n);
  540. fwrite(&ic, b, cp, off, n);
  541. if (statson){
  542. cfsstat.bytestocache += n;
  543. cfsstat.bytesfromserver += n;
  544. }
  545. }else{
  546. DPRINT(2, "fetched %ld bytes from cache\n", n);
  547. if(statson)
  548. cfsstat.bytesfromcache += n;
  549. }
  550. cnt -= n;
  551. off += n;
  552. cp += n;
  553. }
  554. c.rhdr.data = data;
  555. c.rhdr.count = off - first;
  556. if(statson)
  557. cfsstat.bytesread += c.rhdr.count;
  558. sendreply(0);
  559. }
  560. void
  561. rwrite(Mfile *mf)
  562. {
  563. Ibuf *b;
  564. char buf[MAXFDATA];
  565. if(statson && ctltest(mf)){
  566. sendreply("read only");
  567. return;
  568. }
  569. if(mf->qid.type & (QTDIR|QTAUTH)){
  570. delegate();
  571. if(statson && c.rhdr.count > 0)
  572. cfsstat.byteswritten += c.rhdr.count;
  573. return;
  574. }
  575. memmove(buf, c.thdr.data, c.thdr.count);
  576. if(delegate() < 0)
  577. return;
  578. if(s.rhdr.count > 0)
  579. cfsstat.byteswritten += s.rhdr.count;
  580. /* don't modify our cache for append-only data; always read from server*/
  581. if(mf->qid.type & QTAPPEND)
  582. return;
  583. b = iget(&ic, mf->qid);
  584. if(b == 0)
  585. return;
  586. if (b->inode.length < c.thdr.offset + s.rhdr.count)
  587. b->inode.length = c.thdr.offset + s.rhdr.count;
  588. mf->qid.vers++;
  589. if (s.rhdr.count != c.thdr.count)
  590. syslog(0, "cfslog", "rhdr.count %u, thdr.count %u\n",
  591. s.rhdr.count, c.thdr.count);
  592. if(fwrite(&ic, b, buf, c.thdr.offset, s.rhdr.count) == s.rhdr.count){
  593. iinc(&ic, b);
  594. if(statson)
  595. cfsstat.bytestocache += s.rhdr.count;
  596. }
  597. }
  598. void
  599. rstat(Mfile *mf)
  600. {
  601. Dir d;
  602. if(statson && ctltest(mf)){
  603. genstats();
  604. d.qid = ctlqid;
  605. d.mode = 0444;
  606. d.length = statlen; /* would be nice to do better */
  607. d.name = "cfsctl";
  608. d.uid = "none";
  609. d.gid = "none";
  610. d.muid = "none";
  611. d.atime = time(nil);
  612. d.mtime = d.atime;
  613. c.rhdr.nstat = convD2M(&d, c.rhdr.stat,
  614. sizeof c.rhdr - (c.rhdr.stat - (uint8_t*)&c.rhdr));
  615. sendreply(0);
  616. return;
  617. }
  618. if(delegate() == 0){
  619. Ibuf *b;
  620. convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
  621. mf->qid = d.qid;
  622. b = iget(&ic, mf->qid);
  623. if(b)
  624. b->inode.length = d.length;
  625. }
  626. }
  627. void
  628. rwstat(Mfile *mf)
  629. {
  630. Ibuf *b;
  631. if(statson && ctltest(mf)){
  632. sendreply("read only");
  633. return;
  634. }
  635. delegate();
  636. if(b = iget(&ic, mf->qid))
  637. b->inode.length = MAXLEN;
  638. }
  639. void
  640. error(char *fmt, ...)
  641. {
  642. va_list arg;
  643. static char buf[2048];
  644. va_start(arg, fmt);
  645. vseprint(buf, buf+sizeof(buf), fmt, arg);
  646. va_end(arg);
  647. fprint(2, "%s: %s\n", argv0, buf);
  648. exits("error");
  649. }
  650. void
  651. warning(char *s)
  652. {
  653. fprint(2, "cfs: %s: %r\n", s);
  654. }
  655. /*
  656. * send a reply to the client
  657. */
  658. void
  659. sendreply(char *err)
  660. {
  661. if(err){
  662. c.rhdr.type = Rerror;
  663. c.rhdr.ename = err;
  664. }else{
  665. c.rhdr.type = c.thdr.type+1;
  666. c.rhdr.fid = c.thdr.fid;
  667. }
  668. c.rhdr.tag = c.thdr.tag;
  669. sendmsg(&c, &c.rhdr);
  670. }
  671. /*
  672. * send a request to the server, get the reply, and send that to
  673. * the client
  674. */
  675. int
  676. delegate(void)
  677. {
  678. int type;
  679. type = c.thdr.type;
  680. if(statson){
  681. cfsstat.sm[type].n++;
  682. cfsstat.sm[type].s = nsec();
  683. }
  684. sendmsg(&s, &c.thdr);
  685. rcvmsg(&s, &s.rhdr);
  686. if(statson)
  687. cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
  688. sendmsg(&c, &s.rhdr);
  689. return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
  690. }
  691. /*
  692. * send a request to the server and get a reply
  693. */
  694. int
  695. askserver(void)
  696. {
  697. int type;
  698. s.thdr.tag = c.thdr.tag;
  699. type = s.thdr.type;
  700. if(statson){
  701. cfsstat.sm[type].n++;
  702. cfsstat.sm[type].s = nsec();
  703. }
  704. sendmsg(&s, &s.thdr);
  705. rcvmsg(&s, &s.rhdr);
  706. if(statson)
  707. cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
  708. return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
  709. }
  710. /*
  711. * send/receive messages with logging
  712. */
  713. void
  714. sendmsg(P9fs *p, Fcall *f)
  715. {
  716. DPRINT(2, "->%s: %F\n", p->name, f);
  717. p->len = convS2M(f, datasnd, messagesize);
  718. if(p->len <= 0)
  719. error("convS2M");
  720. if(write(p->fd[1], datasnd, p->len)!=p->len)
  721. error("sendmsg");
  722. }
  723. void
  724. dump(uint8_t *p, int len)
  725. {
  726. fprint(2, "%d bytes", len);
  727. while(len-- > 0)
  728. fprint(2, " %.2x", *p++);
  729. fprint(2, "\n");
  730. }
  731. void
  732. rcvmsg(P9fs *p, Fcall *f)
  733. {
  734. int olen, rlen;
  735. char buf[128];
  736. olen = p->len;
  737. p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
  738. if(p->len <= 0){
  739. snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
  740. p->fd[0], p->len);
  741. error(buf);
  742. }
  743. if((rlen = convM2S(datarcv, p->len, f)) != p->len)
  744. error("rcvmsg format error, expected length %d, got %d",
  745. rlen, p->len);
  746. if(f->fid >= Nfid){
  747. fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
  748. mname[f->type]? mname[f->type]: "mystery", f->fid);
  749. dump((uint8_t*)datasnd, olen);
  750. dump((uint8_t*)datarcv, p->len);
  751. error("rcvmsg fid out of range");
  752. }
  753. DPRINT(2, "<-%s: %F\n", p->name, f);
  754. }
  755. int
  756. ctltest(Mfile *mf)
  757. {
  758. return mf->busy && mf->qid.type == ctlqid.type &&
  759. mf->qid.path == ctlqid.path;
  760. }
  761. void
  762. genstats(void)
  763. {
  764. int i;
  765. char *p;
  766. p = statbuf;
  767. p += snprint(p, sizeof statbuf+statbuf-p,
  768. " Client Server\n");
  769. p += snprint(p, sizeof statbuf+statbuf-p,
  770. " #calls Δ ms/call Δ #calls Δ ms/call Δ\n");
  771. for (i = 0; i < nelem(cfsstat.cm); i++)
  772. if(cfsstat.cm[i].n || cfsstat.sm[i].n) {
  773. p += snprint(p, sizeof statbuf+statbuf-p,
  774. "%7lud %7lud ", cfsstat.cm[i].n,
  775. cfsstat.cm[i].n - cfsprev.cm[i].n);
  776. if (cfsstat.cm[i].n)
  777. p += snprint(p, sizeof statbuf+statbuf-p,
  778. "%7.3f ", 0.000001*cfsstat.cm[i].t/
  779. cfsstat.cm[i].n);
  780. else
  781. p += snprint(p, sizeof statbuf+statbuf-p,
  782. " ");
  783. if(cfsstat.cm[i].n - cfsprev.cm[i].n)
  784. p += snprint(p, sizeof statbuf+statbuf-p,
  785. "%7.3f ", 0.000001*
  786. (cfsstat.cm[i].t - cfsprev.cm[i].t)/
  787. (cfsstat.cm[i].n - cfsprev.cm[i].n));
  788. else
  789. p += snprint(p, sizeof statbuf+statbuf-p,
  790. " ");
  791. p += snprint(p, sizeof statbuf+statbuf-p,
  792. "%7lud %7lud ", cfsstat.sm[i].n,
  793. cfsstat.sm[i].n - cfsprev.sm[i].n);
  794. if (cfsstat.sm[i].n)
  795. p += snprint(p, sizeof statbuf+statbuf-p,
  796. "%7.3f ", 0.000001*cfsstat.sm[i].t/
  797. cfsstat.sm[i].n);
  798. else
  799. p += snprint(p, sizeof statbuf+statbuf-p,
  800. " ");
  801. if(cfsstat.sm[i].n - cfsprev.sm[i].n)
  802. p += snprint(p, sizeof statbuf+statbuf-p,
  803. "%7.3f ", 0.000001*
  804. (cfsstat.sm[i].t - cfsprev.sm[i].t)/
  805. (cfsstat.sm[i].n - cfsprev.sm[i].n));
  806. else
  807. p += snprint(p, sizeof statbuf+statbuf-p,
  808. " ");
  809. p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
  810. mname[i]);
  811. }
  812. p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
  813. cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
  814. p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
  815. cfsstat.ndelegateread, cfsstat.ndelegateread -
  816. cfsprev.ndelegateread);
  817. p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
  818. cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
  819. p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
  820. cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
  821. p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
  822. cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
  823. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
  824. cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
  825. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
  826. cfsstat.byteswritten, cfsstat.byteswritten -
  827. cfsprev.byteswritten);
  828. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
  829. cfsstat.bytesfromserver, cfsstat.bytesfromserver -
  830. cfsprev.bytesfromserver);
  831. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
  832. cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
  833. cfsprev.bytesfromdirs);
  834. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
  835. cfsstat.bytesfromcache, cfsstat.bytesfromcache -
  836. cfsprev.bytesfromcache);
  837. p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
  838. cfsstat.bytestocache, cfsstat.bytestocache -
  839. cfsprev.bytestocache);
  840. statlen = p - statbuf;
  841. cfsprev = cfsstat;
  842. }