123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /* 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 uint64_t
- adduvlongov(uint64_t a, uint64_t b)
- {
- uint64_t r = a + b;
- if (r < a || r < b)
- return 0;
- return r;
- }
- static uint64_t
- muluvlongov(uint64_t a, uint64_t b)
- {
- uint64_t r = a * b;
- if (a != 0 && r/a != b || r < a || r < b)
- return 0;
- return r;
- }
- static uint64_t
- maxsize(void)
- {
- int i;
- uint64_t 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 = %,llu\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(const void *va, const 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.2X", 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;
- }
|