statsrv.c 10 KB

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