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