1 /* cached-worm file server */
6 extern int oldcachefmt;
20 * Put a string on the console.
34 * Print a string on the console.
37 putstrn(char *str, int n)
43 * get a character from the console
48 return Bgetrune(&bin);
59 n = vseprint(buf, buf + sizeof buf, fmt, arg) - buf;
62 print("panic: %s\n", buf);
71 print("okay to %s? ", quest);
72 if ((ln = Brdline(&bin, '\n')) == nil)
74 ln[Blinelen(&bin)-1] = '\0';
75 if (isascii(*ln) && isupper(*ln))
81 mapinit(char *mapfile)
91 bp = Bopen(mapfile, OREAD);
93 sysfatal("can't read %s", mapfile);
95 while ((ln = Brdline(bp, '\n')) != nil) {
96 ln[Blinelen(bp)-1] = '\0';
97 if (*ln == '\0' || *ln == '#')
99 nf = tokenize(ln, fields, nelem(fields));
102 if(testconfig(fields[0]) != 0) {
103 print("bad `from' device %s in %s\n",
107 map = malloc(sizeof *map);
108 map->from = strdup(fields[0]);
109 map->to = strdup(fields[1]);
110 map->fdev = iconfig(fields[0]);
112 if (access(map->to, AEXIST) < 0) {
114 * map->to isn't an existing file, so it had better be
115 * a config string for a device.
117 if(testconfig(fields[1]) == 0)
118 map->tdev = iconfig(fields[1]);
120 /* else map->to is the replacement file name */
132 conf.mem = meminit();
135 conf.nserve = 15; /* tunable */
142 conf.nwpath = conf.nfile*8;
143 conf.nauth = conf.nfile/10;
144 conf.gidspace = conf.nuid*3;
149 mapinit(conf.devmap);
153 srvfd(char *s, int mode, int sfd)
158 fd = create(s, ORCLOSE|OWRITE, mode);
161 fd = create(s, ORCLOSE|OWRITE, mode);
165 sprint(buf, "%d", sfd);
166 if(write(fd, buf, strlen(buf)) != strlen(buf))
178 panic("no service name");
182 panic("can't make a pipe");
187 /* post 9p service */
188 snprint(buf, sizeof(buf), "#s/%s", service);
189 srvfd(buf, 0666, sfd);
194 panic("can't make a pipe");
196 /* post cmd service */
197 snprint(buf, sizeof(buf), "#s/%s.cmd", service);
198 srvfd(buf, 0222, p[0]);
201 /* use it as stdin */
207 * compute BUFSIZE*(NDBLOCK+INDPERBUF+INDPERBUF+INDPERBUF+INDPERBUF⁴)
208 * while watching for overflow; in that case, return 0.
212 adduvlongov(uvlong a, uvlong b)
222 muluvlongov(uvlong a, uvlong b)
226 if (a != 0 && r/a != b || r < a || r < b)
235 uvlong max = NDBLOCK, ind = 1;
237 for (i = 0; i < NIBLOCK; i++) {
238 ind = muluvlongov(ind, INDPERBUF); /* power of INDPERBUF */
241 max = adduvlongov(max, ind);
245 return muluvlongov(max, BUFSIZE);
249 INDPERBUF = ((uvlong)INDPERBUF *INDPERBUF),
250 INDPERBUF⁴ = ((uvlong)INDPERBUF*INDPERBUF),
256 uvlong max = maxsize();
258 print("\tblock size = %d; ", RBUFSIZE);
260 print("max file size exceeds 2⁶⁴ bytes\n");
262 uvlong offlim = 1ULL << (sizeof(Off)*8 - 1);
266 print("max file size = %,llud\n", (Wideoff)max);
268 if (INDPERBUF/INDPERBUF != INDPERBUF)
269 print("overflow computing INDPERBUF\n");
270 if (INDPERBUF⁴/INDPERBUF != INDPERBUF)
271 print("overflow computing INDPERBUF⁴\n");
272 print("\tINDPERBUF = %d, INDPERBUF^4 = %,lld, ", INDPERBUF,
273 (Wideoff)INDPERBUF⁴);
274 print("CEPERBK = %d\n", CEPERBK);
275 print("\tsizeofs: Dentry = %d, Cache = %d\n",
276 sizeof(Dentry), sizeof(Cache));
282 fprint(2, "usage: %s [ -csC ] [-n service] [ -a ann-str ] [ -m dev-map ] [-f config-dev ]\n", argv0);
287 main(int argc, char **argv)
295 conf.confdev = "/dev/sdC0/cwfs";
300 case 'a': /* announce on this net */
301 ann = EARGF(usage());
302 if (nets >= Maxnets) {
303 fprint(2, "%s: too many networks to announce: %s\n",
305 exits("too many nets");
307 annstrs[nets++] = ann;
310 strcpy(service, EARGF(usage()));
316 if(open("/dev/cons", OREAD) < 0)
317 open("#c/cons", OREAD);
319 if(open("/dev/cons", OWRITE) < 0)
320 open("#c/cons", OWRITE);
322 case 'C': /* use new, faster cache layout */
328 case 'f': /* device / partition / file */
329 conf.confdev = EARGF(usage());
331 case 'm': /* name device-map file */
332 conf.devmap = EARGF(usage());
342 Binit(&bin, 0, OREAD);
345 print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n",
346 sizeof(Off)*8 - 1, NIBLOCK);
351 serveq = newqueue(1000, "9P service"); /* tunable */
352 raheadq = newqueue(1000, "readahead"); /* tunable */
358 files = malloc(conf.nfile * sizeof *files);
359 for(i=0; i < conf.nfile; i++) {
364 wpaths = malloc(conf.nwpath * sizeof(*wpaths));
365 uid = malloc(conf.nuid * sizeof(*uid));
366 gidspace = malloc(conf.gidspace * sizeof(*gidspace));
369 print("iobufinit\n");
373 boottime = time(nil);
381 * post filedescriptors to /srv
386 * Ethernet i/o processes
391 * read ahead processes
393 newproc(rahead, 0, "rah");
398 for(i=0; i < conf.nserve; i++)
399 newproc(serve, 0, "srv");
402 * worm "dump" copy process
404 newproc(wormcopy, 0, "wcp");
407 * "sync" copy process
409 newproc(synccopy, 0, "scp");
412 * processes to read the console
418 * read ahead processes.
419 * read message from q and then
423 rbcmp(void *va, void *vb)
433 if(ra->dev > rb->dev)
435 if(ra->dev < rb->dev)
437 if(ra->addr > rb->addr)
439 if(ra->addr < rb->addr)
452 rb[0] = fs_recv(raheadq, 0);
453 for(n = 1; n < nelem(rb); n++) {
454 if(raheadq->count <= 0)
456 rb[n] = fs_recv(raheadq, 0);
458 qsort(rb, n, sizeof rb[0], rbcmp);
459 for(i = 0; i < n; i++) {
462 p = getbuf(rb[i]->dev, rb[i]->addr, Brd);
466 rb[i]->link = rabuffree;
474 * main filesystem server loop.
475 * entered by many processes.
476 * they wait for message buffers and
488 /* read 9P request from a network input process */
489 mb = fs_recv(serveq, 0);
490 assert(mb->magic == Mbmagic);
491 /* fs kernel sets chan in /sys/src/fs/ip/il.c:/^getchan */
494 panic("serve: nil mb->chan");
501 panic("serve: nil mb->data");
502 /* better sniffing code in /sys/src/cmd/disk/kfs/9p12.c */
503 if(cp->protocol == nil){
504 /* do we recognise the protocol in this packet? */
505 /* better sniffing code: /sys/src/cmd/disk/kfs/9p12.c */
506 for(i = 0; fsprotocol[i] != nil; i++)
507 if(fsprotocol[i](mb) != 0) {
508 cp->protocol = fsprotocol[i];
511 if(cp->protocol == nil){
512 print("no protocol for message\n");
513 for(i = 0; i < 12; i++)
514 print(" %2.2uX", mb->data[i]);
518 /* process the request, generate an answer and reply */
523 runlock(&cp->reflock);
534 print("halted at %T.\n", time(nil));
535 postnote(PNGROUP, getpid(), "die");
540 DUMPTIME = 5, /* 5 am */
541 WEEKMASK = 0, /* every day (1=sun, 2=mon, 4=tue, etc.) */
545 * calculate the next dump time.
546 * minimum delay is 100 minutes.
551 Timet nddate = nextime(t+MINUTE(100), DUMPTIME, WEEKMASK);
554 print("next dump at %T\n", nddate);
559 * process to copy dump blocks from
560 * cache to worm. it runs flat out when
561 * it gets work, but only looks for
562 * work every 10 seconds.
568 Timet dt, t = 0, nddate = 0, ntoytime = 0;
575 nddate = nextdump(t); /* chatters */
576 ntoytime = time(nil);
579 if(dt < 0 || dt > MINUTE(100)) {
581 print("time went back\n");
583 print("time jumped ahead\n");
590 ntoytime = time(nil) + HOUR(1);
591 else if(t > nddate) {
593 print("automatic dump %T\n", t);
594 for(fs=filsys; fs->name; fs++)
595 if(fs->dev->type == Devcw)
601 for(fs=filsys; fs->name; fs++)
602 if(fs->dev->type == Devcw)
603 f |= dumpblock(fs->dev);
613 * process to synch blocks
614 * it puts out a block/cache-line every second
615 * it waits 10 seconds if caught up.
616 * in both cases, it takes about 10 seconds
639 char *ln, *end, *data = malloc(strlen(file) + 5 + 1);
645 end = strstr(data, "/data");
647 strcat(data, "/ctl");
650 bp = Bopen(data, OREAD);
652 while (rv < 0 && (ln = Brdline(bp, '\n')) != nil) {
653 ln[Blinelen(bp)-1] = '\0';
654 nf = tokenize(ln, fields, nelem(fields));
655 if (nf == 3 && strcmp(fields[0], "geometry") == 0)
656 rv = atoi(fields[2]);