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