1 /* cached-worm file server */
26 n = vseprint(buf, buf + sizeof buf, fmt, arg) - buf;
29 fprint(2, "panic: %s\n", buf);
38 print("okay to %s? ", quest);
39 if ((ln = Brdline(&bin, '\n')) == nil)
41 ln[Blinelen(&bin)-1] = '\0';
42 if (isascii(*ln) && isupper(*ln))
48 mapinit(char *mapfile)
58 bp = Bopen(mapfile, OREAD);
60 sysfatal("can't read %s", mapfile);
62 while((ln = Brdline(bp, '\n')) != nil) {
63 ln[Blinelen(bp)-1] = '\0';
64 if(*ln == '\0' || *ln == '#')
66 nf = tokenize(ln, fields, nelem(fields));
69 if(testconfig(fields[0]) != 0) {
70 print("bad `from' device %s in %s\n",
74 map = ialloc(sizeof(Map), 0);
75 map->from = strdup(fields[0]);
76 map->to = strdup(fields[1]);
77 map->fdev = iconfig(fields[0]);
79 if(access(map->to, AEXIST) < 0) {
81 * map->to isn't an existing file, so it had better be
82 * a config string for a device.
84 if(testconfig(fields[1]) == 0)
85 map->tdev = iconfig(fields[1]);
87 /* else map->to is the replacement file name */
100 conf.nserve = 15; /* tunable */
107 conf.nwpath = conf.nfile*8;
108 conf.gidspace = conf.nuid*3;
113 mapinit(conf.devmap);
117 srvfd(char *s, int mode, int sfd)
122 fd = create(s, ORCLOSE|OWRITE, mode);
125 fd = create(s, ORCLOSE|OWRITE, mode);
129 sprint(buf, "%d", sfd);
130 if(write(fd, buf, strlen(buf)) != strlen(buf))
142 panic("no service name");
144 /* serve 9p for -s */
146 srvchan(sfd, "stdio");
150 /* post 9p service */
152 panic("can't make a pipe");
153 snprint(buf, sizeof(buf), "#s/%s", service);
154 srvfd(buf, 0666, p[0]);
158 /* post cmd service */
160 panic("can't make a pipe");
161 snprint(buf, sizeof(buf), "#s/%s.cmd", service);
162 srvfd(buf, 0660, p[0]);
165 /* use it as stdin */
171 * compute BUFSIZE*(NDBLOCK+INDPERBUF+INDPERBUF²+INDPERBUF³+INDPERBUF⁴)
172 * while watching for overflow; in that case, return 0.
176 adduvlongov(uvlong a, uvlong b)
186 muluvlongov(uvlong a, uvlong b)
190 if (a != 0 && r/a != b || r < a || r < b)
199 uvlong max = NDBLOCK, ind = 1;
201 for (i = 0; i < NIBLOCK; i++) {
202 ind = muluvlongov(ind, INDPERBUF); /* power of INDPERBUF */
205 max = adduvlongov(max, ind);
209 return muluvlongov(max, BUFSIZE);
213 INDPERBUF² = ((uvlong)INDPERBUF*INDPERBUF),
214 INDPERBUF⁴ = ((uvlong)INDPERBUF²*INDPERBUF²),
220 uvlong max = maxsize();
222 print("\tblock size = %d; ", RBUFSIZE);
224 print("max file size exceeds 2⁶⁴ bytes\n");
226 uvlong offlim = 1ULL << (sizeof(Off)*8 - 1);
230 print("max file size = %,llud\n", (Wideoff)max);
232 if (INDPERBUF²/INDPERBUF != INDPERBUF)
233 print("overflow computing INDPERBUF²\n");
234 if (INDPERBUF⁴/INDPERBUF² != INDPERBUF²)
235 print("overflow computing INDPERBUF⁴\n");
236 print("\tINDPERBUF = %d, INDPERBUF^4 = %,lld, ", INDPERBUF,
237 (Wideoff)INDPERBUF⁴);
238 print("CEPERBK = %d\n", CEPERBK);
239 print("\tsizeofs: Dentry = %d, Cache = %d\n",
240 sizeof(Dentry), sizeof(Cache));
246 fprint(2, "usage: %s [ -csC ] [-n service] [ -a ann-str ] [ -m dev-map ] [-f config-dev ]\n", argv0);
251 main(int argc, char **argv)
259 conf.confdev = "/dev/sdC0/fscache";
263 case 'a': /* announce on this net */
264 ann = EARGF(usage());
265 if (nets >= Maxnets) {
266 fprint(2, "%s: too many networks to announce: %s\n",
268 exits("too many nets");
270 annstrs[nets++] = ann;
273 strcpy(service, EARGF(usage()));
279 if(open("/dev/cons", OREAD) < 0)
280 open("#c/cons", OREAD);
282 if(open("/dev/cons", OWRITE) < 0)
283 open("#c/cons", OWRITE);
285 case 'C': /* use new, faster cache layout */
291 case 'f': /* device / partition / file */
292 conf.confdev = EARGF(usage());
294 case 'm': /* name device-map file */
295 conf.devmap = EARGF(usage());
308 Binit(&bin, 0, OREAD);
312 print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n",
313 sizeof(Off)*8 - 1, NIBLOCK);
319 serveq = newqueue(1000, "9P service"); /* tunable */
320 raheadq = newqueue(1000, "readahead"); /* tunable */
326 files = ialloc((uintptr)conf.nfile * sizeof(*files), 0);
327 for(i=0; i < conf.nfile; i++) {
332 wpaths = ialloc((uintptr)conf.nwpath * sizeof(*wpaths), 0);
333 uid = ialloc((uintptr)conf.nuid * sizeof(*uid), 0);
334 gidspace = ialloc((uintptr)conf.gidspace * sizeof(*gidspace), 0);
339 boottime = time(nil);
345 * post filedescriptors to /srv
350 * processes to read the console
355 * Ethernet i/o processes
360 * read ahead processes
362 newproc(rahead, 0, "rah");
367 for(i=0; i < conf.nserve; i++)
368 newproc(serve, 0, "srv");
371 * worm "dump" copy process
373 newproc(wormcopy, 0, "wcp");
376 * "sync" copy process
378 newproc(synccopy, 0, "scp");
385 * read ahead processes.
386 * read message from q and then
390 rbcmp(void *va, void *vb)
400 if(ra->dev > rb->dev)
402 if(ra->dev < rb->dev)
404 if(ra->addr > rb->addr)
406 if(ra->addr < rb->addr)
419 rb[0] = fs_recv(raheadq, 0);
420 for(n = 1; n < nelem(rb); n++) {
421 if(raheadq->count <= 0)
423 rb[n] = fs_recv(raheadq, 0);
425 qsort(rb, n, sizeof rb[0], rbcmp);
426 for(i = 0; i < n; i++) {
429 p = getbuf(rb[i]->dev, rb[i]->addr, Brd);
433 rb[i]->link = rabuffree;
441 * main filesystem server loop.
442 * entered by many processes.
443 * they wait for message buffers and
455 /* read 9P request from a network input process */
456 mb = fs_recv(serveq, 0);
457 assert(mb->magic == Mbmagic);
458 /* fs kernel sets chan in /sys/src/fs/ip/il.c:/^getchan */
461 panic("serve: nil mb->chan");
468 panic("serve: nil mb->data");
469 /* better sniffing code in /sys/src/cmd/disk/kfs/9p12.c */
470 if(cp->protocol == nil){
471 /* do we recognise the protocol in this packet? */
472 /* better sniffing code: /sys/src/cmd/disk/kfs/9p12.c */
473 for(i = 0; fsprotocol[i] != nil; i++)
474 if(fsprotocol[i](mb) != 0) {
475 cp->protocol = fsprotocol[i];
478 if(cp->protocol == nil && (chatty > 1)){
479 fprint(2, "no protocol for message\n");
480 hexdump(mb->data, 12);
483 /* process the request, generate an answer and reply */
488 runlock(&cp->reflock);
499 fprint(2, "halted at %T.\n", time(nil));
500 postnote(PNGROUP, getpid(), "die");
505 DUMPTIME = 5, /* 5 am */
506 WEEKMASK = 0, /* every day (1=sun, 2=mon, 4=tue, etc.) */
510 * calculate the next dump time.
511 * minimum delay is 100 minutes.
516 Timet nddate = nextime(t+MINUTE(100), DUMPTIME, WEEKMASK);
518 if(!conf.nodump && chatty)
519 fprint(2, "next dump at %T\n", nddate);
524 * process to copy dump blocks from
525 * cache to worm. it runs flat out when
526 * it gets work, but only looks for
527 * work every 10 seconds.
533 Timet dt, t = 0, nddate = 0, ntoytime = 0;
540 nddate = nextdump(t); /* chatters */
541 ntoytime = time(nil);
544 if(dt < 0 || dt > MINUTE(100)) {
551 ntoytime = time(nil) + HOUR(1);
552 else if(t > nddate) {
554 fprint(2, "automatic dump %T\n", t);
555 for(fs=filsys; fs->name; fs++)
556 if(fs->dev->type == Devcw)
562 for(fs=filsys; fs->name; fs++)
563 if(fs->dev->type == Devcw)
564 f |= dumpblock(fs->dev);
574 * process to synch blocks
575 * it puts out a block/cache-line every second
576 * it waits 10 seconds if caught up.
577 * in both cases, it takes about 10 seconds
600 char *ln, *end, *data;
605 data = malloc(strlen(file) + 5 + 1);
607 end = strstr(data, "/data");
609 strcat(data, "/ctl");
612 bp = Bopen(data, OREAD);
614 while (rv < 0 && (ln = Brdline(bp, '\n')) != nil) {
615 ln[Blinelen(bp)-1] = '\0';
616 nf = tokenize(ln, fields, nelem(fields));
617 if (nf == 3 && strcmp(fields[0], "geometry") == 0)
618 rv = atoi(fields[2]);