diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/disk/kfs/main.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/disk/kfs/main.c')
-rwxr-xr-x | sys/src/cmd/disk/kfs/main.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/sys/src/cmd/disk/kfs/main.c b/sys/src/cmd/disk/kfs/main.c new file mode 100755 index 000000000..3ca31615b --- /dev/null +++ b/sys/src/cmd/disk/kfs/main.c @@ -0,0 +1,558 @@ +#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; i<f.nfilter; i++) { + ft = f.filters[i]; + c0 = ft->count; + 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; i<nhiob; i++) { + lock(hp); + unlock(hp); + hp++; + } + p = ialloc(niob * sizeof(Iobuf)); + hp = hiob; + for(i=0; i<niob; i++) { + qlock(p); + qunlock(p); + if(hp == hiob) + hp = hiob + nhiob; + hp--; + q = hp->link; + 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); +} |