1 /* cached-worm file server */
25 n = vseprint(buf, buf + sizeof buf, fmt, arg) - buf;
28 fprint(2, "panic: %s\n", buf);
37 print("okay to %s? ", quest);
38 if ((ln = Brdline(&bin, '\n')) == nil)
40 ln[Blinelen(&bin)-1] = '\0';
41 if (isascii(*ln) && isupper(*ln))
47 mapinit(char *mapfile)
57 bp = Bopen(mapfile, OREAD);
59 sysfatal("can't read %s", mapfile);
61 while((ln = Brdline(bp, '\n')) != nil) {
62 ln[Blinelen(bp)-1] = '\0';
63 if(*ln == '\0' || *ln == '#')
65 nf = tokenize(ln, fields, nelem(fields));
68 if(testconfig(fields[0]) != 0) {
69 print("bad `from' device %s in %s\n",
73 map = ialloc(sizeof(Map), 0);
74 map->from = strdup(fields[0]);
75 map->to = strdup(fields[1]);
76 map->fdev = iconfig(fields[0]);
78 if(access(map->to, AEXIST) < 0) {
80 * map->to isn't an existing file, so it had better be
81 * a config string for a device.
83 if(testconfig(fields[1]) == 0)
84 map->tdev = iconfig(fields[1]);
86 /* else map->to is the replacement file name */
99 conf.nserve = 15; /* tunable */
106 conf.nwpath = conf.nfile*8;
107 conf.gidspace = conf.nuid*3;
112 mapinit(conf.devmap);
116 srvfd(char *s, int mode, int sfd)
121 fd = create(s, ORCLOSE|OWRITE, mode);
124 fd = create(s, ORCLOSE|OWRITE, mode);
128 sprint(buf, "%d", sfd);
129 if(write(fd, buf, strlen(buf)) != strlen(buf))
135 postservice(char *name)
140 if(name == nil || *name == 0)
141 panic("no service name");
143 /* serve 9p for -s */
145 srvchan(sfd, "stdio");
149 /* post 9p service */
151 panic("can't make a pipe");
152 snprint(buf, sizeof(buf), "#s/%s", name);
153 srvfd(buf, 0666, p[0]);
157 /* post cmd service */
159 panic("can't make a pipe");
160 snprint(buf, sizeof(buf), "#s/%s.cmd", name);
161 srvfd(buf, 0660, p[0]);
164 /* use it as stdin */
170 * compute BUFSIZE*(NDBLOCK+INDPERBUF+INDPERBUF²+INDPERBUF³+INDPERBUF⁴)
171 * while watching for overflow; in that case, return 0.
175 adduvlongov(uvlong a, uvlong b)
185 muluvlongov(uvlong a, uvlong b)
189 if (a != 0 && r/a != b || r < a || r < b)
198 uvlong max = NDBLOCK, ind = 1;
200 for (i = 0; i < NIBLOCK; i++) {
201 ind = muluvlongov(ind, INDPERBUF); /* power of INDPERBUF */
204 max = adduvlongov(max, ind);
208 return muluvlongov(max, BUFSIZE);
212 INDPERBUF² = ((uvlong)INDPERBUF*INDPERBUF),
213 INDPERBUF⁴ = ((uvlong)INDPERBUF²*INDPERBUF²),
219 uvlong max = maxsize();
221 print("\tblock size = %d; ", RBUFSIZE);
223 print("max file size exceeds 2⁶⁴ bytes\n");
225 uvlong offlim = 1ULL << (sizeof(Off)*8 - 1);
229 print("max file size = %,llud\n", (Wideoff)max);
231 if (INDPERBUF²/INDPERBUF != INDPERBUF)
232 print("overflow computing INDPERBUF²\n");
233 if (INDPERBUF⁴/INDPERBUF² != INDPERBUF²)
234 print("overflow computing INDPERBUF⁴\n");
235 print("\tINDPERBUF = %d, INDPERBUF^4 = %,lld, ", INDPERBUF,
236 (Wideoff)INDPERBUF⁴);
237 print("CEPERBK = %d\n", CEPERBK);
238 print("\tsizeofs: Dentry = %d, Cache = %d\n",
239 sizeof(Dentry), sizeof(Cache));
245 fprint(2, "usage: %s [ -csC ] [-n service] [ -a ann-str ] [ -m dev-map ] [-f config-dev ]\n", argv0);
250 main(int argc, char **argv)
253 char *ann, *sname = nil;
258 conf.confdev = "/dev/sdC0/fscache";
262 case 'a': /* announce on this net */
263 ann = EARGF(usage());
264 if (nets >= Maxnets) {
265 fprint(2, "%s: too many networks to announce: %s\n",
267 exits("too many nets");
269 annstrs[nets++] = ann;
272 sname = EARGF(usage());
278 if(open("/dev/cons", OREAD) < 0)
279 open("#c/cons", OREAD);
281 if(open("/dev/cons", OWRITE) < 0)
282 open("#c/cons", OWRITE);
284 case 'C': /* use new, faster cache layout */
290 case 'f': /* device / partition / file */
291 conf.confdev = EARGF(usage());
293 case 'm': /* name device-map file */
294 conf.devmap = EARGF(usage());
307 Binit(&bin, 0, OREAD);
311 print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n",
312 sizeof(Off)*8 - 1, NIBLOCK);
318 serveq = newqueue(1000, "9P service"); /* tunable */
319 raheadq = newqueue(1000, "readahead"); /* tunable */
325 files = ialloc((uintptr)conf.nfile * sizeof(*files), 0);
326 for(i=0; i < conf.nfile; i++) {
331 wpaths = ialloc((uintptr)conf.nwpath * sizeof(*wpaths), 0);
332 uid = ialloc((uintptr)conf.nuid * sizeof(*uid), 0);
333 gidspace = ialloc((uintptr)conf.gidspace * sizeof(*gidspace), 0);
338 boottime = time(nil);
344 * post filedescriptors to /srv
346 postservice(sname != nil ? sname : service);
349 * processes to read the console
354 * Ethernet i/o processes
359 * read ahead processes
361 newproc(rahead, 0, "rah");
366 for(i=0; i < conf.nserve; i++)
367 newproc(serve, 0, "srv");
370 * worm "dump" copy process
372 newproc(wormcopy, 0, "wcp");
375 * "sync" copy process
377 newproc(synccopy, 0, "scp");
384 * read ahead processes.
385 * read message from q and then
389 rbcmp(void *va, void *vb)
399 if(ra->dev > rb->dev)
401 if(ra->dev < rb->dev)
403 if(ra->addr > rb->addr)
405 if(ra->addr < rb->addr)
418 rb[0] = fs_recv(raheadq, 0);
419 for(n = 1; n < nelem(rb); n++) {
420 if(raheadq->count <= 0)
422 rb[n] = fs_recv(raheadq, 0);
424 qsort(rb, n, sizeof rb[0], rbcmp);
425 for(i = 0; i < n; i++) {
428 p = getbuf(rb[i]->dev, rb[i]->addr, Brd);
432 rb[i]->link = rabuffree;
440 * main filesystem server loop.
441 * entered by many processes.
442 * they wait for message buffers and
454 /* read 9P request from a network input process */
455 mb = fs_recv(serveq, 0);
456 /* fs kernel sets chan in /sys/src/fs/ip/il.c:/^getchan */
459 panic("serve: nil mb->chan");
466 panic("serve: nil mb->data");
467 if(cp->protocol != nil){
468 /* process the request, generate an answer and reply */
471 /* do we recognise the protocol in this packet? */
472 for(i = 0; fsprotocol[i] != nil; i++)
473 if(fsprotocol[i](mb) != 0) {
474 cp->protocol = fsprotocol[i];
477 if(cp->protocol == nil && (chatty > 1)){
478 fprint(2, "no protocol for message\n");
479 hexdump(mb->data, 12);
485 runlock(&cp->reflock);
496 fprint(2, "halted at %T.\n", time(nil));
497 postnote(PNGROUP, getpid(), "die");
502 DUMPTIME = 5, /* 5 am */
503 WEEKMASK = 0, /* every day (1=sun, 2=mon, 4=tue, etc.) */
507 * calculate the next dump time.
508 * minimum delay is 100 minutes.
513 Timet nddate = nextime(t+MINUTE(100), DUMPTIME, WEEKMASK);
515 if(!conf.nodump && chatty)
516 fprint(2, "next dump at %T\n", nddate);
521 * process to copy dump blocks from
522 * cache to worm. it runs flat out when
523 * it gets work, but only looks for
524 * work every 10 seconds.
530 Timet dt, t = 0, nddate = 0, ntoytime = 0;
537 nddate = nextdump(t); /* chatters */
538 ntoytime = time(nil);
541 if(dt < 0 || dt > MINUTE(100)) {
548 ntoytime = time(nil) + HOUR(1);
549 else if(t > nddate) {
551 fprint(2, "automatic dump %T\n", t);
552 for(fs=filsys; fs->name; fs++)
553 if(fs->dev->type == Devcw)
559 for(fs=filsys; fs->name; fs++)
560 if(fs->dev->type == Devcw)
561 f |= dumpblock(fs->dev);
571 * process to synch blocks
572 * it puts out a block/cache-line every second
573 * it waits 10 seconds if caught up.
574 * in both cases, it takes about 10 seconds
597 char *ln, *end, *data;
602 data = malloc(strlen(file) + 5 + 1);
604 end = strstr(data, "/data");
606 strcat(data, "/ctl");
609 bp = Bopen(data, OREAD);
611 while (rv < 0 && (ln = Brdline(bp, '\n')) != nil) {
612 ln[Blinelen(bp)-1] = '\0';
613 nf = tokenize(ln, fields, nelem(fields));
614 if (nf == 3 && strcmp(fields[0], "geometry") == 0)
615 rv = atoi(fields[2]);