statsrv.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #define Extern extern
  6. #include "statfs.h"
  7. char Ebadfid[] = "Bad fid";
  8. char Enotdir[] ="Not a directory";
  9. char Edupfid[] = "Fid already in use";
  10. char Eopen[] = "Fid already opened";
  11. char Exmnt[] = "Cannot .. past mount point";
  12. char Enoauth[] = "iostats: Authentication failed";
  13. char Ebadver[] = "Unrecognized 9P version";
  14. int
  15. okfile(char *s, int mode)
  16. {
  17. if(strncmp(s, "/fd/", 3) == 0){
  18. /* 0, 1, and 2 we handle ourselves */
  19. if(s[4]=='/' || atoi(s+4) > 2)
  20. return 0;
  21. return 1;
  22. }
  23. if(strncmp(s, "/net/ssl", 8) == 0)
  24. return 0;
  25. if(strncmp(s, "/net/tls", 8) == 0)
  26. return 0;
  27. if(strncmp(s, "/srv/", 5) == 0 && ((mode&3) == OWRITE || (mode&3) == ORDWR))
  28. return 0;
  29. return 1;
  30. }
  31. void
  32. Xversion(Fsrpc *r)
  33. {
  34. Fcall thdr;
  35. Rpc *rpc;
  36. ulong t;
  37. t = msec();
  38. if(r->work.msize > IOHDRSZ+Maxfdata)
  39. thdr.msize = IOHDRSZ+Maxfdata;
  40. else
  41. thdr.msize = r->work.msize;
  42. myiounit = thdr.msize - IOHDRSZ;
  43. if(strncmp(r->work.version, "9P2000", 6) != 0){
  44. reply(&r->work, &thdr, Ebadver);
  45. r->busy = 0;
  46. return;
  47. }
  48. thdr.version = "9P2000";
  49. /* BUG: should clunk all fids */
  50. reply(&r->work, &thdr, 0);
  51. r->busy = 0;
  52. t = msec()-t;
  53. rpc = &stats->rpc[Tversion];
  54. rpc->time += t;
  55. if(t < rpc->loms)
  56. rpc->loms = t;
  57. if(t > rpc->hims)
  58. rpc->hims = t;
  59. }
  60. void
  61. Xauth(Fsrpc *r)
  62. {
  63. Fcall thdr;
  64. Rpc *rpc;
  65. ulong t;
  66. t = msec();
  67. reply(&r->work, &thdr, Enoauth);
  68. r->busy = 0;
  69. t = msec()-t;
  70. rpc = &stats->rpc[Tauth];
  71. rpc->time += t;
  72. if(t < rpc->loms)
  73. rpc->loms = t;
  74. if(t > rpc->hims)
  75. rpc->hims = t;
  76. }
  77. void
  78. Xflush(Fsrpc *r)
  79. {
  80. Fsrpc *t, *e;
  81. Fcall thdr;
  82. e = &Workq[Nr_workbufs];
  83. for(t = Workq; t < e; t++) {
  84. if(t->work.tag == r->work.oldtag) {
  85. DEBUG(2, "\tQ busy %d pid %d can %d\n", t->busy, t->pid, t->canint);
  86. if(t->busy && t->pid) {
  87. t->flushtag = r->work.tag;
  88. DEBUG(2, "\tset flushtag %d\n", r->work.tag);
  89. if(t->canint)
  90. postnote(PNPROC, t->pid, "flush");
  91. r->busy = 0;
  92. return;
  93. }
  94. }
  95. }
  96. reply(&r->work, &thdr, 0);
  97. DEBUG(2, "\tflush reply\n");
  98. r->busy = 0;
  99. }
  100. void
  101. Xattach(Fsrpc *r)
  102. {
  103. Fcall thdr;
  104. Fid *f;
  105. Rpc *rpc;
  106. ulong t;
  107. t = msec();
  108. f = newfid(r->work.fid);
  109. if(f == 0) {
  110. reply(&r->work, &thdr, Ebadfid);
  111. r->busy = 0;
  112. return;
  113. }
  114. f->f = root;
  115. thdr.qid = f->f->qid;
  116. reply(&r->work, &thdr, 0);
  117. r->busy = 0;
  118. t = msec()-t;
  119. rpc = &stats->rpc[Tattach];
  120. rpc->time += t;
  121. if(t < rpc->loms)
  122. rpc->loms = t;
  123. if(t > rpc->hims)
  124. rpc->hims = t;
  125. }
  126. void
  127. Xwalk(Fsrpc *r)
  128. {
  129. char errbuf[ERRMAX], *err;
  130. Fcall thdr;
  131. Fid *f, *n;
  132. File *nf;
  133. Rpc *rpc;
  134. ulong t;
  135. int i;
  136. t = msec();
  137. f = getfid(r->work.fid);
  138. if(f == 0) {
  139. reply(&r->work, &thdr, Ebadfid);
  140. r->busy = 0;
  141. return;
  142. }
  143. n = nil;
  144. if(r->work.newfid != r->work.fid){
  145. n = newfid(r->work.newfid);
  146. if(n == 0) {
  147. reply(&r->work, &thdr, Edupfid);
  148. r->busy = 0;
  149. return;
  150. }
  151. n->f = f->f;
  152. f = n; /* walk new guy */
  153. }
  154. thdr.nwqid = 0;
  155. err = nil;
  156. for(i=0; i<r->work.nwname; i++){
  157. if(i >= MAXWELEM)
  158. break;
  159. if(strcmp(r->work.wname[i], "..") == 0) {
  160. if(f->f->parent == 0) {
  161. err = Exmnt;
  162. break;
  163. }
  164. f->f = f->f->parent;
  165. thdr.wqid[thdr.nwqid++] = f->f->qid;
  166. continue;
  167. }
  168. nf = file(f->f, r->work.wname[i]);
  169. if(nf == 0) {
  170. errstr(errbuf, sizeof errbuf);
  171. err = errbuf;
  172. break;
  173. }
  174. f->f = nf;
  175. thdr.wqid[thdr.nwqid++] = nf->qid;
  176. continue;
  177. }
  178. if(err == nil && thdr.nwqid == 0 && r->work.nwname > 0)
  179. err = "file does not exist";
  180. if(n != nil && (err != 0 || thdr.nwqid < r->work.nwname)){
  181. /* clunk the new fid, which is the one we walked */
  182. freefid(n->nr);
  183. }
  184. if(thdr.nwqid > 0)
  185. err = nil;
  186. reply(&r->work, &thdr, err);
  187. r->busy = 0;
  188. t = msec()-t;
  189. rpc = &stats->rpc[Twalk];
  190. rpc->time += t;
  191. if(t < rpc->loms)
  192. rpc->loms = t;
  193. if(t > rpc->hims)
  194. rpc->hims = t;
  195. }
  196. void
  197. Xclunk(Fsrpc *r)
  198. {
  199. Fcall thdr;
  200. Fid *f;
  201. Rpc *rpc;
  202. ulong t;
  203. int fid;
  204. t = msec();
  205. f = getfid(r->work.fid);
  206. if(f == 0) {
  207. reply(&r->work, &thdr, Ebadfid);
  208. r->busy = 0;
  209. return;
  210. }
  211. if(f->fid >= 0)
  212. close(f->fid);
  213. fid = r->work.fid;
  214. reply(&r->work, &thdr, 0);
  215. r->busy = 0;
  216. t = msec()-t;
  217. rpc = &stats->rpc[Tclunk];
  218. rpc->time += t;
  219. if(t < rpc->loms)
  220. rpc->loms = t;
  221. if(t > rpc->hims)
  222. rpc->hims = t;
  223. if(f->nread || f->nwrite)
  224. fidreport(f);
  225. freefid(fid);
  226. }
  227. void
  228. Xstat(Fsrpc *r)
  229. {
  230. char err[ERRMAX], path[128];
  231. uchar statbuf[STATMAX];
  232. Fcall thdr;
  233. Fid *f;
  234. int s;
  235. Rpc *rpc;
  236. ulong t;
  237. t = msec();
  238. f = getfid(r->work.fid);
  239. if(f == 0) {
  240. reply(&r->work, &thdr, Ebadfid);
  241. r->busy = 0;
  242. return;
  243. }
  244. makepath(path, f->f, "");
  245. if(!okfile(path, -1)){
  246. snprint(err, sizeof err, "iostats: can't simulate %s", path);
  247. reply(&r->work, &thdr, err);
  248. r->busy = 0;
  249. return;
  250. }
  251. if(f->fid >= 0)
  252. s = fstat(f->fid, statbuf, sizeof statbuf);
  253. else
  254. s = stat(path, statbuf, sizeof statbuf);
  255. if(s < 0) {
  256. errstr(err, sizeof err);
  257. reply(&r->work, &thdr, err);
  258. r->busy = 0;
  259. return;
  260. }
  261. thdr.stat = statbuf;
  262. thdr.nstat = s;
  263. reply(&r->work, &thdr, 0);
  264. r->busy = 0;
  265. t = msec()-t;
  266. rpc = &stats->rpc[Tstat];
  267. rpc->time += t;
  268. if(t < rpc->loms)
  269. rpc->loms = t;
  270. if(t > rpc->hims)
  271. rpc->hims = t;
  272. }
  273. void
  274. Xcreate(Fsrpc *r)
  275. {
  276. char err[ERRMAX], path[128];
  277. Fcall thdr;
  278. Fid *f;
  279. File *nf;
  280. Rpc *rpc;
  281. ulong t;
  282. t = msec();
  283. f = getfid(r->work.fid);
  284. if(f == 0) {
  285. reply(&r->work, &thdr, Ebadfid);
  286. r->busy = 0;
  287. return;
  288. }
  289. makepath(path, f->f, r->work.name);
  290. f->fid = create(path, r->work.mode, r->work.perm);
  291. if(f->fid < 0) {
  292. errstr(err, sizeof err);
  293. reply(&r->work, &thdr, err);
  294. r->busy = 0;
  295. return;
  296. }
  297. nf = file(f->f, r->work.name);
  298. if(nf == 0) {
  299. errstr(err, sizeof err);
  300. reply(&r->work, &thdr, err);
  301. r->busy = 0;
  302. return;
  303. }
  304. f->mode = r->work.mode;
  305. f->f = nf;
  306. thdr.iounit = myiounit;
  307. thdr.qid = f->f->qid;
  308. reply(&r->work, &thdr, 0);
  309. r->busy = 0;
  310. t = msec()-t;
  311. rpc = &stats->rpc[Tcreate];
  312. rpc->time += t;
  313. if(t < rpc->loms)
  314. rpc->loms = t;
  315. if(t > rpc->hims)
  316. rpc->hims = t;
  317. }
  318. void
  319. Xremove(Fsrpc *r)
  320. {
  321. char err[ERRMAX], path[128];
  322. Fcall thdr;
  323. Fid *f;
  324. ulong t;
  325. Rpc *rpc;
  326. t = msec();
  327. f = getfid(r->work.fid);
  328. if(f == 0) {
  329. reply(&r->work, &thdr, Ebadfid);
  330. r->busy = 0;
  331. return;
  332. }
  333. makepath(path, f->f, "");
  334. DEBUG(2, "\tremove: %s\n", path);
  335. if(remove(path) < 0) {
  336. errstr(err, sizeof err);
  337. reply(&r->work, &thdr, err);
  338. freefid(r->work.fid);
  339. r->busy = 0;
  340. return;
  341. }
  342. f->f->inval = 1;
  343. if(f->fid >= 0)
  344. close(f->fid);
  345. freefid(r->work.fid);
  346. reply(&r->work, &thdr, 0);
  347. r->busy = 0;
  348. t = msec()-t;
  349. rpc = &stats->rpc[Tremove];
  350. rpc->time += t;
  351. if(t < rpc->loms)
  352. rpc->loms = t;
  353. if(t > rpc->hims)
  354. rpc->hims = t;
  355. }
  356. void
  357. Xwstat(Fsrpc *r)
  358. {
  359. char err[ERRMAX], path[128];
  360. Fcall thdr;
  361. Fid *f;
  362. int s;
  363. ulong t;
  364. Rpc *rpc;
  365. t = msec();
  366. f = getfid(r->work.fid);
  367. if(f == 0) {
  368. reply(&r->work, &thdr, Ebadfid);
  369. r->busy = 0;
  370. return;
  371. }
  372. if(f->fid >= 0)
  373. s = fwstat(f->fid, r->work.stat, r->work.nstat);
  374. else {
  375. makepath(path, f->f, "");
  376. s = wstat(path, r->work.stat, r->work.nstat);
  377. }
  378. if(s < 0) {
  379. errstr(err, sizeof err);
  380. reply(&r->work, &thdr, err);
  381. }
  382. else
  383. reply(&r->work, &thdr, 0);
  384. r->busy = 0;
  385. t = msec()-t;
  386. rpc = &stats->rpc[Twstat];
  387. rpc->time += t;
  388. if(t < rpc->loms)
  389. rpc->loms = t;
  390. if(t > rpc->hims)
  391. rpc->hims = t;
  392. }
  393. void
  394. slave(Fsrpc *f)
  395. {
  396. Proc *p;
  397. int pid;
  398. static int nproc;
  399. for(;;) {
  400. for(p = Proclist; p; p = p->next) {
  401. if(p->busy == 0) {
  402. f->pid = p->pid;
  403. p->busy = 1;
  404. pid = rendezvous(p->pid, (ulong)f);
  405. if(pid != p->pid)
  406. fatal("rendezvous sync fail");
  407. return;
  408. }
  409. }
  410. if(++nproc > MAXPROC)
  411. fatal("too many procs");
  412. pid = rfork(RFPROC|RFMEM);
  413. if(pid < 0)
  414. fatal("rfork");
  415. if(pid == 0)
  416. blockingslave();
  417. p = malloc(sizeof(Proc));
  418. if(p == 0)
  419. fatal("out of memory");
  420. p->busy = 0;
  421. p->pid = pid;
  422. p->next = Proclist;
  423. Proclist = p;
  424. rendezvous(pid, (ulong)p);
  425. }
  426. }
  427. void
  428. blockingslave(void)
  429. {
  430. Proc *m;
  431. int pid;
  432. Fsrpc *p;
  433. Fcall thdr;
  434. notify(flushaction);
  435. pid = getpid();
  436. m = (Proc*)rendezvous(pid, 0);
  437. for(;;) {
  438. p = (Fsrpc*)rendezvous(pid, pid);
  439. if((int)p == ~0) /* Interrupted */
  440. continue;
  441. DEBUG(2, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
  442. if(p->flushtag != NOTAG)
  443. return;
  444. switch(p->work.type) {
  445. case Tread:
  446. slaveread(p);
  447. break;
  448. case Twrite:
  449. slavewrite(p);
  450. break;
  451. case Topen:
  452. slaveopen(p);
  453. break;
  454. default:
  455. reply(&p->work, &thdr, "exportfs: slave type error");
  456. }
  457. if(p->flushtag != NOTAG) {
  458. p->work.type = Tflush;
  459. p->work.tag = p->flushtag;
  460. reply(&p->work, &thdr, 0);
  461. }
  462. p->busy = 0;
  463. m->busy = 0;
  464. }
  465. }
  466. void
  467. slaveopen(Fsrpc *p)
  468. {
  469. char err[ERRMAX], path[128];
  470. Fcall *work, thdr;
  471. Fid *f;
  472. ulong t;
  473. Rpc *rpc;
  474. work = &p->work;
  475. t = msec();
  476. f = getfid(work->fid);
  477. if(f == 0) {
  478. reply(work, &thdr, Ebadfid);
  479. return;
  480. }
  481. if(f->fid >= 0) {
  482. close(f->fid);
  483. f->fid = -1;
  484. }
  485. makepath(path, f->f, "");
  486. DEBUG(2, "\topen: %s %d\n", path, work->mode);
  487. p->canint = 1;
  488. if(p->flushtag != NOTAG)
  489. return;
  490. if(!okfile(path, work->mode)){
  491. snprint(err, sizeof err, "iostats can't simulate %s", path);
  492. reply(work, &thdr, err);
  493. return;
  494. }
  495. /* There is a race here I ignore because there are no locks */
  496. f->fid = open(path, work->mode);
  497. p->canint = 0;
  498. if(f->fid < 0) {
  499. errstr(err, sizeof err);
  500. reply(work, &thdr, err);
  501. return;
  502. }
  503. DEBUG(2, "\topen: fd %d\n", f->fid);
  504. f->mode = work->mode;
  505. thdr.iounit = myiounit;
  506. thdr.qid = f->f->qid;
  507. reply(work, &thdr, 0);
  508. t = msec()-t;
  509. rpc = &stats->rpc[Topen];
  510. rpc->time += t;
  511. if(t < rpc->loms)
  512. rpc->loms = t;
  513. if(t > rpc->hims)
  514. rpc->hims = t;
  515. }
  516. void
  517. slaveread(Fsrpc *p)
  518. {
  519. char data[Maxfdata], err[ERRMAX];
  520. Fcall *work, thdr;
  521. Fid *f;
  522. int n, r;
  523. ulong t;
  524. Rpc *rpc;
  525. work = &p->work;
  526. t = msec();
  527. f = getfid(work->fid);
  528. if(f == 0) {
  529. reply(work, &thdr, Ebadfid);
  530. return;
  531. }
  532. n = (work->count > Maxfdata) ? Maxfdata : work->count;
  533. p->canint = 1;
  534. if(p->flushtag != NOTAG)
  535. return;
  536. /* can't just call pread, since directories must update the offset */
  537. if(f->f->qid.type&QTDIR){
  538. if(work->offset != f->offset){
  539. if(work->offset != 0){
  540. snprint(err, sizeof err, "can't seek in directory from %lld to %lld", f->offset, work->offset);
  541. reply(work, &thdr, err);
  542. return;
  543. }
  544. if(seek(f->fid, 0, 0) != 0){
  545. errstr(err, sizeof err);
  546. reply(work, &thdr, err);
  547. return;
  548. }
  549. f->offset = 0;
  550. }
  551. r = read(f->fid, data, n);
  552. if(r > 0)
  553. f->offset += r;
  554. }else
  555. r = pread(f->fid, data, n, work->offset);
  556. p->canint = 0;
  557. if(r < 0) {
  558. errstr(err, sizeof err);
  559. reply(work, &thdr, err);
  560. return;
  561. }
  562. DEBUG(2, "\tread: fd=%d %d bytes\n", f->fid, r);
  563. thdr.data = data;
  564. thdr.count = r;
  565. stats->totread += r;
  566. f->nread++;
  567. f->bread += r;
  568. reply(work, &thdr, 0);
  569. t = msec()-t;
  570. rpc = &stats->rpc[Tread];
  571. rpc->time += t;
  572. if(t < rpc->loms)
  573. rpc->loms = t;
  574. if(t > rpc->hims)
  575. rpc->hims = t;
  576. }
  577. void
  578. slavewrite(Fsrpc *p)
  579. {
  580. char err[ERRMAX];
  581. Fcall *work, thdr;
  582. Fid *f;
  583. int n;
  584. ulong t;
  585. Rpc *rpc;
  586. work = &p->work;
  587. t = msec();
  588. f = getfid(work->fid);
  589. if(f == 0) {
  590. reply(work, &thdr, Ebadfid);
  591. return;
  592. }
  593. n = (work->count > Maxfdata) ? Maxfdata : work->count;
  594. p->canint = 1;
  595. if(p->flushtag != NOTAG)
  596. return;
  597. n = pwrite(f->fid, work->data, n, work->offset);
  598. p->canint = 0;
  599. if(n < 0) {
  600. errstr(err, sizeof err);
  601. reply(work, &thdr, err);
  602. return;
  603. }
  604. DEBUG(2, "\twrite: %d bytes fd=%d\n", n, f->fid);
  605. thdr.count = n;
  606. f->nwrite++;
  607. f->bwrite += n;
  608. stats->totwrite += n;
  609. reply(work, &thdr, 0);
  610. t = msec()-t;
  611. rpc = &stats->rpc[Twrite];
  612. rpc->time += t;
  613. if(t < rpc->loms)
  614. rpc->loms = t;
  615. if(t > rpc->hims)
  616. rpc->hims = t;
  617. }
  618. void
  619. reopen(Fid *f)
  620. {
  621. USED(f);
  622. fatal("reopen");
  623. }
  624. void
  625. flushaction(void *a, char *cause)
  626. {
  627. USED(a);
  628. if(strncmp(cause, "kill", 4) == 0)
  629. noted(NDFLT);
  630. noted(NCONT);
  631. }