main.c 10 KB

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