#include "all.h" int sfd; int cmdmode = 0660; int rfd; int chat; extern char *wrenfile; extern int nwren; char *myname; int cmdfd; int writeallow; /* never on; for compatibility with fs */ int wstatallow; int writegroup; int allownone; int noatime; int srvfd(char*, int, int); void usage(void); void confinit(void); Chan *chaninit(char*); void consinit(void); void forkserve(void); void main(int argc, char *argv[]) { Filsys *fs; int ream, fsok; int newbufsize, nocheck; char buf[NAMELEN]; int pid, ctl; progname = "kfs"; procname = "init"; /* * insulate from invoker's environment and keep it from swapping */ rfork(RFNAMEG|RFNOTEG|RFREND); confinit(); sfd = -1; ream = 0; newbufsize = 0; nocheck = 0; wrenfile = "/dev/sdC0/fs"; pid = getpid(); snprint(buf, sizeof buf, "/proc/%d/ctl", pid); ctl = open(buf, OWRITE); fprint(ctl, "noswap\n"); close(ctl); buf[0] = '\0'; ARGBEGIN{ case 'b': newbufsize = atol(ARGF()); break; case 'c': nocheck = 1; break; case 'f': wrenfile = ARGF(); break; case 'm': nwren = atol(ARGF()); break; case 'n': strncpy(buf, ARGF(), NAMELEN-1); buf[NAMELEN-1] = '\0'; break; case 'p': cmdmode = atol(ARGF()); break; case 'r': ream = 1; break; case 's': sfd = 0; rfd = dup(1, -1); close(1); if(open("/dev/cons", OWRITE) < 0) open("#c/cons", OWRITE); break; case 'B': conf.niobuf = strtoul(ARGF(), 0, 0); break; case 'C': chat = 1; break; default: usage(); }ARGEND if(argc != 0) usage(); cmdfd = 2; if (access(wrenfile, AREAD|AWRITE) == -1) sysfatal("%s cannot access device", wrenfile); formatinit(); sublockinit(); if(buf[0]) sprint(service, "kfs.%s", buf); else strcpy(service, "kfs"); chan = chaninit(service); consinit(); tlocks = ialloc(NTLOCK * sizeof *tlocks); uid = ialloc(conf.nuid * sizeof(*uid)); uidspace = ialloc(conf.uidspace * sizeof(*uidspace)); gidspace = ialloc(conf.gidspace * sizeof(*gidspace)); /* * init global locks */ wlock(&mainlock); wunlock(&mainlock); /* * init the file system, ream it if needed, and get the block sizes */ ream = fsinit(ream, newbufsize); iobufinit(); for(fs=filesys; fs->name; fs++) if(fs->flags & FREAM){ /* set by fsinit if reamed */ ream++; rootream(fs->dev, getraddr(fs->dev)); superream(fs->dev, superaddr(fs->dev)); } boottime = time(nil); consserve(); fsok = superok(filesys[0].dev, superaddr(filesys[0].dev), 0); if(!nocheck && !ream && !fsok) cmd_exec("check fq"); startproc(forkserve, "srv"); startproc(syncproc, "sync"); exits(0); } void forkserve(void) { serve(chan); } static struct { int nfilter; Filter* filters[100]; }f; int alarmed; void catchalarm(void *regs, char *msg) { USED(regs, msg); if(strcmp(msg, "alarm") == 0){ alarmed = 1; noted(NCONT); } else noted(NDFLT); } /* * process to synch blocks * it puts out a block/line every second * it waits 10 seconds if catches up. * in both cases, it takes about 10 seconds * to get up-to-date. * * it also updates the filter stats * and executes commands */ void syncproc(void) { char buf[4*1024]; Filter *ft; ulong c0, c1; long t, n, d; int i, p[2]; /* * make a pipe for commands */ if(pipe(p) < 0) panic("command pipe"); sprint(buf, "#s/%s.cmd", service); srvfd(buf, cmdmode, p[0]); close(p[0]); cmdfd = p[1]; notify(catchalarm); t = time(nil); for(;;){ i = syncblock(); alarmed = 0; alarm(i ? 1000: 10000); n = read(cmdfd, buf, sizeof buf - 1); if(n <= 0 && !alarmed) sleep(i ? 1000: 10000); alarm(0); if(n > 0){ buf[n] = '\0'; if(cmd_exec(buf)) fprint(cmdfd, "done"); else fprint(cmdfd, "unknown command"); } n = time(nil); d = n - t; if(d < 0 || d > 5*60) d = 0; while(d >= 1) { d -= 1; for(i=0; icount; c1 = c0 - ft->oldcount; ft->oldcount = c0; ft->filter[0] = famd(ft->filter[0], c1, 59, 60); ft->filter[1] = famd(ft->filter[1], c1, 599, 600); ft->filter[2] = famd(ft->filter[2], c1, 5999, 6000); } } t = n; } } void dofilter(Filter *ft) { int i; i = f.nfilter; if(i >= sizeof f.filters / sizeof f.filters[0]) { print("dofilter: too many filters\n"); return; } f.filters[i] = ft; f.nfilter = i+1; } void startproc(void (*f)(void), char *name) { switch(rfork(RFMEM|RFFDG|RFPROC)){ case -1: panic("can't fork"); case 0: break; default: return; } procname = name; f(); _exits(nil); } void confinit(void) { conf.niobuf = 0; conf.nuid = 600; conf.nserve = 2; conf.uidspace = conf.nuid*6; conf.gidspace = conf.nuid*3; cons.flags = 0; } static void dochaninit(Chan *cp, int fd) { cp->chan = fd; fileinit(cp); wlock(&cp->reflock); wunlock(&cp->reflock); lock(&cp->flock); unlock(&cp->flock); } Chan* chaninit(char *server) { Chan *cp; char buf[3*NAMELEN]; int p[2]; sprint(buf, "#s/%s", server); if(sfd < 0){ if(pipe(p) < 0) panic("can't make a pipe"); sfd = p[0]; rfd = p[1]; } srvfd(buf, 0666, sfd); close(sfd); cp = ialloc(sizeof *cp); cons.srvchan = cp; dochaninit(cp, rfd); return cp; } int netserve(char *netaddr) { int afd, lfd, fd; char adir[2*NAMELEN], ldir[2*NAMELEN]; Chan *netchan; if(access("/net/tcp/clone", 0) < 0) bind("#I", "/net", MAFTER); if(access("/net.alt/tcp/clone", 0) < 0) bind("#I1", "/net.alt", MAFTER); afd = announce(netaddr, adir); if (afd < 0) return -1; switch (rfork(RFMEM|RFFDG|RFPROC)) { case -1: return -1; case 0: break; default: return 0; } for (;;) { lfd = listen(adir, ldir); if (lfd < 0) continue; fd = accept(lfd, ldir); if (fd < 0) { close(lfd); continue; } netchan = mallocz(sizeof(Chan), 1); if(netchan == nil) panic("out of memory"); dochaninit(netchan, fd); switch (rfork(RFMEM|RFFDG|RFPROC)) { case -1: panic("can't fork"); case 0: close(afd); close(lfd); serve(netchan); free(netchan); exits(0); default: close(fd); close(lfd); continue; } } } int srvfd(char *s, int mode, int sfd) { int fd; char buf[32]; fd = create(s, ORCLOSE|OWRITE, mode); if(fd < 0){ remove(s); fd = create(s, ORCLOSE|OWRITE, mode); if(fd < 0) panic(s); } sprint(buf, "%d", sfd); if(write(fd, buf, strlen(buf)) != strlen(buf)) panic("srv write"); return sfd; } void consinit(void) { int i; cons.chan = ialloc(sizeof(Chan)); wlock(&cons.chan->reflock); wunlock(&cons.chan->reflock); lock(&cons.chan->flock); unlock(&cons.chan->flock); dofilter(&cons.work); dofilter(&cons.rate); dofilter(&cons.bhit); dofilter(&cons.bread); dofilter(&cons.binit); for(i = 0; i < MAXTAG; i++) dofilter(&cons.tags[i]); } /* * always called with mainlock locked */ void syncall(void) { for(;;) if(!syncblock()) return; } int askream(Filsys *fs) { char c; print("File system %s inconsistent\n", fs->name); print("Would you like to ream it (y/n)? "); read(0, &c, 1); return c == 'y'; } ulong memsize(void) { char *p, buf[128]; int fd, n, by2pg, secs; by2pg = 4*1024; p = getenv("cputype"); if(p && strcmp(p, "68020") == 0) by2pg = 8*1024; secs = 4*1024*1024; fd = open("/dev/swap", OREAD); if(fd < 0) return secs; n = read(fd, buf, sizeof(buf)-1); close(fd); if(n <= 0) return secs; buf[n] = 0; p = strchr(buf, '/'); if(p) secs = strtoul(p+1, 0, 0)*by2pg; return secs; } /* * init the devices * wipe some of the file systems, or all if ream is set * this code really assumes that only one file system exists */ int fsinit(int ream, int newbufsize) { Filsys *fs; RBUFSIZE = 4 * 1024; for(fs=filesys; fs->name; fs++) (*devcall[fs->dev.type].init)(fs->dev); if(newbufsize == 0) newbufsize = RBUFSIZE; if(conf.niobuf == 0) { conf.niobuf = memsize()/10; if(conf.niobuf > 2*1024*1024) conf.niobuf = 2*1024*1024; conf.niobuf /= newbufsize; if(conf.niobuf < 30) conf.niobuf = 30; } BUFSIZE = RBUFSIZE - sizeof(Tag); for(fs=filesys; fs->name; fs++) if(ream || (*devcall[fs->dev.type].check)(fs->dev) && askream(fs)){ RBUFSIZE = newbufsize; BUFSIZE = RBUFSIZE - sizeof(Tag); (*devcall[fs->dev.type].ream)(fs->dev); fs->flags |= FREAM; ream = 1; } /* * set up the block size dependant variables */ BUFSIZE = RBUFSIZE - sizeof(Tag); DIRPERBUF = BUFSIZE / sizeof(Dentry); INDPERBUF = BUFSIZE / sizeof(long); INDPERBUF2 = INDPERBUF * INDPERBUF; FEPERBUF = (BUFSIZE - sizeof(Super1) - sizeof(long)) / sizeof(long); return ream; } /* * allocate rest of mem * for io buffers. */ #define HWIDTH 5 /* buffers per hash */ void iobufinit(void) { long i; Iobuf *p, *q; Hiob *hp; i = conf.niobuf*RBUFSIZE; niob = i / (sizeof(Iobuf) + RBUFSIZE + sizeof(Hiob)/HWIDTH); nhiob = niob / HWIDTH; while(!prime(nhiob)) nhiob++; if(chat) print(" %ld buffers; %ld hashes\n", niob, nhiob); hiob = ialloc(nhiob * sizeof(Hiob)); hp = hiob; for(i=0; ilink; if(q) { p->fore = q; p->back = q->back; q->back = p; p->back->fore = p; } else { hp->link = p; p->fore = p; p->back = p; } p->dev = devnone; p->addr = -1; p->xiobuf = ialloc(RBUFSIZE); p->iobuf = (char*)-1; p++; } } void usage(void) { fprint(2, "usage: kfs [-cCr] [-b bufsize] [-s infd outfd] [-f fsfile]\n"); exits(0); }