summaryrefslogtreecommitdiff
path: root/sys/src/cmd/disk/kfs/main.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/disk/kfs/main.c558
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);
+}