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