cfs.c 17 KB

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