main.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* cached-worm file server */
  2. #include "all.h"
  3. #include "io.h"
  4. #include "9p1.h"
  5. Map *devmap;
  6. Biobuf bin;
  7. void
  8. machinit(void)
  9. {
  10. active.exiting = 0;
  11. }
  12. /*
  13. * Put a string on the console.
  14. */
  15. void
  16. puts(char *s, int n)
  17. {
  18. print("%.*s", n, s);
  19. }
  20. void
  21. prflush(void)
  22. {
  23. }
  24. /*
  25. * Print a string on the console.
  26. */
  27. void
  28. putstrn(char *str, int n)
  29. {
  30. puts(str, n);
  31. }
  32. /*
  33. * get a character from the console
  34. */
  35. int
  36. getc(void)
  37. {
  38. return Bgetrune(&bin);
  39. }
  40. void
  41. panic(char *fmt, ...)
  42. {
  43. int n;
  44. va_list arg;
  45. char buf[PRINTSIZE];
  46. va_start(arg, fmt);
  47. n = vseprint(buf, buf + sizeof buf, fmt, arg) - buf;
  48. va_end(arg);
  49. buf[n] = '\0';
  50. print("panic: %s\n", buf);
  51. exit();
  52. }
  53. int
  54. okay(char *quest)
  55. {
  56. char *ln;
  57. print("okay to %s? ", quest);
  58. if ((ln = Brdline(&bin, '\n')) == nil)
  59. return 0;
  60. ln[Blinelen(&bin)-1] = '\0';
  61. if (isascii(*ln) && isupper(*ln))
  62. *ln = tolower(*ln);
  63. return *ln == 'y';
  64. }
  65. static void
  66. mapinit(char *mapfile)
  67. {
  68. int nf;
  69. char *ln;
  70. char *fields[2];
  71. Biobuf *bp;
  72. Map *map;
  73. if (mapfile == nil)
  74. return;
  75. bp = Bopen(mapfile, OREAD);
  76. if (bp == nil)
  77. sysfatal("can't read %s", mapfile);
  78. devmap = nil;
  79. while ((ln = Brdline(bp, '\n')) != nil) {
  80. ln[Blinelen(bp)-1] = '\0';
  81. if (*ln == '\0' || *ln == '#')
  82. continue;
  83. nf = tokenize(ln, fields, nelem(fields));
  84. if (nf != 2)
  85. continue;
  86. if(testconfig(fields[0]) != 0) {
  87. print("bad `from' device %s in %s\n",
  88. fields[0], mapfile);
  89. continue;
  90. }
  91. map = malloc(sizeof *map);
  92. map->from = strdup(fields[0]);
  93. map->to = strdup(fields[1]);
  94. map->fdev = iconfig(fields[0]);
  95. if(testconfig(fields[1]) == 0)
  96. map->tdev = iconfig(fields[1]);
  97. /* else map->to is the replacement file name */
  98. map->next = devmap;
  99. devmap = map;
  100. }
  101. Bterm(bp);
  102. }
  103. static void
  104. confinit(void)
  105. {
  106. conf.nmach = 1;
  107. conf.mem = meminit();
  108. conf.nuid = 1000;
  109. conf.nserve = 15; /* tunable */
  110. conf.nfile = 30000;
  111. conf.nlgmsg = 100;
  112. conf.nsmmsg = 500;
  113. localconfinit();
  114. conf.nwpath = conf.nfile*8;
  115. conf.nauth = conf.nfile/10;
  116. conf.gidspace = conf.nuid*3;
  117. cons.flags = 0;
  118. if (conf.devmap)
  119. mapinit(conf.devmap);
  120. }
  121. /*
  122. * compute BUFSIZE*(NDBLOCK+INDPERBUF+INDPERBUF⁲+INDPERBUF⁳+INDPERBUF⁴)
  123. * while watching for overflow; in that case, return 0.
  124. */
  125. static uvlong
  126. adduvlongov(uvlong a, uvlong b)
  127. {
  128. uvlong r = a + b;
  129. if (r < a || r < b)
  130. return 0;
  131. return r;
  132. }
  133. static uvlong
  134. muluvlongov(uvlong a, uvlong b)
  135. {
  136. uvlong r = a * b;
  137. if (a != 0 && r/a != b || r < a || r < b)
  138. return 0;
  139. return r;
  140. }
  141. static uvlong
  142. maxsize(void)
  143. {
  144. int i;
  145. uvlong max = NDBLOCK, ind = 1;
  146. for (i = 0; i < NIBLOCK; i++) {
  147. ind = muluvlongov(ind, INDPERBUF); /* power of INDPERBUF */
  148. if (ind == 0)
  149. return 0;
  150. max = adduvlongov(max, ind);
  151. if (max == 0)
  152. return 0;
  153. }
  154. return muluvlongov(max, BUFSIZE);
  155. }
  156. enum {
  157. INDPERBUF⁲ = ((uvlong)INDPERBUF *INDPERBUF),
  158. INDPERBUF⁴ = ((uvlong)INDPERBUF⁲*INDPERBUF⁲),
  159. };
  160. static void
  161. printsizes(void)
  162. {
  163. uvlong max = maxsize();
  164. print("\tblock size = %d; ", RBUFSIZE);
  165. if (max == 0)
  166. print("max file size exceeds 2⁶⁴ bytes\n");
  167. else {
  168. uvlong offlim = 1ULL << (sizeof(Off)*8 - 1);
  169. if (max >= offlim)
  170. max = offlim - 1;
  171. print("max file size = %,llud\n", (Wideoff)max);
  172. }
  173. if (INDPERBUF⁲/INDPERBUF != INDPERBUF)
  174. print("overflow computing INDPERBUF⁲\n");
  175. if (INDPERBUF⁴/INDPERBUF⁲ != INDPERBUF⁲)
  176. print("overflow computing INDPERBUF⁴\n");
  177. print("\tINDPERBUF = %d, INDPERBUF^4 = %,lld, ", INDPERBUF,
  178. (Wideoff)INDPERBUF⁴);
  179. print("CEPERBK = %d\n", CEPERBK);
  180. print("\tsizeofs: Dentry = %d, Cache = %d\n",
  181. sizeof(Dentry), sizeof(Cache));
  182. }
  183. void
  184. usage(void)
  185. {
  186. fprint(2, "usage: %s [-f][-a ann-str][-m dev-map] config-dev\n", argv0);
  187. exits("usage");
  188. }
  189. void
  190. main(int argc, char **argv)
  191. {
  192. int i, nets = 0;
  193. char *ann;
  194. rfork(RFNOTEG);
  195. formatinit();
  196. machinit();
  197. conf.confdev = "n"; /* Devnone */
  198. ARGBEGIN{
  199. case 'a':
  200. ann = EARGF(usage());
  201. if (nets >= Maxnets) {
  202. fprint(2, "%s: too many networks to announce: %s\n",
  203. argv0, ann);
  204. exits("too many nets");
  205. }
  206. annstrs[nets++] = ann;
  207. break;
  208. case 'f':
  209. conf.configfirst++;
  210. break;
  211. case 'm':
  212. conf.devmap = EARGF(usage());
  213. break;
  214. default:
  215. usage();
  216. break;
  217. }ARGEND
  218. if (argc != 1)
  219. usage();
  220. conf.confdev = argv[0]; /* config string for dev holding full config */
  221. Binit(&bin, 0, OREAD);
  222. confinit();
  223. print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n",
  224. sizeof(Off)*8 - 1, NIBLOCK);
  225. printsizes();
  226. qlock(&reflock);
  227. qunlock(&reflock);
  228. serveq = newqueue(1000, "9P service"); /* tunable */
  229. raheadq = newqueue(1000, "readahead"); /* tunable */
  230. mbinit();
  231. netinit();
  232. scsiinit();
  233. files = malloc(conf.nfile * sizeof *files);
  234. for(i=0; i < conf.nfile; i++) {
  235. qlock(&files[i]);
  236. qunlock(&files[i]);
  237. }
  238. wpaths = malloc(conf.nwpath * sizeof(*wpaths));
  239. uid = malloc(conf.nuid * sizeof(*uid));
  240. gidspace = malloc(conf.gidspace * sizeof(*gidspace));
  241. authinit();
  242. print("iobufinit\n");
  243. iobufinit();
  244. arginit();
  245. boottime = time(nil);
  246. print("sysinit\n");
  247. sysinit();
  248. /*
  249. * Ethernet i/o processes
  250. */
  251. netstart();
  252. /*
  253. * read ahead processes
  254. */
  255. newproc(rahead, 0, "rah");
  256. /*
  257. * server processes
  258. */
  259. for(i=0; i < conf.nserve; i++)
  260. newproc(serve, 0, "srv");
  261. /*
  262. * worm "dump" copy process
  263. */
  264. newproc(wormcopy, 0, "wcp");
  265. /*
  266. * processes to read the console
  267. */
  268. consserve();
  269. /*
  270. * "sync" copy process
  271. * this doesn't return.
  272. */
  273. procsetname("scp");
  274. synccopy();
  275. }
  276. /*
  277. * read ahead processes.
  278. * read message from q and then
  279. * read the device.
  280. */
  281. int
  282. rbcmp(void *va, void *vb)
  283. {
  284. Rabuf *ra, *rb;
  285. ra = *(Rabuf**)va;
  286. rb = *(Rabuf**)vb;
  287. if(rb == 0)
  288. return 1;
  289. if(ra == 0)
  290. return -1;
  291. if(ra->dev > rb->dev)
  292. return 1;
  293. if(ra->dev < rb->dev)
  294. return -1;
  295. if(ra->addr > rb->addr)
  296. return 1;
  297. if(ra->addr < rb->addr)
  298. return -1;
  299. return 0;
  300. }
  301. void
  302. rahead(void *)
  303. {
  304. Rabuf *rb[50];
  305. Iobuf *p;
  306. int i, n;
  307. for (;;) {
  308. rb[0] = fs_recv(raheadq, 0);
  309. for(n = 1; n < nelem(rb); n++) {
  310. if(raheadq->count <= 0)
  311. break;
  312. rb[n] = fs_recv(raheadq, 0);
  313. }
  314. qsort(rb, n, sizeof rb[0], rbcmp);
  315. for(i = 0; i < n; i++) {
  316. if(rb[i] == 0)
  317. continue;
  318. p = getbuf(rb[i]->dev, rb[i]->addr, Brd);
  319. if(p)
  320. putbuf(p);
  321. lock(&rabuflock);
  322. rb[i]->link = rabuffree;
  323. rabuffree = rb[i];
  324. unlock(&rabuflock);
  325. }
  326. }
  327. }
  328. /*
  329. * main filesystem server loop.
  330. * entered by many processes.
  331. * they wait for message buffers and
  332. * then process them.
  333. */
  334. void
  335. serve(void *)
  336. {
  337. int i;
  338. Chan *cp;
  339. Msgbuf *mb;
  340. for (;;) {
  341. qlock(&reflock);
  342. /* read 9P request from a network input process */
  343. mb = fs_recv(serveq, 0);
  344. assert(mb->magic == Mbmagic);
  345. /* fs kernel sets chan in /sys/src/fs/ip/il.c:/^getchan */
  346. cp = mb->chan;
  347. if (cp == nil)
  348. panic("serve: nil mb->chan");
  349. rlock(&cp->reflock);
  350. qunlock(&reflock);
  351. rlock(&mainlock);
  352. if (mb->data == nil)
  353. panic("serve: nil mb->data");
  354. /* better sniffing code in /sys/src/cmd/disk/kfs/9p12.c */
  355. if(cp->protocol == nil){
  356. /* do we recognise the protocol in this packet? */
  357. /* better sniffing code: /sys/src/cmd/disk/kfs/9p12.c */
  358. for(i = 0; fsprotocol[i] != nil; i++)
  359. if(fsprotocol[i](mb) != 0) {
  360. cp->protocol = fsprotocol[i];
  361. break;
  362. }
  363. if(cp->protocol == nil){
  364. print("no protocol for message\n");
  365. for(i = 0; i < 12; i++)
  366. print(" %2.2uX", mb->data[i]);
  367. print("\n");
  368. }
  369. } else
  370. /* process the request, generate an answer and reply */
  371. cp->protocol(mb);
  372. mbfree(mb);
  373. runlock(&mainlock);
  374. runlock(&cp->reflock);
  375. }
  376. }
  377. void
  378. exit(void)
  379. {
  380. lock(&active);
  381. active.exiting = 1;
  382. unlock(&active);
  383. print("halted at %T.\n", time(nil));
  384. postnote(PNGROUP, getpid(), "die");
  385. exits(nil);
  386. }
  387. enum {
  388. DUMPTIME = 5, /* 5 am */
  389. WEEKMASK = 0, /* every day (1=sun, 2=mon, 4=tue, etc.) */
  390. };
  391. /*
  392. * calculate the next dump time.
  393. * minimum delay is 100 minutes.
  394. */
  395. Timet
  396. nextdump(Timet t)
  397. {
  398. Timet nddate = nextime(t+MINUTE(100), DUMPTIME, WEEKMASK);
  399. if(!conf.nodump)
  400. print("next dump at %T\n", nddate);
  401. return nddate;
  402. }
  403. /*
  404. * process to copy dump blocks from
  405. * cache to worm. it runs flat out when
  406. * it gets work, but only looks for
  407. * work every 10 seconds.
  408. */
  409. void
  410. wormcopy(void *)
  411. {
  412. int f, dorecalc = 1;
  413. Timet dt, t = 0, nddate = 0, ntoytime = 0;
  414. Filsys *fs;
  415. for (;;) {
  416. if (dorecalc) {
  417. dorecalc = 0;
  418. t = time(nil);
  419. nddate = nextdump(t); /* chatters */
  420. ntoytime = time(nil);
  421. }
  422. dt = time(nil) - t;
  423. if(dt < 0 || dt > MINUTE(100)) {
  424. if(dt < 0)
  425. print("time went back\n");
  426. else
  427. print("time jumped ahead\n");
  428. dorecalc = 1;
  429. continue;
  430. }
  431. t += dt;
  432. f = 0;
  433. if(t > ntoytime)
  434. ntoytime = time(nil) + HOUR(1);
  435. else if(t > nddate) {
  436. if(!conf.nodump) {
  437. print("automatic dump %T\n", t);
  438. for(fs=filsys; fs->name; fs++)
  439. if(fs->dev->type == Devcw)
  440. cfsdump(fs);
  441. }
  442. dorecalc = 1;
  443. } else {
  444. rlock(&mainlock);
  445. for(fs=filsys; fs->name; fs++)
  446. if(fs->dev->type == Devcw)
  447. f |= dumpblock(fs->dev);
  448. runlock(&mainlock);
  449. if(!f)
  450. delay(10000);
  451. wormprobe();
  452. }
  453. }
  454. }
  455. /*
  456. * process to synch blocks
  457. * it puts out a block/cache-line every second
  458. * it waits 10 seconds if caught up.
  459. * in both cases, it takes about 10 seconds
  460. * to get up-to-date.
  461. */
  462. void
  463. synccopy(void)
  464. {
  465. int f;
  466. for (;;) {
  467. rlock(&mainlock);
  468. f = syncblock();
  469. runlock(&mainlock);
  470. if(!f)
  471. delay(10000);
  472. else
  473. delay(1000);
  474. }
  475. }
  476. Devsize
  477. inqsize(char *file)
  478. {
  479. int nf;
  480. char *ln, *end, *data = malloc(strlen(file) + 5 + 1);
  481. char *fields[4];
  482. Devsize rv = -1;
  483. Biobuf *bp;
  484. strcpy(data, file);
  485. end = strstr(data, "/data");
  486. if (end == nil)
  487. strcat(end, "/ctl");
  488. else
  489. strcpy(end, "/ctl");
  490. bp = Bopen(data, OREAD);
  491. if (bp) {
  492. while (rv < 0 && (ln = Brdline(bp, '\n')) != nil) {
  493. ln[Blinelen(bp)-1] = '\0';
  494. nf = tokenize(ln, fields, nelem(fields));
  495. if (nf == 3 && strcmp(fields[0], "geometry") == 0)
  496. rv = atoi(fields[2]);
  497. }
  498. Bterm(bp);
  499. }
  500. free(data);
  501. return rv;
  502. }