xref: /plan9/sys/src/cmd/disk/kfs/main.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1 #include	"all.h"
2 
3 int	sfd;
4 int	cmdmode = 0660;
5 int	rfd;
6 int	chat;
7 extern	char *wrenfile;
8 extern	int nwren;
9 char	*myname;
10 int	cmdfd;
11 int	writeallow;	/* never on; for compatibility with fs */
12 int	wstatallow;
13 int	noauth;
14 Nvrsafe	nvr;
15 int	srvfd(char*, int, int);
16 void	usage(void);
17 void	confinit(void);
18 Chan	*chaninit(char*);
19 void	consinit(void);
20 
21 void
22 main(int argc, char *argv[])
23 {
24 	Filsys *fs;
25 	int i, ream, fsok;
26 	int newbufsize, nocheck;
27 	char buf[NAMELEN];
28 
29 	progname = "kfs";
30 	procname = "init";
31 
32 	/*
33 	 * insulate from invokers environment
34 	 */
35 	rfork(RFNAMEG|RFNOTEG|RFREND);
36 
37 	confinit();
38 	sfd = -1;
39 	ream = 0;
40 	newbufsize = 0;
41 	nocheck = 0;
42 	wrenfile = "/dev/sdC0/fs";
43 	buf[0] = '\0';
44 	ARGBEGIN{
45 	case 'b':
46 		newbufsize = atol(ARGF());
47 		break;
48 	case 'c':
49 		nocheck = 1;
50 		break;
51 	case 'f':
52 		wrenfile = ARGF();
53 		break;
54 	case 'm':
55 		nwren = atol(ARGF());
56 		break;
57 	case 'n':
58 		strncpy(buf, ARGF(), NAMELEN-1);
59 		buf[NAMELEN-1] = '\0';
60 		break;
61 	case 'p':
62 		cmdmode = atol(ARGF());
63 		break;
64 	case 'r':
65 		ream = 1;
66 		break;
67 	case 's':
68 		sfd = 0;
69 		rfd = 1;
70 		break;
71 	case 'B':
72 		conf.niobuf = strtoul(ARGF(), 0, 0);
73 		break;
74 	case 'C':
75 		chat = 1;
76 		break;
77 	default:
78 		usage();
79 	}ARGEND
80 
81 	if(argc != 0)
82 		usage();
83 
84 	cmdfd = 2;
85 
86 	formatinit();
87 	sublockinit();
88 
89 	if(buf[0])
90 		sprint(service, "kfs.%s", buf);
91 	else
92 		strcpy(service, "kfs");
93 	chan = chaninit(service);
94 	consinit();
95 	tlocks = ialloc(NTLOCK * sizeof *tlocks);
96 	uid = ialloc(conf.nuid * sizeof(*uid));
97 	uidspace = ialloc(conf.uidspace * sizeof(*uidspace));
98 	gidspace = ialloc(conf.gidspace * sizeof(*gidspace));
99 
100 	/*
101 	 * init global locks
102 	 */
103 	wlock(&mainlock); wunlock(&mainlock);
104 
105 	/*
106 	 * init the file system, ream it if needed, and get the block sizes
107 	 */
108 	ream = fsinit(ream, newbufsize);
109 	iobufinit();
110 	for(fs=filesys; fs->name; fs++)
111 		if(fs->flags & FREAM){		/* set by fsinit if reamed */
112 			ream++;
113 			rootream(fs->dev, getraddr(fs->dev));
114 			superream(fs->dev, superaddr(fs->dev));
115 		}
116 
117 	boottime = time(nil);
118 
119 	consserve();
120 	fsok = superok(filesys[0].dev, superaddr(filesys[0].dev), 0);
121 	if(!nocheck && !ream && !fsok)
122 		cmd_exec("check fq");
123 
124 	/*
125 	 * start up procs
126 	 */
127 	for(i=0; i<conf.nserve; i++)
128 		startproc(serve, "srv");
129 
130 	startproc(syncproc, "sync");
131 
132 	exits(0);
133 }
134 
135 Chan *
136 getmsg(Chan *chan, char *buf, Fcall *f, int *n)
137 {
138 	int fd;
139 
140 	fd = chan->chan;
141 	for(;;){
142 		*n = read(fd, buf, MAXMSG + MAXDAT);
143 		if(chat)
144 			print("read msg %d\n", *n);
145 		if(*n == 0){
146 			if(chan != cons.srvchan)
147 				return 0;
148 			continue;
149 		}
150 		if(*n < 0)
151 			return 0;
152 		if(convM2S(buf, f, *n))
153 			return chan;
154 		if(chat)
155 			print("bad convM2S\n");
156 	}
157 	return 0;
158 }
159 
160 void
161 send(Chan *c, char *buf, int n)
162 {
163 	int fd, m;
164 
165 	fd = c->chan;
166 	for(;;){
167 		m = write(fd, buf, n);
168 		if(m == n)
169 			return;
170 	}
171 }
172 
173 /*
174  * main filesystem server loop.
175  * entered by many processes.
176  * they wait for messages and
177  * then process them.
178  */
179 void
180 doserve(Chan* chan)
181 {
182 	Chan *cp;
183 	Fcall fi, fo;
184 	char msgbuf[MAXMSG + MAXDAT];
185 	int t, n;
186 
187 loop:
188 	cp = getmsg(chan, msgbuf, &fi, &n);
189 	if(!cp){
190 		if(chan == cons.chan || chan == cons.srvchan)
191 			panic("input channel read error");
192 		return;
193 	}
194 
195 	if(chat)
196 		print("%A\n", &fi);
197 
198 	/*
199 	 * simple syntax checks.
200 	 */
201 	t = fi.type;
202 	if(t < 0 || t >= MAXSYSCALL || (t&1) || !p9call[t]){
203 		print("bad message type\n");
204 		fo.tag = fi.tag;
205 		fo.type = Terror+1;
206 		strncpy(fo.ename, "unknown message type", sizeof(fo.ename));
207 		goto reply;
208 	}
209 
210 	/*
211 	 * set up reply message
212 	 */
213 	fo.err = 0;
214 	if(t == Tread)
215 		fo.data = msgbuf + 8;
216 
217 	/*
218 	 * stats
219 	 */
220 	cons.work.count++;
221 	cons.rate.count += n;
222 
223 	/*
224 	 * call the file system
225 	 */
226 	rlock(&mainlock);
227 	rlock(&cp->reflock);
228 
229 	(*p9call[t])(cp, &fi, &fo);
230 
231 	runlock(&cp->reflock);
232 	runlock(&mainlock);
233 
234 	fo.type = t + 1;
235 	fo.tag = fi.tag;
236 
237 	if(fo.err) {
238 		if(CHAT(cp))
239 			print("	error: %s\n", errstring[fo.err]);
240 		fo.type = Terror+1;
241 		strncpy(fo.ename, errstring[fo.err], sizeof(fo.ename));
242 	}
243 
244 reply:
245 	if(chat)
246 		print("%A\n", &fo);
247 	n = convS2M(&fo, msgbuf);
248 	if(!n) {
249 		print("bad S2M convers\n");
250 		print("type=%d count=%d\n", msgbuf[0], n);
251 		print(" %.2x %.2x %.2x %.2x\n",
252 			msgbuf[1]&0xff, msgbuf[2]&0xff,
253 			msgbuf[3]&0xff, msgbuf[4]&0xff);
254 		print(" %.2x %.2x %.2x %.2x\n",
255 			msgbuf[5]&0xff, msgbuf[6]&0xff,
256 			msgbuf[7]&0xff, msgbuf[8]&0xff);
257 		print(" %.2x %.2x %.2x %.2x\n",
258 			msgbuf[9]&0xff, msgbuf[10]&0xff,
259 			msgbuf[11]&0xff, msgbuf[12]&0xff);
260 	}else{
261 		send(cp, msgbuf, n);
262 		cons.rate.count += n;
263 	}
264 	goto loop;
265 }
266 
267 void
268 serve(void)
269 {
270 	doserve(chan);
271 }
272 
273 static
274 struct
275 {
276 	int	nfilter;
277 	Filter*	filters[100];
278 }f;
279 
280 int alarmed;
281 
282 void
283 catchalarm(void *regs, char *msg)
284 {
285 	USED(regs, msg);
286 	if(strcmp(msg, "alarm") == 0){
287 		alarmed = 1;
288 		noted(NCONT);
289 	} else
290 		noted(NDFLT);
291 }
292 
293 /*
294  * process to synch blocks
295  * it puts out a block/line every second
296  * it waits 10 seconds if catches up.
297  * in both cases, it takes about 10 seconds
298  * to get up-to-date.
299  *
300  * it also updates the filter stats
301  * and executes commands
302  */
303 void
304 syncproc(void)
305 {
306 	char buf[4*1024];
307 	Filter *ft;
308 	ulong c0, c1;
309 	long t, n, d;
310 	int i, p[2];
311 
312 	/*
313 	 * make a pipe for commands
314 	 */
315 	if(pipe(p) < 0)
316 		panic("command pipe");
317 	sprint(buf, "#s/%s.cmd", service);
318 	srvfd(buf, cmdmode, p[0]);
319 	close(p[0]);
320 	cmdfd = p[1];
321 	notify(catchalarm);
322 
323 	t = time(nil);
324 	for(;;){
325 		i = syncblock();
326 		alarmed = 0;
327 		alarm(i ? 1000: 10000);
328 		n = read(cmdfd, buf, sizeof buf - 1);
329 		if(n <= 0 && !alarmed)
330 			sleep(i ? 1000: 10000);
331 		alarm(0);
332 		if(n > 0){
333 			buf[n] = '\0';
334 			if(cmd_exec(buf))
335 				fprint(cmdfd, "done");
336 			else
337 				fprint(cmdfd, "unknown command");
338 		}
339 		n = time(nil);
340 		d = n - t;
341 		if(d < 0 || d > 5*60)
342 			d = 0;
343 		while(d >= 1) {
344 			d -= 1;
345 			for(i=0; i<f.nfilter; i++) {
346 				ft = f.filters[i];
347 				c0 = ft->count;
348 				c1 = c0 - ft->oldcount;
349 				ft->oldcount = c0;
350 				ft->filter[0] = famd(ft->filter[0], c1, 59, 60);
351 				ft->filter[1] = famd(ft->filter[1], c1, 599, 600);
352 				ft->filter[2] = famd(ft->filter[2], c1, 5999, 6000);
353 			}
354 		}
355 		t = n;
356 	}
357 }
358 
359 void
360 dofilter(Filter *ft)
361 {
362 	int i;
363 
364 	i = f.nfilter;
365 	if(i >= sizeof f.filters / sizeof f.filters[0]) {
366 		print("dofilter: too many filters\n");
367 		return;
368 	}
369 	f.filters[i] = ft;
370 	f.nfilter = i+1;
371 }
372 
373 void
374 startproc(void (*f)(void), char *name)
375 {
376 	switch(rfork(RFMEM|RFFDG|RFPROC)){
377 	case -1:
378 		panic("can't fork");
379 	case 0:
380 		break;
381 	default:
382 		return;
383 	}
384 	procname = name;
385 	f();
386 }
387 
388 void
389 confinit(void)
390 {
391 	int fd;
392 
393 	conf.niobuf = 0;
394 	conf.nuid = 600;
395 	conf.nserve = 2;
396 	conf.uidspace = conf.nuid*6;
397 	conf.gidspace = conf.nuid*3;
398 	cons.flags = 0;
399 
400 	if ((fd = open("#c/hostowner", OREAD)) > 0) {
401 		read(fd, nvr.authid, sizeof(nvr.authid));
402 		close(fd);
403 	}
404 	if ((fd = open("#c/hostdomain", OREAD)) > 0) {
405 		read(fd, nvr.authdom, sizeof(nvr.authdom));
406 		close(fd);
407 	}
408 	if ((fd = open("#c/key", OREAD)) > 0) {
409 		read(fd, nvr.authkey, sizeof(nvr.authkey));
410 		close(fd);
411 	}
412 
413 }
414 
415 static void
416 dochaninit(Chan *cp, int fd)
417 {
418 	cp->chan = fd;
419 	strncpy(cp->whoname, "<none>", sizeof(cp->whoname));
420 	fileinit(cp);
421 	wlock(&cp->reflock);
422 	wunlock(&cp->reflock);
423 	lock(&cp->flock);
424 	unlock(&cp->flock);
425 }
426 
427 Chan*
428 chaninit(char *server)
429 {
430 	Chan *cp;
431 	char buf[3*NAMELEN];
432 	int p[2];
433 
434 	sprint(buf, "#s/%s", server);
435 	if(sfd < 0){
436 		if(pipe(p) < 0)
437 			panic("can't make a pipe");
438 		sfd = p[0];
439 		rfd = p[1];
440 	}
441 	srvfd(buf, 0666, sfd);
442 	close(sfd);
443 	cp = ialloc(sizeof *cp);
444 	cons.srvchan = cp;
445 	dochaninit(cp, rfd);
446 	return cp;
447 }
448 
449 int
450 netserve(char *netaddr)
451 {
452 	int afd, lfd, fd;
453 	char adir[2*NAMELEN], ldir[2*NAMELEN];
454 	Chan netchan;
455 
456 	if(access("/net/il/clone", 0) < 0)
457 		bind("#I", "/net", MAFTER);
458 	if(access("/net.alt/il/clone", 0) < 0)
459 		bind("#I1", "/net.alt", MAFTER);
460 
461 	afd = announce(netaddr, adir);
462 	if (afd < 0)
463 		return -1;
464 	switch (rfork(RFMEM|RFFDG|RFPROC)) {
465 	case -1:
466 		return -1;
467 	case 0:
468 		break;
469 	default:
470 		return 0;
471 	}
472 	for (;;) {
473 		lfd = listen(adir, ldir);
474 		if (lfd < 0)
475 			continue;
476 		fd = accept(lfd, ldir);
477 		if (fd < 0) {
478 			close(lfd);
479 			continue;
480 		}
481 		memset(&netchan, 0, sizeof(netchan));
482 		dochaninit(&netchan, fd);
483 		switch (rfork(RFMEM|RFFDG|RFPROC)) {
484 		case -1:
485 			panic("can't fork");
486 		case 0:
487 			close(afd);
488 			close(lfd);
489 			doserve(&netchan);
490 			fileinit(&netchan);
491 			exits(0);
492 		default:
493 			close(fd);
494 			close(lfd);
495 			continue;
496 		}
497 	}
498 	return 0;
499 }
500 
501 int
502 srvfd(char *s, int mode, int sfd)
503 {
504 	int fd;
505 	char buf[32];
506 
507 	fd = create(s, OWRITE, mode);
508 	if(fd < 0){
509 		remove(s);
510 		fd = create(s, OWRITE, mode);
511 		if(fd < 0)
512 			panic(s);
513 	}
514 	sprint(buf, "%d", sfd);
515 	if(write(fd, buf, strlen(buf)) != strlen(buf))
516 		panic("srv write");
517 	close(fd);
518 	return sfd;
519 }
520 
521 void
522 consinit(void)
523 {
524 	int i;
525 
526 	cons.chan = ialloc(sizeof(Chan));
527 	wlock(&cons.chan->reflock);
528 	wunlock(&cons.chan->reflock);
529 	lock(&cons.chan->flock);
530 	unlock(&cons.chan->flock);
531 	dofilter(&cons.work);
532 	dofilter(&cons.rate);
533 	dofilter(&cons.bhit);
534 	dofilter(&cons.bread);
535 	dofilter(&cons.binit);
536 	for(i = 0; i < MAXTAG; i++)
537 		dofilter(&cons.tags[i]);
538 }
539 
540 /*
541  * always called with mainlock locked
542  */
543 void
544 syncall(void)
545 {
546 	for(;;)
547 		if(!syncblock())
548 			return;
549 }
550 
551 int
552 askream(Filsys *fs)
553 {
554 	char c;
555 
556 	print("File system %s inconsistent\n", fs->name);
557 	print("Would you like to ream it (y/n)? ");
558 	read(0, &c, 1);
559 	return c == 'y';
560 }
561 
562 ulong
563 memsize(void)
564 {
565 	char *p, buf[128];
566 	int fd, n, by2pg, secs;
567 
568 	by2pg = 4*1024;
569 	p = getenv("cputype");
570 	if(p && strcmp(p, "68020") == 0)
571 		by2pg = 8*1024;
572 
573 	secs = 4*1024*1024;
574 
575 	fd = open("/dev/swap", OREAD);
576 	if(fd < 0)
577 		return secs;
578 	n = read(fd, buf, sizeof(buf)-1);
579 	close(fd);
580 	if(n <= 0)
581 		return secs;
582 	buf[n] = 0;
583 	p = strchr(buf, '/');
584 	if(p)
585 		secs = strtoul(p+1, 0, 0)*by2pg;
586 	return secs;
587 }
588 
589 /*
590  * init the devices
591  * wipe some of the file systems, or all if ream is set
592  * this code really assumes that only one file system exists
593  */
594 int
595 fsinit(int ream, int newbufsize)
596 {
597 	Filsys *fs;
598 
599 	RBUFSIZE = 4 * 1024;
600 	for(fs=filesys; fs->name; fs++)
601 		(*devcall[fs->dev.type].init)(fs->dev);
602 	if(newbufsize == 0)
603 		newbufsize = RBUFSIZE;
604 
605 	if(conf.niobuf == 0) {
606 		conf.niobuf = memsize()/10;
607 		if(conf.niobuf > 2*1024*1024)
608 			conf.niobuf = 2*1024*1024;
609 		conf.niobuf /= newbufsize;
610 		if(conf.niobuf < 30)
611 			conf.niobuf = 30;
612 	}
613 
614 	BUFSIZE = RBUFSIZE - sizeof(Tag);
615 
616 	for(fs=filesys; fs->name; fs++)
617 		if(ream || (*devcall[fs->dev.type].check)(fs->dev) && askream(fs)){
618 			RBUFSIZE = newbufsize;
619 			BUFSIZE = RBUFSIZE - sizeof(Tag);
620 			(*devcall[fs->dev.type].ream)(fs->dev);
621 			fs->flags |= FREAM;
622 			ream = 1;
623 		}
624 
625 	/*
626 	 * set up the block size dependant variables
627 	 */
628 	BUFSIZE = RBUFSIZE - sizeof(Tag);
629 	DIRPERBUF = BUFSIZE / sizeof(Dentry);
630 	INDPERBUF = BUFSIZE / sizeof(long);
631 	INDPERBUF2 = INDPERBUF * INDPERBUF;
632 	FEPERBUF = (BUFSIZE - sizeof(Super1) - sizeof(long)) / sizeof(long);
633 	return ream;
634 }
635 
636 /*
637  * allocate rest of mem
638  * for io buffers.
639  */
640 #define	HWIDTH	5	/* buffers per hash */
641 void
642 iobufinit(void)
643 {
644 	long i;
645 	Iobuf *p, *q;
646 	Hiob *hp;
647 
648 	i = conf.niobuf*RBUFSIZE;
649 	niob = i / (sizeof(Iobuf) + RBUFSIZE + sizeof(Hiob)/HWIDTH);
650 	nhiob = niob / HWIDTH;
651 	while(!prime(nhiob))
652 		nhiob++;
653 	if(chat)
654 		print("	%ld buffers; %ld hashes\n", niob, nhiob);
655 	hiob = ialloc(nhiob * sizeof(Hiob));
656 	hp = hiob;
657 	for(i=0; i<nhiob; i++) {
658 		lock(hp);
659 		unlock(hp);
660 		hp++;
661 	}
662 	p = ialloc(niob * sizeof(Iobuf));
663 	hp = hiob;
664 	for(i=0; i<niob; i++) {
665 		qlock(p);
666 		qunlock(p);
667 		if(hp == hiob)
668 			hp = hiob + nhiob;
669 		hp--;
670 		q = hp->link;
671 		if(q) {
672 			p->fore = q;
673 			p->back = q->back;
674 			q->back = p;
675 			p->back->fore = p;
676 		} else {
677 			hp->link = p;
678 			p->fore = p;
679 			p->back = p;
680 		}
681 		p->dev = devnone;
682 		p->addr = -1;
683 		p->xiobuf = ialloc(RBUFSIZE);
684 		p->iobuf = (char*)-1;
685 		p++;
686 	}
687 }
688 
689 void
690 usage(void)
691 {
692 	fprint(2, "usage: kfs [-cCr] [-b bufsize] [-s infd outfd] [-f fsfile]\n");
693 	exits(0);
694 }
695