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/cwfs/main.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/main.c')
-rwxr-xr-x | sys/src/cmd/cwfs/main.c | 586 |
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; +} |