journal.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <9p.h>
  7. #include "flashfs.h"
  8. enum
  9. {
  10. debug = 0,
  11. diags = 1,
  12. };
  13. typedef struct Gen Gen;
  14. typedef struct Sect Sect;
  15. struct Gen
  16. {
  17. int gnum;
  18. int count;
  19. int low;
  20. int high;
  21. Sect* head;
  22. Sect* tail;
  23. Sect* dup;
  24. Sect** vect;
  25. };
  26. struct Sect
  27. {
  28. int sect;
  29. ulong seq;
  30. int coff;
  31. int toff;
  32. int sum;
  33. ulong time;
  34. Sect* next;
  35. };
  36. static Gen gens[2];
  37. static Sect* freehead;
  38. static Sect* freetail;
  39. static int nfree;
  40. static int nbad;
  41. static ulong ltime;
  42. static int cursect;
  43. /*
  44. * If we have a delta then file times are in the future.
  45. * But they drift back to reality.
  46. */
  47. ulong
  48. now(void)
  49. {
  50. ulong cur, drift;
  51. static ulong last;
  52. cur = time(0);
  53. if(cur < last)
  54. delta += last - cur;
  55. else if(delta != 0 && last != 0) {
  56. drift = (cur - last + 1) / 2;
  57. if(drift > delta)
  58. delta = 0;
  59. else
  60. delta -= drift;
  61. }
  62. last = cur;
  63. return cur + delta;
  64. }
  65. static void
  66. damaged(char *mesg)
  67. {
  68. sysfatal("damaged filesystem: %s\n", mesg);
  69. }
  70. static void
  71. lddisc(char *mesg)
  72. {
  73. if(debug)
  74. fprint(2, "discard %s\n", mesg);
  75. }
  76. static Sect *
  77. getsect(void)
  78. {
  79. Sect *t;
  80. t = freehead;
  81. freehead = t->next;
  82. if(freehead == nil)
  83. freetail = nil;
  84. nfree--;
  85. return t;
  86. }
  87. static void
  88. newsect(Gen *g, Sect *s)
  89. {
  90. int m, n, err;
  91. uchar hdr[2*3];
  92. if(debug)
  93. fprint(2, "new %d %ld\n", g->gnum, s->seq);
  94. if(g->tail == nil)
  95. g->head = s;
  96. else
  97. g->tail->next = s;
  98. g->tail = s;
  99. s->next = nil;
  100. m = putc3(&hdr[0], g->gnum);
  101. n = putc3(&hdr[m], s->seq);
  102. s->toff = MAGSIZE + m + n;
  103. s->coff = s->toff + 4;
  104. s->time = NOTIME;
  105. s->sum = 0;
  106. err = 1;
  107. for(;;) {
  108. if(writedata(err, s->sect, hdr, m + n, MAGSIZE)
  109. && writedata(err, s->sect, magic, MAGSIZE, 0))
  110. break;
  111. clearsect(s->sect);
  112. err = 0;
  113. }
  114. }
  115. static Sect *
  116. newsum(Gen *g, ulong seq)
  117. {
  118. Sect *t;
  119. if(nfree == 0)
  120. damaged("no free sector for summary");
  121. t = getsect();
  122. t->seq = seq;
  123. newsect(g, t);
  124. return t;
  125. }
  126. static void
  127. freesect(Sect *s)
  128. {
  129. clearsect(s->sect);
  130. if(freetail == nil)
  131. freehead = s;
  132. else
  133. freetail->next = s;
  134. freetail = s;
  135. s->next = nil;
  136. nfree++;
  137. }
  138. static void
  139. dupsect(Sect *s, int renum)
  140. {
  141. Sect *t;
  142. Renum r;
  143. uchar *b;
  144. int err, n;
  145. ulong doff, off;
  146. if(nfree == 0)
  147. damaged("no free for copy");
  148. t = getsect();
  149. b = sectbuff;
  150. off = s->coff;
  151. readdata(s->sect, b, off, 0);
  152. doff = s->toff;
  153. if(s->time == NOTIME)
  154. doff += 4;
  155. // Window 5
  156. err = 1;
  157. for(;;) {
  158. if(writedata(err, t->sect, b + 1, s->toff - 1, 1)
  159. && writedata(err, t->sect, b + doff, off - doff, doff)
  160. && writedata(err, t->sect, b, 1, 0))
  161. break;
  162. clearsect(t->sect);
  163. err = 0;
  164. }
  165. if(renum) {
  166. r.old = s->sect;
  167. r.new = t->sect;
  168. erenum(&r);
  169. }
  170. n = s->sect;
  171. s->sect = t->sect;
  172. t->sect = n;
  173. freesect(t);
  174. if(cursect >= 0)
  175. readdata(cursect, b, sectsize, 0);
  176. }
  177. static void
  178. gswap(void)
  179. {
  180. Gen t;
  181. t = gens[0];
  182. gens[0] = gens[1];
  183. gens[1] = t;
  184. }
  185. static void
  186. checkdata(void)
  187. {
  188. Gen *g;
  189. g = &gens[0];
  190. if(g->dup != nil) { // Window 5 damage
  191. if(diags)
  192. fprint(2, "%s: window 5 damage\n", argv0);
  193. freesect(g->dup);
  194. g->dup = nil;
  195. }
  196. }
  197. static void
  198. checksweep(void)
  199. {
  200. Gen *g;
  201. Jrec j;
  202. uchar *b;
  203. int n, op;
  204. Sect *s, *t, *u;
  205. long off, seq, soff;
  206. g = &gens[1];
  207. if(g->dup != nil) { // Window 5 damage
  208. if(diags)
  209. fprint(2, "%s: window 5 damage\n", argv0);
  210. freesect(g->dup);
  211. g->dup = nil;
  212. }
  213. s = g->head;
  214. if(s != g->tail) {
  215. while(s->next != g->tail)
  216. s = s->next;
  217. }
  218. b = sectbuff;
  219. op = -1;
  220. seq = -1;
  221. soff = 0;
  222. u = nil;
  223. t = s;
  224. for(;;) {
  225. readdata(t->sect, b, sectsize, 0);
  226. off = t->toff + 4;
  227. for(;;) {
  228. n = convM2J(&j, &b[off]);
  229. if(n < 0) {
  230. if(j.type != 0xFF) {
  231. if(debug)
  232. fprint(2, "s[%d] @ %d %ld\n", j.type, t->sect, off);
  233. damaged("bad Jrec");
  234. }
  235. break;
  236. }
  237. switch(j.type) {
  238. case FT_SUMMARY:
  239. case FT_SUMBEG:
  240. seq = j.seq;
  241. case FT_SUMEND:
  242. op = j.type;
  243. soff = off;
  244. u = t;
  245. break;
  246. case FT_WRITE:
  247. case FT_AWRITE:
  248. off += j.size;
  249. }
  250. off += n;
  251. }
  252. t = t->next;
  253. if(t == nil)
  254. break;
  255. }
  256. if(op == FT_SUMBEG) { // Window 1 damage
  257. if(diags)
  258. fprint(2, "%s: window 1 damage\n", argv0);
  259. if(u != s) {
  260. freesect(u);
  261. s->next = nil;
  262. g->tail = s;
  263. }
  264. s->coff = soff;
  265. dupsect(s, 0);
  266. seq--;
  267. }
  268. if(seq >= 0) {
  269. g = &gens[0];
  270. if(seq > g->low)
  271. damaged("high sweep");
  272. if(seq == g->low) { // Window 2 damage
  273. if(diags)
  274. fprint(2, "%s: window 2 damage\n", argv0);
  275. s = g->head;
  276. g->head = s->next;
  277. freesect(s);
  278. if(g->head == nil) {
  279. g->tail = nil;
  280. g->gnum += 2;
  281. newsum(g, 0);
  282. gswap();
  283. }
  284. }
  285. }
  286. }
  287. void
  288. load1(Sect *s, int parity)
  289. {
  290. int n;
  291. Jrec j;
  292. uchar *b;
  293. char *err;
  294. Extent *x;
  295. Entry *d, *e;
  296. ulong ctime, off, mtime;
  297. if(s->sect < 0 && readonly) // readonly damaged
  298. return;
  299. b = sectbuff;
  300. readdata(s->sect, b, sectsize, 0);
  301. s->sum = 0;
  302. off = s->toff;
  303. ctime = get4(&b[off]);
  304. off += 4;
  305. for(;;) {
  306. n = convM2J(&j, &b[off]);
  307. if(n < 0) {
  308. if(j.type != 0xFF) {
  309. if(debug)
  310. fprint(2, "l[%d] @ %d %ld\n", j.type, s->sect, off);
  311. damaged("bad Jrec");
  312. }
  313. s->coff = off;
  314. break;
  315. }
  316. off += n;
  317. if(debug)
  318. fprint(2, "get %J\n", &j);
  319. switch(j.type) {
  320. case FT_create:
  321. ctime += j.mtime;
  322. create:
  323. d = elookup(j.parent);
  324. if(d == nil) {
  325. lddisc("parent");
  326. break;
  327. }
  328. d->ref++;
  329. e = ecreate(d, j.name, j.fnum, j.mode, ctime, &err);
  330. if(e == nil) {
  331. d->ref--;
  332. lddisc("create");
  333. break;
  334. }
  335. e->ref--;
  336. if(j.type == FT_trunc)
  337. e->mode = j.mode;
  338. break;
  339. case FT_chmod:
  340. e = elookup(j.fnum);
  341. if(e == nil) {
  342. lddisc("lookup");
  343. break;
  344. }
  345. echmod(e, j.mode, j.mnum);
  346. break;
  347. case FT_REMOVE:
  348. e = elookup(j.fnum);
  349. if(e == nil) {
  350. lddisc("lookup");
  351. break;
  352. }
  353. if(eremove(e) != nil) {
  354. lddisc("remove");
  355. break;
  356. }
  357. break;
  358. case FT_AWRITE:
  359. mtime = 0;
  360. goto write;
  361. case FT_WRITE:
  362. ctime += j.mtime;
  363. mtime = ctime;
  364. write:
  365. x = emalloc9p(sizeof(Extent));
  366. x->sect = s->sect;
  367. x->addr = off;
  368. x->off = j.offset;
  369. x->size = j.size;
  370. off += j.size;
  371. e = elookup(j.fnum);
  372. if(e == nil) {
  373. lddisc("lookup");
  374. break;
  375. }
  376. ewrite(e, x, parity, mtime);
  377. break;
  378. case FT_trunc:
  379. ctime += j.mtime;
  380. e = elookup(j.tnum);
  381. if(e == nil) {
  382. if(debug)
  383. fprint(2, "-> create\n");
  384. goto create;
  385. }
  386. etrunc(e, j.fnum, ctime);
  387. break;
  388. case FT_SUMMARY:
  389. case FT_SUMBEG:
  390. case FT_SUMEND:
  391. s->sum += n;
  392. break;
  393. default:
  394. damaged("load1 botch");
  395. }
  396. }
  397. if(s->sum > Nsum)
  398. s->sum = Nsum;
  399. s->time = ctime;
  400. if(ctime != NOTIME && ctime > ltime)
  401. ltime = ctime;
  402. }
  403. void
  404. load0(int parity)
  405. {
  406. Sect *s;
  407. if(debug)
  408. fprint(2, "load %d\n", parity);
  409. for(s = gens[parity].head; s != nil; s = s->next)
  410. load1(s, parity);
  411. }
  412. void
  413. loadfs(int ro)
  414. {
  415. Gen *g;
  416. Sect *s;
  417. ulong u, v;
  418. int i, j, n;
  419. uchar hdr[MAXHDR];
  420. readonly = ro;
  421. fmtinstall('J', Jconv);
  422. for(i = 0; i < 2; i++) {
  423. g = &gens[i];
  424. g->gnum = -1;
  425. g->low = nsects;
  426. g->high = -1;
  427. g->count = 0;
  428. g->head = nil;
  429. g->tail = nil;
  430. }
  431. for(i = 0; i < nsects; i++) {
  432. readdata(i, hdr, MAXHDR, 0);
  433. if(memcmp(hdr, magic, MAGSIZE) == 0) {
  434. n = MAGSIZE + getc3(&hdr[MAGSIZE], &u);
  435. getc3(&hdr[n], &v);
  436. if(debug)
  437. fprint(2, "%d: %ld %ld\n", i, u, v);
  438. for(j = 0; j < 2; j++) {
  439. g = &gens[j];
  440. if(g->gnum == u) {
  441. g->count++;
  442. if(v < g->low)
  443. g->low = v;
  444. if(v > g->high)
  445. g->high = v;
  446. break;
  447. }
  448. else if(g->gnum < 0) {
  449. g->gnum = u;
  450. g->count = 1;
  451. g->low = v;
  452. g->high = v;
  453. break;
  454. }
  455. }
  456. if(j == 2)
  457. damaged("unexpected generation");
  458. }
  459. else if(hdr[0] == 0xFF) {
  460. nfree++;
  461. s = emalloc9p(sizeof(Sect));
  462. s->sect = i;
  463. s->next = freehead;
  464. freehead = s;
  465. if(freetail == nil)
  466. freetail = s;
  467. }
  468. else
  469. nbad++;
  470. }
  471. if(nbad > 0)
  472. damaged("bad sectors");
  473. if(gens[0].gnum < 0)
  474. damaged("no data");
  475. if(gens[1].gnum < 0) { // Window 3 death
  476. if(diags)
  477. fprint(2, "%s: window 3 damage\n", argv0);
  478. g = &gens[1];
  479. g->gnum = gens[0].gnum + 1;
  480. g->low = 0;
  481. g->high = 0;
  482. g->count = 1;
  483. if(!readonly)
  484. newsum(g, 0);
  485. }
  486. if(gens[0].gnum > gens[1].gnum)
  487. gswap();
  488. for(i = 0; i < 2; i++) {
  489. g = &gens[i];
  490. n = g->count;
  491. if(n <= g->high - g->low)
  492. damaged("missing sectors");
  493. g->vect = emalloc9p(n * sizeof(Sect *));
  494. for(j = 0; j < n; j++) {
  495. s = emalloc9p(sizeof(Sect));
  496. s->sect = -1;
  497. g->vect[j] = s;
  498. }
  499. }
  500. if(debug) {
  501. for(j = 0; j < 2; j++) {
  502. g = &gens[j];
  503. print("%d\t%d\t%d-%d\n", g->gnum, g->count, g->low, g->high);
  504. }
  505. }
  506. for(i = 0; i < nsects; i++) {
  507. readdata(i, hdr, MAXHDR, 0);
  508. if(memcmp(hdr, magic, MAGSIZE) == 0) {
  509. n = MAGSIZE + getc3(&hdr[MAGSIZE], &u);
  510. n += getc3(&hdr[n], &v);
  511. g = nil;
  512. for(j = 0; j < 2; j++) {
  513. g = &gens[j];
  514. if(g->gnum == u)
  515. break;
  516. }
  517. if(j == 2)
  518. damaged("generation botch");
  519. s = g->vect[v - g->low];
  520. s->seq = v;
  521. s->toff = n;
  522. if(s->sect < 0)
  523. s->sect = i;
  524. else if(v == g->high && g->dup == nil) {
  525. s = emalloc9p(sizeof(Sect));
  526. s->sect = i;
  527. g->dup = s;
  528. }
  529. else
  530. damaged("dup block");
  531. }
  532. }
  533. for(j = 0; j < 2; j++) {
  534. g = &gens[j];
  535. for(i = 0; i < g->count; i++) {
  536. s = g->vect[i];
  537. if(g->tail == nil)
  538. g->head = s;
  539. else
  540. g->tail->next = s;
  541. g->tail = s;
  542. s->next = nil;
  543. }
  544. free(g->vect);
  545. }
  546. cursect = -1;
  547. if(!readonly) {
  548. checkdata();
  549. checksweep();
  550. }
  551. load0(1);
  552. load0(0);
  553. if(ltime != 0) {
  554. u = now();
  555. if(u < ltime) {
  556. delta = ltime - u;
  557. if(diags)
  558. fprint(2, "%s: check clock: delta = %lud\n", argv0, delta);
  559. }
  560. }
  561. limit = 80 * nsects * sectsize / 100;
  562. maxwrite = sectsize - MAXHDR - Nwrite - Nsum;
  563. if(maxwrite > WRSIZE)
  564. maxwrite = WRSIZE;
  565. }
  566. static int
  567. sputw(Sect *s, Jrec *j, int mtime, Extent *x, void *a)
  568. {
  569. ulong t;
  570. int err, n, r;
  571. uchar buff[Nmax], type[1];
  572. if(debug)
  573. fprint(2, "put %J\n", j);
  574. if(mtime) {
  575. t = j->mtime;
  576. if(s->time == NOTIME) {
  577. put4(buff, t);
  578. if(!writedata(1, s->sect, buff, 4, s->toff)) {
  579. dupsect(s, 1);
  580. writedata(0, s->sect, buff, 4, s->toff);
  581. }
  582. s->time = t;
  583. j->mtime = 0;
  584. }
  585. else {
  586. j->mtime = t - s->time;
  587. s->time = t;
  588. }
  589. }
  590. n = convJ2M(j, buff);
  591. if(n < 0)
  592. damaged("convJ2M");
  593. // Window 4
  594. err = 2;
  595. for(;;) {
  596. err--;
  597. if(!err)
  598. dupsect(s, 1); // Window 4 damage
  599. t = s->coff + 1;
  600. if(!writedata(err, s->sect, buff, n, t))
  601. continue;
  602. t += n;
  603. r = n;
  604. if(x != nil) {
  605. x->sect = s->sect;
  606. x->addr = t;
  607. if(!writedata(err, s->sect, a, j->size, t))
  608. continue;
  609. t += j->size;
  610. r += j->size;
  611. }
  612. type[0] = j->type;
  613. if(!writedata(err, s->sect, type, 1, s->coff))
  614. continue;
  615. r++;
  616. break;
  617. }
  618. s->coff = t;
  619. return r;
  620. }
  621. static void
  622. summarize(void)
  623. {
  624. Gen *g;
  625. uchar *b;
  626. Entry *e;
  627. Extent *x;
  628. Jrec j, sum;
  629. Sect *s, *t;
  630. ulong off, ctime;
  631. int n, bytes, more, mtime, sumd;
  632. g = &gens[eparity];
  633. s = g->head;
  634. g->head = s->next;
  635. if(g->head == nil)
  636. g->tail = nil;
  637. g = &gens[eparity^1];
  638. t = g->tail;
  639. b = sectbuff;
  640. x = nil;
  641. if(debug)
  642. fprint(2, "summarize\n");
  643. for(;;) { // Window 1
  644. readdata(s->sect, b, sectsize, 0);
  645. off = s->toff;
  646. ctime = get4(&b[off]);
  647. off += 4;
  648. sumd = 0;
  649. cursect = s->sect;
  650. while(b[off] != 0xFF) {
  651. n = convM2J(&j, &b[off]);
  652. if(n < 0)
  653. damaged("bad Jrec");
  654. if(debug)
  655. fprint(2, "read %J\n", &j);
  656. off += n;
  657. bytes = n;
  658. mtime = 0;
  659. switch(j.type) {
  660. case FT_create:
  661. ctime += j.mtime;
  662. mtime = 1;
  663. create:
  664. e = elookup(j.fnum);
  665. if(e == nil)
  666. continue;
  667. break;
  668. case FT_chmod:
  669. e = elookup(j.fnum);
  670. if(e == nil || j.mnum != e->mnum)
  671. continue;
  672. break;
  673. case FT_REMOVE:
  674. e = elookup(j.fnum);
  675. if(e == nil)
  676. continue;
  677. break;
  678. case FT_trunc:
  679. ctime += j.mtime;
  680. mtime = 1;
  681. e = elookup(j.tnum);
  682. if(e == nil) {
  683. if(debug)
  684. fprint(2, "-> create\n");
  685. j.type = FT_create;
  686. goto create;
  687. }
  688. break;
  689. case FT_AWRITE:
  690. goto write;
  691. case FT_WRITE:
  692. ctime += j.mtime;
  693. mtime = 1;
  694. write:
  695. e = elookup(j.fnum);
  696. if(e == nil) {
  697. off += j.size;
  698. continue;
  699. }
  700. x = esum(e, s->sect, off, &more);
  701. if(x == nil) {
  702. damaged("missing extent");
  703. off += j.size;
  704. continue;
  705. }
  706. if(more) {
  707. j.type = FT_AWRITE;
  708. mtime = 0;
  709. }
  710. bytes += j.size;
  711. break;
  712. case FT_SUMMARY:
  713. case FT_SUMBEG:
  714. case FT_SUMEND:
  715. continue;
  716. default:
  717. damaged("summarize botch");
  718. }
  719. if(!sumd) {
  720. if(t->coff + Nsumbeg >= sectsize - 1)
  721. t = newsum(g, t->seq + 1);
  722. sum.type = FT_SUMBEG;
  723. sum.seq = s->seq;
  724. if(debug)
  725. fprint(2, "+ %J\n", &sum);
  726. t->sum += sputw(t, &sum, 0, nil, nil);
  727. if(t->sum >= Nsum)
  728. t->sum = Nsum;
  729. sumd = 1;
  730. }
  731. if(t->coff + bytes >= sectsize - Nsum + t->sum - 1)
  732. t = newsum(g, t->seq + 1);
  733. if(mtime)
  734. j.mtime = ctime;
  735. switch(j.type) {
  736. case FT_AWRITE:
  737. case FT_WRITE:
  738. sputw(t, &j, mtime, x, &b[off]);
  739. off += j.size;
  740. break;
  741. default:
  742. sputw(t, &j, mtime, nil, nil);
  743. }
  744. }
  745. cursect = -1;
  746. if(t->coff + Nsumbeg >= sectsize - 1)
  747. t = newsum(g, t->seq + 1);
  748. if(sumd)
  749. sum.type = FT_SUMEND;
  750. else {
  751. sum.type = FT_SUMMARY;
  752. sum.seq = s->seq;
  753. }
  754. if(debug)
  755. fprint(2, "+ %J\n", &sum);
  756. t->sum += sputw(t, &sum, 0, nil, nil);
  757. if(t->sum >= Nsum)
  758. t->sum = Nsum;
  759. // Window 2
  760. freesect(s);
  761. g = &gens[eparity];
  762. s = g->head;
  763. if(s == nil) {
  764. // Window 3
  765. g->gnum += 2;
  766. newsum(g, 0);
  767. eparity ^= 1;
  768. return;
  769. }
  770. if(nfree >= Nfree)
  771. return;
  772. g->head = s->next;
  773. if(g->head == nil)
  774. g->tail = nil;
  775. g = &gens[eparity^1];
  776. }
  777. }
  778. char *
  779. need(int bytes)
  780. {
  781. Gen *g;
  782. int sums;
  783. Sect *s, *t;
  784. sums = 0;
  785. for(;;) {
  786. s = gens[eparity].tail;
  787. if(s->coff + bytes < sectsize - Nsum + s->sum - 1)
  788. return nil;
  789. if(nfree >= Nfree)
  790. break;
  791. if(sums == 2) {
  792. readonly = 1;
  793. return "generation full";
  794. }
  795. summarize();
  796. sums++;
  797. }
  798. g = &gens[eparity];
  799. t = getsect();
  800. t->seq = g->tail->seq + 1;
  801. newsect(g, t);
  802. return nil;
  803. }
  804. void
  805. putw(Jrec *j, int mtime, Extent *x, void *a)
  806. {
  807. sputw(gens[eparity].tail, j, mtime, x, a);
  808. }
  809. void
  810. put(Jrec *j, int mtime)
  811. {
  812. sputw(gens[eparity].tail, j, mtime, nil, nil);
  813. }