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