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 if (access(wrenfile, AREAD|AWRITE) == -1) 101 sysfatal("%s cannot access device\n", 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 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 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 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 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 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 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 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* 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 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/il/clone", 0) < 0) 321 bind("#I", "/net", MAFTER); 322 if(access("/net.alt/il/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 return 0; 365 } 366 367 int 368 srvfd(char *s, int mode, int sfd) 369 { 370 int fd; 371 char buf[32]; 372 373 fd = create(s, ORCLOSE|OWRITE, mode); 374 if(fd < 0){ 375 remove(s); 376 fd = create(s, ORCLOSE|OWRITE, mode); 377 if(fd < 0) 378 panic(s); 379 } 380 sprint(buf, "%d", sfd); 381 if(write(fd, buf, strlen(buf)) != strlen(buf)) 382 panic("srv write"); 383 return sfd; 384 } 385 386 void 387 consinit(void) 388 { 389 int i; 390 391 cons.chan = ialloc(sizeof(Chan)); 392 wlock(&cons.chan->reflock); 393 wunlock(&cons.chan->reflock); 394 lock(&cons.chan->flock); 395 unlock(&cons.chan->flock); 396 dofilter(&cons.work); 397 dofilter(&cons.rate); 398 dofilter(&cons.bhit); 399 dofilter(&cons.bread); 400 dofilter(&cons.binit); 401 for(i = 0; i < MAXTAG; i++) 402 dofilter(&cons.tags[i]); 403 } 404 405 /* 406 * always called with mainlock locked 407 */ 408 void 409 syncall(void) 410 { 411 for(;;) 412 if(!syncblock()) 413 return; 414 } 415 416 int 417 askream(Filsys *fs) 418 { 419 char c; 420 421 print("File system %s inconsistent\n", fs->name); 422 print("Would you like to ream it (y/n)? "); 423 read(0, &c, 1); 424 return c == 'y'; 425 } 426 427 ulong 428 memsize(void) 429 { 430 char *p, buf[128]; 431 int fd, n, by2pg, secs; 432 433 by2pg = 4*1024; 434 p = getenv("cputype"); 435 if(p && strcmp(p, "68020") == 0) 436 by2pg = 8*1024; 437 438 secs = 4*1024*1024; 439 440 fd = open("/dev/swap", OREAD); 441 if(fd < 0) 442 return secs; 443 n = read(fd, buf, sizeof(buf)-1); 444 close(fd); 445 if(n <= 0) 446 return secs; 447 buf[n] = 0; 448 p = strchr(buf, '/'); 449 if(p) 450 secs = strtoul(p+1, 0, 0)*by2pg; 451 return secs; 452 } 453 454 /* 455 * init the devices 456 * wipe some of the file systems, or all if ream is set 457 * this code really assumes that only one file system exists 458 */ 459 int 460 fsinit(int ream, int newbufsize) 461 { 462 Filsys *fs; 463 464 RBUFSIZE = 4 * 1024; 465 for(fs=filesys; fs->name; fs++) 466 (*devcall[fs->dev.type].init)(fs->dev); 467 if(newbufsize == 0) 468 newbufsize = RBUFSIZE; 469 470 if(conf.niobuf == 0) { 471 conf.niobuf = memsize()/10; 472 if(conf.niobuf > 2*1024*1024) 473 conf.niobuf = 2*1024*1024; 474 conf.niobuf /= newbufsize; 475 if(conf.niobuf < 30) 476 conf.niobuf = 30; 477 } 478 479 BUFSIZE = RBUFSIZE - sizeof(Tag); 480 481 for(fs=filesys; fs->name; fs++) 482 if(ream || (*devcall[fs->dev.type].check)(fs->dev) && askream(fs)){ 483 RBUFSIZE = newbufsize; 484 BUFSIZE = RBUFSIZE - sizeof(Tag); 485 (*devcall[fs->dev.type].ream)(fs->dev); 486 fs->flags |= FREAM; 487 ream = 1; 488 } 489 490 /* 491 * set up the block size dependant variables 492 */ 493 BUFSIZE = RBUFSIZE - sizeof(Tag); 494 DIRPERBUF = BUFSIZE / sizeof(Dentry); 495 INDPERBUF = BUFSIZE / sizeof(long); 496 INDPERBUF2 = INDPERBUF * INDPERBUF; 497 FEPERBUF = (BUFSIZE - sizeof(Super1) - sizeof(long)) / sizeof(long); 498 return ream; 499 } 500 501 /* 502 * allocate rest of mem 503 * for io buffers. 504 */ 505 #define HWIDTH 5 /* buffers per hash */ 506 void 507 iobufinit(void) 508 { 509 long i; 510 Iobuf *p, *q; 511 Hiob *hp; 512 513 i = conf.niobuf*RBUFSIZE; 514 niob = i / (sizeof(Iobuf) + RBUFSIZE + sizeof(Hiob)/HWIDTH); 515 nhiob = niob / HWIDTH; 516 while(!prime(nhiob)) 517 nhiob++; 518 if(chat) 519 print(" %ld buffers; %ld hashes\n", niob, nhiob); 520 hiob = ialloc(nhiob * sizeof(Hiob)); 521 hp = hiob; 522 for(i=0; i<nhiob; i++) { 523 lock(hp); 524 unlock(hp); 525 hp++; 526 } 527 p = ialloc(niob * sizeof(Iobuf)); 528 hp = hiob; 529 for(i=0; i<niob; i++) { 530 qlock(p); 531 qunlock(p); 532 if(hp == hiob) 533 hp = hiob + nhiob; 534 hp--; 535 q = hp->link; 536 if(q) { 537 p->fore = q; 538 p->back = q->back; 539 q->back = p; 540 p->back->fore = p; 541 } else { 542 hp->link = p; 543 p->fore = p; 544 p->back = p; 545 } 546 p->dev = devnone; 547 p->addr = -1; 548 p->xiobuf = ialloc(RBUFSIZE); 549 p->iobuf = (char*)-1; 550 p++; 551 } 552 } 553 554 void 555 usage(void) 556 { 557 fprint(2, "usage: kfs [-cCr] [-b bufsize] [-s infd outfd] [-f fsfile]\n"); 558 exits(0); 559 } 560