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