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