summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cwfs/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/cwfs/main.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/main.c')
-rwxr-xr-xsys/src/cmd/cwfs/main.c586
1 files changed, 586 insertions, 0 deletions
diff --git a/sys/src/cmd/cwfs/main.c b/sys/src/cmd/cwfs/main.c
new file mode 100755
index 000000000..d1422a1f9
--- /dev/null
+++ b/sys/src/cmd/cwfs/main.c
@@ -0,0 +1,586 @@
+/* cached-worm file server */
+#include "all.h"
+#include "io.h"
+#include "9p1.h"
+
+extern int oldcachefmt;
+
+Map *devmap;
+
+Biobuf bin;
+
+void
+machinit(void)
+{
+ active.exiting = 0;
+}
+
+/*
+ * Put a string on the console.
+ */
+void
+puts(char *s, int n)
+{
+ print("%.*s", n, s);
+}
+
+void
+prflush(void)
+{
+}
+
+/*
+ * Print a string on the console.
+ */
+void
+putstrn(char *str, int n)
+{
+ puts(str, n);
+}
+
+/*
+ * get a character from the console
+ */
+int
+getc(void)
+{
+ return Bgetrune(&bin);
+}
+
+void
+panic(char *fmt, ...)
+{
+ int n;
+ va_list arg;
+ char buf[PRINTSIZE];
+
+ va_start(arg, fmt);
+ n = vseprint(buf, buf + sizeof buf, fmt, arg) - buf;
+ va_end(arg);
+ buf[n] = '\0';
+ print("panic: %s\n", buf);
+ exit();
+}
+
+int
+okay(char *quest)
+{
+ char *ln;
+
+ print("okay to %s? ", quest);
+ if ((ln = Brdline(&bin, '\n')) == nil)
+ return 0;
+ ln[Blinelen(&bin)-1] = '\0';
+ if (isascii(*ln) && isupper(*ln))
+ *ln = tolower(*ln);
+ return *ln == 'y';
+}
+
+static void
+mapinit(char *mapfile)
+{
+ int nf;
+ char *ln;
+ char *fields[2];
+ Biobuf *bp;
+ Map *map;
+
+ if (mapfile == nil)
+ return;
+ bp = Bopen(mapfile, OREAD);
+ if (bp == nil)
+ sysfatal("can't read %s", mapfile);
+ devmap = nil;
+ while ((ln = Brdline(bp, '\n')) != nil) {
+ ln[Blinelen(bp)-1] = '\0';
+ if (*ln == '\0' || *ln == '#')
+ continue;
+ nf = tokenize(ln, fields, nelem(fields));
+ if (nf != 2)
+ continue;
+ if(testconfig(fields[0]) != 0) {
+ print("bad `from' device %s in %s\n",
+ fields[0], mapfile);
+ continue;
+ }
+ map = malloc(sizeof *map);
+ map->from = strdup(fields[0]);
+ map->to = strdup(fields[1]);
+ map->fdev = iconfig(fields[0]);
+ map->tdev = nil;
+ if (access(map->to, AEXIST) < 0) {
+ /*
+ * map->to isn't an existing file, so it had better be
+ * a config string for a device.
+ */
+ if(testconfig(fields[1]) == 0)
+ map->tdev = iconfig(fields[1]);
+ }
+ /* else map->to is the replacement file name */
+ map->next = devmap;
+ devmap = map;
+ }
+ Bterm(bp);
+}
+
+static void
+confinit(void)
+{
+ conf.nmach = 1;
+
+ conf.mem = meminit();
+
+ conf.nuid = 1000;
+ conf.nserve = 15; /* tunable */
+ conf.nfile = 30000;
+ conf.nlgmsg = 100;
+ conf.nsmmsg = 500;
+
+ localconfinit();
+
+ conf.nwpath = conf.nfile*8;
+ conf.nauth = conf.nfile/10;
+ conf.gidspace = conf.nuid*3;
+
+ cons.flags = 0;
+
+ if (conf.devmap)
+ mapinit(conf.devmap);
+}
+
+/*
+ * compute BUFSIZE*(NDBLOCK+INDPERBUF+INDPERBUF⁲+INDPERBUF⁳+INDPERBUF⁴)
+ * while watching for overflow; in that case, return 0.
+ */
+
+static uvlong
+adduvlongov(uvlong a, uvlong b)
+{
+ uvlong r = a + b;
+
+ if (r < a || r < b)
+ return 0;
+ return r;
+}
+
+static uvlong
+muluvlongov(uvlong a, uvlong b)
+{
+ uvlong r = a * b;
+
+ if (a != 0 && r/a != b || r < a || r < b)
+ return 0;
+ return r;
+}
+
+static uvlong
+maxsize(void)
+{
+ int i;
+ uvlong max = NDBLOCK, ind = 1;
+
+ for (i = 0; i < NIBLOCK; i++) {
+ ind = muluvlongov(ind, INDPERBUF); /* power of INDPERBUF */
+ if (ind == 0)
+ return 0;
+ max = adduvlongov(max, ind);
+ if (max == 0)
+ return 0;
+ }
+ return muluvlongov(max, BUFSIZE);
+}
+
+enum {
+ INDPERBUF⁲ = ((uvlong)INDPERBUF *INDPERBUF),
+ INDPERBUF⁴ = ((uvlong)INDPERBUF⁲*INDPERBUF⁲),
+};
+
+static void
+printsizes(void)
+{
+ uvlong max = maxsize();
+
+ print("\tblock size = %d; ", RBUFSIZE);
+ if (max == 0)
+ print("max file size exceeds 2⁶⁴ bytes\n");
+ else {
+ uvlong offlim = 1ULL << (sizeof(Off)*8 - 1);
+
+ if (max >= offlim)
+ max = offlim - 1;
+ print("max file size = %,llud\n", (Wideoff)max);
+ }
+ if (INDPERBUF⁲/INDPERBUF != INDPERBUF)
+ print("overflow computing INDPERBUF⁲\n");
+ if (INDPERBUF⁴/INDPERBUF⁲ != INDPERBUF⁲)
+ print("overflow computing INDPERBUF⁴\n");
+ print("\tINDPERBUF = %d, INDPERBUF^4 = %,lld, ", INDPERBUF,
+ (Wideoff)INDPERBUF⁴);
+ print("CEPERBK = %d\n", CEPERBK);
+ print("\tsizeofs: Dentry = %d, Cache = %d\n",
+ sizeof(Dentry), sizeof(Cache));
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-cf][-a ann-str][-m dev-map] config-dev\n",
+ argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int i, nets = 0;
+ char *ann;
+
+ rfork(RFNOTEG);
+ formatinit();
+ machinit();
+ conf.confdev = "n"; /* Devnone */
+
+ ARGBEGIN{
+ case 'a': /* announce on this net */
+ ann = EARGF(usage());
+ if (nets >= Maxnets) {
+ fprint(2, "%s: too many networks to announce: %s\n",
+ argv0, ann);
+ exits("too many nets");
+ }
+ annstrs[nets++] = ann;
+ break;
+ case 'c': /* use new, faster cache layout */
+ oldcachefmt = 0;
+ break;
+ case 'f': /* enter configuration mode first */
+ conf.configfirst++;
+ break;
+ case 'm': /* name device-map file */
+ conf.devmap = EARGF(usage());
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND
+
+ if (argc != 1)
+ usage();
+ conf.confdev = argv[0]; /* config string for dev holding full config */
+
+ Binit(&bin, 0, OREAD);
+ confinit();
+
+ print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n",
+ sizeof(Off)*8 - 1, NIBLOCK);
+ printsizes();
+
+ qlock(&reflock);
+ qunlock(&reflock);
+ serveq = newqueue(1000, "9P service"); /* tunable */
+ raheadq = newqueue(1000, "readahead"); /* tunable */
+
+ mbinit();
+ netinit();
+ scsiinit();
+
+ files = malloc(conf.nfile * sizeof *files);
+ for(i=0; i < conf.nfile; i++) {
+ qlock(&files[i]);
+ qunlock(&files[i]);
+ }
+
+ wpaths = malloc(conf.nwpath * sizeof(*wpaths));
+ uid = malloc(conf.nuid * sizeof(*uid));
+ gidspace = malloc(conf.gidspace * sizeof(*gidspace));
+ authinit();
+
+ print("iobufinit\n");
+ iobufinit();
+
+ arginit();
+ boottime = time(nil);
+
+ print("sysinit\n");
+ sysinit();
+
+ /*
+ * Ethernet i/o processes
+ */
+ netstart();
+
+ /*
+ * read ahead processes
+ */
+ newproc(rahead, 0, "rah");
+
+ /*
+ * server processes
+ */
+ for(i=0; i < conf.nserve; i++)
+ newproc(serve, 0, "srv");
+
+ /*
+ * worm "dump" copy process
+ */
+ newproc(wormcopy, 0, "wcp");
+
+ /*
+ * processes to read the console
+ */
+ consserve();
+
+ /*
+ * "sync" copy process
+ * this doesn't return.
+ */
+ procsetname("scp");
+ synccopy();
+}
+
+/*
+ * read ahead processes.
+ * read message from q and then
+ * read the device.
+ */
+int
+rbcmp(void *va, void *vb)
+{
+ Rabuf *ra, *rb;
+
+ ra = *(Rabuf**)va;
+ rb = *(Rabuf**)vb;
+ if(rb == 0)
+ return 1;
+ if(ra == 0)
+ return -1;
+ if(ra->dev > rb->dev)
+ return 1;
+ if(ra->dev < rb->dev)
+ return -1;
+ if(ra->addr > rb->addr)
+ return 1;
+ if(ra->addr < rb->addr)
+ return -1;
+ return 0;
+}
+
+void
+rahead(void *)
+{
+ Rabuf *rb[50];
+ Iobuf *p;
+ int i, n;
+
+ for (;;) {
+ rb[0] = fs_recv(raheadq, 0);
+ for(n = 1; n < nelem(rb); n++) {
+ if(raheadq->count <= 0)
+ break;
+ rb[n] = fs_recv(raheadq, 0);
+ }
+ qsort(rb, n, sizeof rb[0], rbcmp);
+ for(i = 0; i < n; i++) {
+ if(rb[i] == 0)
+ continue;
+ p = getbuf(rb[i]->dev, rb[i]->addr, Brd);
+ if(p)
+ putbuf(p);
+ lock(&rabuflock);
+ rb[i]->link = rabuffree;
+ rabuffree = rb[i];
+ unlock(&rabuflock);
+ }
+ }
+}
+
+/*
+ * main filesystem server loop.
+ * entered by many processes.
+ * they wait for message buffers and
+ * then process them.
+ */
+void
+serve(void *)
+{
+ int i;
+ Chan *cp;
+ Msgbuf *mb;
+
+ for (;;) {
+ qlock(&reflock);
+ /* read 9P request from a network input process */
+ mb = fs_recv(serveq, 0);
+ assert(mb->magic == Mbmagic);
+ /* fs kernel sets chan in /sys/src/fs/ip/il.c:/^getchan */
+ cp = mb->chan;
+ if (cp == nil)
+ panic("serve: nil mb->chan");
+ rlock(&cp->reflock);
+ qunlock(&reflock);
+
+ rlock(&mainlock);
+
+ if (mb->data == nil)
+ panic("serve: nil mb->data");
+ /* better sniffing code in /sys/src/cmd/disk/kfs/9p12.c */
+ if(cp->protocol == nil){
+ /* do we recognise the protocol in this packet? */
+ /* better sniffing code: /sys/src/cmd/disk/kfs/9p12.c */
+ for(i = 0; fsprotocol[i] != nil; i++)
+ if(fsprotocol[i](mb) != 0) {
+ cp->protocol = fsprotocol[i];
+ break;
+ }
+ if(cp->protocol == nil){
+ print("no protocol for message\n");
+ for(i = 0; i < 12; i++)
+ print(" %2.2uX", mb->data[i]);
+ print("\n");
+ }
+ } else
+ /* process the request, generate an answer and reply */
+ cp->protocol(mb);
+
+ mbfree(mb);
+ runlock(&mainlock);
+ runlock(&cp->reflock);
+ }
+}
+
+void
+exit(void)
+{
+ lock(&active);
+ active.exiting = 1;
+ unlock(&active);
+
+ print("halted at %T.\n", time(nil));
+ postnote(PNGROUP, getpid(), "die");
+ exits(nil);
+}
+
+enum {
+ DUMPTIME = 5, /* 5 am */
+ WEEKMASK = 0, /* every day (1=sun, 2=mon, 4=tue, etc.) */
+};
+
+/*
+ * calculate the next dump time.
+ * minimum delay is 100 minutes.
+ */
+Timet
+nextdump(Timet t)
+{
+ Timet nddate = nextime(t+MINUTE(100), DUMPTIME, WEEKMASK);
+
+ if(!conf.nodump)
+ print("next dump at %T\n", nddate);
+ return nddate;
+}
+
+/*
+ * process to copy dump blocks from
+ * cache to worm. it runs flat out when
+ * it gets work, but only looks for
+ * work every 10 seconds.
+ */
+void
+wormcopy(void *)
+{
+ int f, dorecalc = 1;
+ Timet dt, t = 0, nddate = 0, ntoytime = 0;
+ Filsys *fs;
+
+ for (;;) {
+ if (dorecalc) {
+ dorecalc = 0;
+ t = time(nil);
+ nddate = nextdump(t); /* chatters */
+ ntoytime = time(nil);
+ }
+ dt = time(nil) - t;
+ if(dt < 0 || dt > MINUTE(100)) {
+ if(dt < 0)
+ print("time went back\n");
+ else
+ print("time jumped ahead\n");
+ dorecalc = 1;
+ continue;
+ }
+ t += dt;
+ f = 0;
+ if(t > ntoytime)
+ ntoytime = time(nil) + HOUR(1);
+ else if(t > nddate) {
+ if(!conf.nodump) {
+ print("automatic dump %T\n", t);
+ for(fs=filsys; fs->name; fs++)
+ if(fs->dev->type == Devcw)
+ cfsdump(fs);
+ }
+ dorecalc = 1;
+ } else {
+ rlock(&mainlock);
+ for(fs=filsys; fs->name; fs++)
+ if(fs->dev->type == Devcw)
+ f |= dumpblock(fs->dev);
+ runlock(&mainlock);
+ if(!f)
+ delay(10000);
+ wormprobe();
+ }
+ }
+}
+
+/*
+ * process to synch blocks
+ * it puts out a block/cache-line every second
+ * it waits 10 seconds if caught up.
+ * in both cases, it takes about 10 seconds
+ * to get up-to-date.
+ */
+void
+synccopy(void)
+{
+ int f;
+
+ for (;;) {
+ rlock(&mainlock);
+ f = syncblock();
+ runlock(&mainlock);
+ if(!f)
+ delay(10000);
+ else
+ delay(1000);
+ }
+}
+
+Devsize
+inqsize(char *file)
+{
+ int nf;
+ char *ln, *end, *data = malloc(strlen(file) + 5 + 1);
+ char *fields[4];
+ Devsize rv = -1;
+ Biobuf *bp;
+
+ strcpy(data, file);
+ end = strstr(data, "/data");
+ if (end == nil)
+ strcat(data, "/ctl");
+ else
+ strcpy(end, "/ctl");
+ bp = Bopen(data, OREAD);
+ if (bp) {
+ while (rv < 0 && (ln = Brdline(bp, '\n')) != nil) {
+ ln[Blinelen(bp)-1] = '\0';
+ nf = tokenize(ln, fields, nelem(fields));
+ if (nf == 3 && strcmp(fields[0], "geometry") == 0)
+ rv = atoi(fields[2]);
+ }
+ Bterm(bp);
+ }
+ free(data);
+ return rv;
+}