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