statsrv.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  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 %p 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. int r;
  348. Proc *p;
  349. uintptr pid;
  350. static int nproc;
  351. for(;;) {
  352. for(p = Proclist; p; p = p->next) {
  353. if(p->busy == 0) {
  354. f->pid = p->pid;
  355. p->busy = 1;
  356. pid = (uintptr)rendezvous((void*)p->pid, f);
  357. if(pid != p->pid)
  358. fatal("rendezvous sync fail");
  359. return;
  360. }
  361. }
  362. if(++nproc > MAXPROC)
  363. fatal("too many procs");
  364. r = rfork(RFPROC|RFMEM);
  365. if(r < 0)
  366. fatal("rfork");
  367. if(r == 0)
  368. blockingslave();
  369. p = malloc(sizeof(Proc));
  370. if(p == 0)
  371. fatal("out of memory");
  372. p->busy = 0;
  373. p->pid = r;
  374. p->next = Proclist;
  375. Proclist = p;
  376. rendezvous((void*)p->pid, p);
  377. }
  378. }
  379. void
  380. blockingslave(void)
  381. {
  382. Proc *m;
  383. uintptr pid;
  384. Fsrpc *p;
  385. Fcall thdr;
  386. notify(flushaction);
  387. pid = getpid();
  388. m = rendezvous((void*)pid, 0);
  389. for(;;) {
  390. p = rendezvous((void*)pid, (void*)pid);
  391. if(p == (void*)~0) /* Interrupted */
  392. continue;
  393. DEBUG(2, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid);
  394. if(p->flushtag != NOTAG)
  395. return;
  396. switch(p->work.type) {
  397. case Tread:
  398. slaveread(p);
  399. break;
  400. case Twrite:
  401. slavewrite(p);
  402. break;
  403. case Topen:
  404. slaveopen(p);
  405. break;
  406. default:
  407. reply(&p->work, &thdr, "exportfs: slave type error");
  408. }
  409. if(p->flushtag != NOTAG) {
  410. p->work.type = Tflush;
  411. p->work.tag = p->flushtag;
  412. reply(&p->work, &thdr, 0);
  413. }
  414. p->busy = 0;
  415. m->busy = 0;
  416. }
  417. }
  418. void
  419. slaveopen(Fsrpc *p)
  420. {
  421. char err[ERRMAX], path[128];
  422. Fcall *work, thdr;
  423. Fid *f;
  424. vlong t;
  425. work = &p->work;
  426. t = nsec();
  427. f = getfid(work->fid);
  428. if(f == 0) {
  429. reply(work, &thdr, Ebadfid);
  430. return;
  431. }
  432. if(f->fid >= 0) {
  433. close(f->fid);
  434. f->fid = -1;
  435. }
  436. makepath(path, f->f, "");
  437. DEBUG(2, "\topen: %s %d\n", path, work->mode);
  438. p->canint = 1;
  439. if(p->flushtag != NOTAG)
  440. return;
  441. if(!okfile(path, work->mode)){
  442. snprint(err, sizeof err, "iostats can't simulate %s", path);
  443. reply(work, &thdr, err);
  444. return;
  445. }
  446. /* There is a race here I ignore because there are no locks */
  447. f->fid = open(path, work->mode);
  448. p->canint = 0;
  449. if(f->fid < 0) {
  450. errstr(err, sizeof err);
  451. reply(work, &thdr, err);
  452. return;
  453. }
  454. DEBUG(2, "\topen: fd %d\n", f->fid);
  455. f->mode = work->mode;
  456. thdr.iounit = myiounit;
  457. thdr.qid = f->f->qid;
  458. reply(work, &thdr, 0);
  459. update(&stats->rpc[Topen], t);
  460. }
  461. void
  462. slaveread(Fsrpc *p)
  463. {
  464. char data[Maxfdata], err[ERRMAX];
  465. Fcall *work, thdr;
  466. Fid *f;
  467. int n, r;
  468. vlong t;
  469. work = &p->work;
  470. t = nsec();
  471. f = getfid(work->fid);
  472. if(f == 0) {
  473. reply(work, &thdr, Ebadfid);
  474. return;
  475. }
  476. n = (work->count > Maxfdata) ? Maxfdata : work->count;
  477. p->canint = 1;
  478. if(p->flushtag != NOTAG)
  479. return;
  480. /* can't just call pread, since directories must update the offset */
  481. if(f->f->qid.type&QTDIR){
  482. if(work->offset != f->offset){
  483. if(work->offset != 0){
  484. snprint(err, sizeof err, "can't seek in directory from %lld to %lld", f->offset, work->offset);
  485. reply(work, &thdr, err);
  486. return;
  487. }
  488. if(seek(f->fid, 0, 0) != 0){
  489. errstr(err, sizeof err);
  490. reply(work, &thdr, err);
  491. return;
  492. }
  493. f->offset = 0;
  494. }
  495. r = read(f->fid, data, n);
  496. if(r > 0)
  497. f->offset += r;
  498. }else
  499. r = pread(f->fid, data, n, work->offset);
  500. p->canint = 0;
  501. if(r < 0) {
  502. errstr(err, sizeof err);
  503. reply(work, &thdr, err);
  504. return;
  505. }
  506. DEBUG(2, "\tread: fd=%d %d bytes\n", f->fid, r);
  507. thdr.data = data;
  508. thdr.count = r;
  509. stats->totread += r;
  510. f->nread++;
  511. f->bread += r;
  512. reply(work, &thdr, 0);
  513. update(&stats->rpc[Tread], t);
  514. }
  515. void
  516. slavewrite(Fsrpc *p)
  517. {
  518. char err[ERRMAX];
  519. Fcall *work, thdr;
  520. Fid *f;
  521. int n;
  522. vlong t;
  523. work = &p->work;
  524. t = nsec();
  525. f = getfid(work->fid);
  526. if(f == 0) {
  527. reply(work, &thdr, Ebadfid);
  528. return;
  529. }
  530. n = (work->count > Maxfdata) ? Maxfdata : work->count;
  531. p->canint = 1;
  532. if(p->flushtag != NOTAG)
  533. return;
  534. n = pwrite(f->fid, work->data, n, work->offset);
  535. p->canint = 0;
  536. if(n < 0) {
  537. errstr(err, sizeof err);
  538. reply(work, &thdr, err);
  539. return;
  540. }
  541. DEBUG(2, "\twrite: %d bytes fd=%d\n", n, f->fid);
  542. thdr.count = n;
  543. f->nwrite++;
  544. f->bwrite += n;
  545. stats->totwrite += n;
  546. reply(work, &thdr, 0);
  547. update(&stats->rpc[Twrite], t);
  548. }
  549. void
  550. reopen(Fid *f)
  551. {
  552. USED(f);
  553. fatal("reopen");
  554. }
  555. void
  556. flushaction(void *a, char *cause)
  557. {
  558. USED(a);
  559. if(strncmp(cause, "kill", 4) == 0)
  560. noted(NDFLT);
  561. noted(NCONT);
  562. }