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