cfs.c 16 KB

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