main.c 11 KB

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