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