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