cfs.c 17 KB

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