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