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