xref: /plan9/sys/src/cmd/aux/flashfs/journal.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier #include <fcall.h>
59a747e4fSDavid du Colombier #include <thread.h>
69a747e4fSDavid du Colombier #include <9p.h>
79a747e4fSDavid du Colombier #include "flashfs.h"
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier enum
109a747e4fSDavid du Colombier {
119a747e4fSDavid du Colombier 	debug	= 0,
129a747e4fSDavid du Colombier 	diags	= 1,
139a747e4fSDavid du Colombier };
149a747e4fSDavid du Colombier 
159a747e4fSDavid du Colombier typedef struct	Gen	Gen;
169a747e4fSDavid du Colombier typedef struct	Sect	Sect;
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier struct Gen
199a747e4fSDavid du Colombier {
209a747e4fSDavid du Colombier 	int	gnum;
219a747e4fSDavid du Colombier 	int	count;
229a747e4fSDavid du Colombier 	int	low;
239a747e4fSDavid du Colombier 	int	high;
249a747e4fSDavid du Colombier 	Sect*	head;
259a747e4fSDavid du Colombier 	Sect*	tail;
269a747e4fSDavid du Colombier 	Sect*	dup;
279a747e4fSDavid du Colombier 	Sect**	vect;
289a747e4fSDavid du Colombier };
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier struct Sect
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier 	int	sect;
339a747e4fSDavid du Colombier 	ulong	seq;
349a747e4fSDavid du Colombier 	int	coff;
359a747e4fSDavid du Colombier 	int	toff;
369a747e4fSDavid du Colombier 	int	sum;
379a747e4fSDavid du Colombier 	ulong	time;
389a747e4fSDavid du Colombier 	Sect*	next;
399a747e4fSDavid du Colombier };
409a747e4fSDavid du Colombier 
419a747e4fSDavid du Colombier static	Gen	gens[2];
429a747e4fSDavid du Colombier static	Sect*	freehead;
439a747e4fSDavid du Colombier static	Sect*	freetail;
449a747e4fSDavid du Colombier static	int	nfree;
459a747e4fSDavid du Colombier static	int	nbad;
469a747e4fSDavid du Colombier static	ulong	ltime;
479a747e4fSDavid du Colombier static	int	cursect;
489a747e4fSDavid du Colombier 
499a747e4fSDavid du Colombier /*
509a747e4fSDavid du Colombier  *	If we have a delta then file times are in the future.
519a747e4fSDavid du Colombier  *	But they drift back to reality.
529a747e4fSDavid du Colombier  */
539a747e4fSDavid du Colombier ulong
now(void)549a747e4fSDavid du Colombier now(void)
559a747e4fSDavid du Colombier {
569a747e4fSDavid du Colombier 	ulong cur, drift;
579a747e4fSDavid du Colombier 	static ulong last;
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier 	cur = time(0);
609a747e4fSDavid du Colombier 	if(cur < last)
619a747e4fSDavid du Colombier 		delta += last - cur;
629a747e4fSDavid du Colombier 	else if(delta != 0 && last != 0) {
639a747e4fSDavid du Colombier 		drift = (cur - last + 1) / 2;
649a747e4fSDavid du Colombier 		if(drift > delta)
659a747e4fSDavid du Colombier 			delta = 0;
669a747e4fSDavid du Colombier 		else
679a747e4fSDavid du Colombier 			delta -= drift;
689a747e4fSDavid du Colombier 	}
699a747e4fSDavid du Colombier 	last = cur;
709a747e4fSDavid du Colombier 	return cur + delta;
719a747e4fSDavid du Colombier }
729a747e4fSDavid du Colombier 
739a747e4fSDavid du Colombier static void
damaged(char * mesg)749a747e4fSDavid du Colombier damaged(char *mesg)
759a747e4fSDavid du Colombier {
76*14cc0f53SDavid du Colombier 	sysfatal("damaged filesystem: %s", mesg);
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier static void
lddisc(char * mesg)809a747e4fSDavid du Colombier lddisc(char *mesg)
819a747e4fSDavid du Colombier {
829a747e4fSDavid du Colombier 	if(debug)
839a747e4fSDavid du Colombier 		fprint(2, "discard %s\n", mesg);
84a21ce2d6SDavid du Colombier 	else
85a21ce2d6SDavid du Colombier 		USED(mesg);
869a747e4fSDavid du Colombier }
879a747e4fSDavid du Colombier 
889a747e4fSDavid du Colombier static Sect *
getsect(void)899a747e4fSDavid du Colombier getsect(void)
909a747e4fSDavid du Colombier {
919a747e4fSDavid du Colombier 	Sect *t;
929a747e4fSDavid du Colombier 
939a747e4fSDavid du Colombier 	t = freehead;
949a747e4fSDavid du Colombier 	freehead = t->next;
959a747e4fSDavid du Colombier 	if(freehead == nil)
969a747e4fSDavid du Colombier 		freetail = nil;
979a747e4fSDavid du Colombier 	nfree--;
989a747e4fSDavid du Colombier 	return t;
999a747e4fSDavid du Colombier }
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier static void
newsect(Gen * g,Sect * s)1029a747e4fSDavid du Colombier newsect(Gen *g, Sect *s)
1039a747e4fSDavid du Colombier {
1049a747e4fSDavid du Colombier 	int m, n, err;
1059a747e4fSDavid du Colombier 	uchar hdr[2*3];
1069a747e4fSDavid du Colombier 
1079a747e4fSDavid du Colombier 	if(debug)
1089a747e4fSDavid du Colombier 		fprint(2, "new %d %ld\n", g->gnum, s->seq);
1099a747e4fSDavid du Colombier 	if(g->tail == nil)
1109a747e4fSDavid du Colombier 		g->head = s;
1119a747e4fSDavid du Colombier 	else
1129a747e4fSDavid du Colombier 		g->tail->next = s;
1139a747e4fSDavid du Colombier 	g->tail = s;
1149a747e4fSDavid du Colombier 	s->next = nil;
1159a747e4fSDavid du Colombier 	m = putc3(&hdr[0], g->gnum);
1169a747e4fSDavid du Colombier 	n = putc3(&hdr[m], s->seq);
1179a747e4fSDavid du Colombier 	s->toff = MAGSIZE + m + n;
1189a747e4fSDavid du Colombier 	s->coff = s->toff + 4;
1199a747e4fSDavid du Colombier 	s->time = NOTIME;
1209a747e4fSDavid du Colombier 	s->sum = 0;
1219a747e4fSDavid du Colombier 	err = 1;
1229a747e4fSDavid du Colombier 	for(;;) {
1239a747e4fSDavid du Colombier 		if(writedata(err, s->sect, hdr, m + n, MAGSIZE)
1249a747e4fSDavid du Colombier 		&& writedata(err, s->sect, magic, MAGSIZE, 0))
1259a747e4fSDavid du Colombier 			break;
1269a747e4fSDavid du Colombier 		clearsect(s->sect);
1279a747e4fSDavid du Colombier 		err = 0;
1289a747e4fSDavid du Colombier 	}
1299a747e4fSDavid du Colombier }
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier static Sect *
newsum(Gen * g,ulong seq)1329a747e4fSDavid du Colombier newsum(Gen *g, ulong seq)
1339a747e4fSDavid du Colombier {
1349a747e4fSDavid du Colombier 	Sect *t;
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 	if(nfree == 0)
1379a747e4fSDavid du Colombier 		damaged("no free sector for summary");
1389a747e4fSDavid du Colombier 	t = getsect();
1399a747e4fSDavid du Colombier 	t->seq = seq;
1409a747e4fSDavid du Colombier 	newsect(g, t);
1419a747e4fSDavid du Colombier 	return t;
1429a747e4fSDavid du Colombier }
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier static void
freesect(Sect * s)1459a747e4fSDavid du Colombier freesect(Sect *s)
1469a747e4fSDavid du Colombier {
1479a747e4fSDavid du Colombier 	clearsect(s->sect);
1489a747e4fSDavid du Colombier 	if(freetail == nil)
1499a747e4fSDavid du Colombier 		freehead = s;
1509a747e4fSDavid du Colombier 	else
1519a747e4fSDavid du Colombier 		freetail->next = s;
1529a747e4fSDavid du Colombier 	freetail = s;
1539a747e4fSDavid du Colombier 	s->next = nil;
1549a747e4fSDavid du Colombier 	nfree++;
1559a747e4fSDavid du Colombier }
1569a747e4fSDavid du Colombier 
1579a747e4fSDavid du Colombier static void
dupsect(Sect * s,int renum)1589a747e4fSDavid du Colombier dupsect(Sect *s, int renum)
1599a747e4fSDavid du Colombier {
1609a747e4fSDavid du Colombier 	Sect *t;
1619a747e4fSDavid du Colombier 	Renum r;
1629a747e4fSDavid du Colombier 	uchar *b;
1639a747e4fSDavid du Colombier 	int err, n;
1649a747e4fSDavid du Colombier 	ulong doff, off;
1659a747e4fSDavid du Colombier 
1669a747e4fSDavid du Colombier 	if(nfree == 0)
1679a747e4fSDavid du Colombier 		damaged("no free for copy");
1689a747e4fSDavid du Colombier 	t = getsect();
1699a747e4fSDavid du Colombier 	b = sectbuff;
1709a747e4fSDavid du Colombier 	off = s->coff;
1719a747e4fSDavid du Colombier 	readdata(s->sect, b, off, 0);
1729a747e4fSDavid du Colombier 	doff = s->toff;
1739a747e4fSDavid du Colombier 	if(s->time == NOTIME)
1749a747e4fSDavid du Colombier 		doff += 4;
1759a747e4fSDavid du Colombier 	// Window 5
1769a747e4fSDavid du Colombier 	err = 1;
1779a747e4fSDavid du Colombier 	for(;;) {
1789a747e4fSDavid du Colombier 		if(writedata(err, t->sect, b + 1, s->toff - 1, 1)
1799a747e4fSDavid du Colombier 		&& writedata(err, t->sect, b + doff, off - doff, doff)
1809a747e4fSDavid du Colombier 		&& writedata(err, t->sect, b, 1, 0))
1819a747e4fSDavid du Colombier 			break;
1829a747e4fSDavid du Colombier 		clearsect(t->sect);
1839a747e4fSDavid du Colombier 		err = 0;
1849a747e4fSDavid du Colombier 	}
1859a747e4fSDavid du Colombier 	if(renum) {
1869a747e4fSDavid du Colombier 		r.old = s->sect;
1879a747e4fSDavid du Colombier 		r.new = t->sect;
1889a747e4fSDavid du Colombier 		erenum(&r);
1899a747e4fSDavid du Colombier 	}
1909a747e4fSDavid du Colombier 	n = s->sect;
1919a747e4fSDavid du Colombier 	s->sect = t->sect;
1929a747e4fSDavid du Colombier 	t->sect = n;
1939a747e4fSDavid du Colombier 	freesect(t);
1949a747e4fSDavid du Colombier 	if(cursect >= 0)
1959a747e4fSDavid du Colombier 		readdata(cursect, b, sectsize, 0);
1969a747e4fSDavid du Colombier }
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier static void
gswap(void)1999a747e4fSDavid du Colombier gswap(void)
2009a747e4fSDavid du Colombier {
2019a747e4fSDavid du Colombier 	Gen t;
2029a747e4fSDavid du Colombier 
2039a747e4fSDavid du Colombier 	t = gens[0];
2049a747e4fSDavid du Colombier 	gens[0] = gens[1];
2059a747e4fSDavid du Colombier 	gens[1] = t;
2069a747e4fSDavid du Colombier }
2079a747e4fSDavid du Colombier 
2089a747e4fSDavid du Colombier static void
checkdata(void)2099a747e4fSDavid du Colombier checkdata(void)
2109a747e4fSDavid du Colombier {
2119a747e4fSDavid du Colombier 	Gen *g;
2129a747e4fSDavid du Colombier 
2139a747e4fSDavid du Colombier 	g = &gens[0];
2149a747e4fSDavid du Colombier 	if(g->dup != nil) {	// Window 5 damage
2159a747e4fSDavid du Colombier 		if(diags)
2169a747e4fSDavid du Colombier 			fprint(2, "%s: window 5 damage\n", argv0);
2179a747e4fSDavid du Colombier 		freesect(g->dup);
2189a747e4fSDavid du Colombier 		g->dup = nil;
2199a747e4fSDavid du Colombier 	}
2209a747e4fSDavid du Colombier }
2219a747e4fSDavid du Colombier 
2229a747e4fSDavid du Colombier static void
checksweep(void)2239a747e4fSDavid du Colombier checksweep(void)
2249a747e4fSDavid du Colombier {
2259a747e4fSDavid du Colombier 	Gen *g;
2269a747e4fSDavid du Colombier 	Jrec j;
2279a747e4fSDavid du Colombier 	uchar *b;
2289a747e4fSDavid du Colombier 	int n, op;
2299a747e4fSDavid du Colombier 	Sect *s, *t, *u;
2309a747e4fSDavid du Colombier 	long off, seq, soff;
2319a747e4fSDavid du Colombier 
2329a747e4fSDavid du Colombier 	g = &gens[1];
2339a747e4fSDavid du Colombier 	if(g->dup != nil) {	// Window 5 damage
2349a747e4fSDavid du Colombier 		if(diags)
2359a747e4fSDavid du Colombier 			fprint(2, "%s: window 5 damage\n", argv0);
2369a747e4fSDavid du Colombier 		freesect(g->dup);
2379a747e4fSDavid du Colombier 		g->dup = nil;
2389a747e4fSDavid du Colombier 	}
2399a747e4fSDavid du Colombier 
2409a747e4fSDavid du Colombier 	s = g->head;
2419a747e4fSDavid du Colombier 	if(s != g->tail) {
2429a747e4fSDavid du Colombier 		while(s->next != g->tail)
2439a747e4fSDavid du Colombier 			s = s->next;
2449a747e4fSDavid du Colombier 	}
2459a747e4fSDavid du Colombier 
2469a747e4fSDavid du Colombier 	b = sectbuff;
2479a747e4fSDavid du Colombier 	op = -1;
2489a747e4fSDavid du Colombier 	seq = -1;
2499a747e4fSDavid du Colombier 	soff = 0;
2509a747e4fSDavid du Colombier 	u = nil;
2519a747e4fSDavid du Colombier 	t = s;
2529a747e4fSDavid du Colombier 	for(;;) {
2539a747e4fSDavid du Colombier 		readdata(t->sect, b, sectsize, 0);
2549a747e4fSDavid du Colombier 		off = t->toff + 4;
2559a747e4fSDavid du Colombier 		for(;;) {
2569a747e4fSDavid du Colombier 			n = convM2J(&j, &b[off]);
2579a747e4fSDavid du Colombier 			if(n < 0) {
2589a747e4fSDavid du Colombier 				if(j.type != 0xFF) {
2599a747e4fSDavid du Colombier 					if(debug)
2609a747e4fSDavid du Colombier 						fprint(2, "s[%d] @ %d %ld\n", j.type, t->sect, off);
2619a747e4fSDavid du Colombier 					damaged("bad Jrec");
2629a747e4fSDavid du Colombier 				}
2639a747e4fSDavid du Colombier 				break;
2649a747e4fSDavid du Colombier 			}
2659a747e4fSDavid du Colombier 			switch(j.type) {
2669a747e4fSDavid du Colombier 			case FT_SUMMARY:
2679a747e4fSDavid du Colombier 			case FT_SUMBEG:
2689a747e4fSDavid du Colombier 				seq = j.seq;
2699a747e4fSDavid du Colombier 			case FT_SUMEND:
2709a747e4fSDavid du Colombier 				op = j.type;
2719a747e4fSDavid du Colombier 				soff = off;
2729a747e4fSDavid du Colombier 				u = t;
2739a747e4fSDavid du Colombier 				break;
2749a747e4fSDavid du Colombier 			case FT_WRITE:
2759a747e4fSDavid du Colombier 			case FT_AWRITE:
2769a747e4fSDavid du Colombier 				off += j.size;
2779a747e4fSDavid du Colombier 			}
2789a747e4fSDavid du Colombier 			off += n;
2799a747e4fSDavid du Colombier 		}
2809a747e4fSDavid du Colombier 		t = t->next;
2819a747e4fSDavid du Colombier 		if(t == nil)
2829a747e4fSDavid du Colombier 			break;
2839a747e4fSDavid du Colombier 	}
2849a747e4fSDavid du Colombier 
2859a747e4fSDavid du Colombier 	if(op == FT_SUMBEG) {		// Window 1 damage
2869a747e4fSDavid du Colombier 		if(diags)
2879a747e4fSDavid du Colombier 			fprint(2, "%s: window 1 damage\n", argv0);
2889a747e4fSDavid du Colombier 		if(u != s) {
2899a747e4fSDavid du Colombier 			freesect(u);
2909a747e4fSDavid du Colombier 			s->next = nil;
2919a747e4fSDavid du Colombier 			g->tail = s;
2929a747e4fSDavid du Colombier 		}
2939a747e4fSDavid du Colombier 		s->coff = soff;
2949a747e4fSDavid du Colombier 		dupsect(s, 0);
2959a747e4fSDavid du Colombier 		seq--;
2969a747e4fSDavid du Colombier 	}
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier 	if(seq >= 0) {
2999a747e4fSDavid du Colombier 		g = &gens[0];
3009a747e4fSDavid du Colombier 		if(seq > g->low)
3019a747e4fSDavid du Colombier 			damaged("high sweep");
3029a747e4fSDavid du Colombier 		if(seq == g->low) {	// Window 2 damage
3039a747e4fSDavid du Colombier 			if(diags)
3049a747e4fSDavid du Colombier 				fprint(2, "%s: window 2 damage\n", argv0);
3059a747e4fSDavid du Colombier 			s = g->head;
3069a747e4fSDavid du Colombier 			g->head = s->next;
3079a747e4fSDavid du Colombier 			freesect(s);
3089a747e4fSDavid du Colombier 			if(g->head == nil) {
3099a747e4fSDavid du Colombier 				g->tail = nil;
3109a747e4fSDavid du Colombier 				g->gnum += 2;
3119a747e4fSDavid du Colombier 				newsum(g, 0);
3129a747e4fSDavid du Colombier 				gswap();
3139a747e4fSDavid du Colombier 			}
3149a747e4fSDavid du Colombier 		}
3159a747e4fSDavid du Colombier 	}
3169a747e4fSDavid du Colombier }
3179a747e4fSDavid du Colombier 
3189a747e4fSDavid du Colombier void
load1(Sect * s,int parity)3199a747e4fSDavid du Colombier load1(Sect *s, int parity)
3209a747e4fSDavid du Colombier {
3219a747e4fSDavid du Colombier 	int n;
3229a747e4fSDavid du Colombier 	Jrec j;
3239a747e4fSDavid du Colombier 	uchar *b;
3249a747e4fSDavid du Colombier 	char *err;
3259a747e4fSDavid du Colombier 	Extent *x;
3269a747e4fSDavid du Colombier 	Entry *d, *e;
3279a747e4fSDavid du Colombier 	ulong ctime, off, mtime;
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	if(s->sect < 0 && readonly)	// readonly damaged
3309a747e4fSDavid du Colombier 		return;
3319a747e4fSDavid du Colombier 
3329a747e4fSDavid du Colombier 	b = sectbuff;
3339a747e4fSDavid du Colombier 	readdata(s->sect, b, sectsize, 0);
3349a747e4fSDavid du Colombier 	s->sum = 0;
3359a747e4fSDavid du Colombier 	off = s->toff;
3369a747e4fSDavid du Colombier 	ctime = get4(&b[off]);
3379a747e4fSDavid du Colombier 	off += 4;
3389a747e4fSDavid du Colombier 
3399a747e4fSDavid du Colombier 	for(;;) {
3409a747e4fSDavid du Colombier 		n = convM2J(&j, &b[off]);
3419a747e4fSDavid du Colombier 		if(n < 0) {
3429a747e4fSDavid du Colombier 			if(j.type != 0xFF) {
3439a747e4fSDavid du Colombier 				if(debug)
3449a747e4fSDavid du Colombier 					fprint(2, "l[%d] @  %d %ld\n", j.type, s->sect, off);
3459a747e4fSDavid du Colombier 				damaged("bad Jrec");
3469a747e4fSDavid du Colombier 			}
3479a747e4fSDavid du Colombier 			s->coff = off;
3489a747e4fSDavid du Colombier 			break;
3499a747e4fSDavid du Colombier 		}
3509a747e4fSDavid du Colombier 		off += n;
3519a747e4fSDavid du Colombier 		if(debug)
3529a747e4fSDavid du Colombier 			fprint(2, "get %J\n", &j);
3539a747e4fSDavid du Colombier 		switch(j.type) {
3549a747e4fSDavid du Colombier 		case FT_create:
3559a747e4fSDavid du Colombier 			ctime += j.mtime;
3569a747e4fSDavid du Colombier 		create:
3579a747e4fSDavid du Colombier 			d = elookup(j.parent);
3589a747e4fSDavid du Colombier 			if(d == nil) {
3599a747e4fSDavid du Colombier 				lddisc("parent");
3609a747e4fSDavid du Colombier 				break;
3619a747e4fSDavid du Colombier 			}
3629a747e4fSDavid du Colombier 			d->ref++;
3639a747e4fSDavid du Colombier 			e = ecreate(d, j.name, j.fnum, j.mode, ctime, &err);
3649a747e4fSDavid du Colombier 			if(e == nil) {
3659a747e4fSDavid du Colombier 				d->ref--;
3669a747e4fSDavid du Colombier 				lddisc("create");
3679a747e4fSDavid du Colombier 				break;
3689a747e4fSDavid du Colombier 			}
3699a747e4fSDavid du Colombier 			e->ref--;
3709a747e4fSDavid du Colombier 			if(j.type == FT_trunc)
3719a747e4fSDavid du Colombier 				e->mode = j.mode;
3729a747e4fSDavid du Colombier 			break;
3739a747e4fSDavid du Colombier 		case FT_chmod:
3749a747e4fSDavid du Colombier 			e = elookup(j.fnum);
3759a747e4fSDavid du Colombier 			if(e == nil) {
3769a747e4fSDavid du Colombier 				lddisc("lookup");
3779a747e4fSDavid du Colombier 				break;
3789a747e4fSDavid du Colombier 			}
3799a747e4fSDavid du Colombier 			echmod(e, j.mode, j.mnum);
3809a747e4fSDavid du Colombier 			break;
3819a747e4fSDavid du Colombier 		case FT_REMOVE:
3829a747e4fSDavid du Colombier 			e = elookup(j.fnum);
3839a747e4fSDavid du Colombier 			if(e == nil) {
3849a747e4fSDavid du Colombier 				lddisc("lookup");
3859a747e4fSDavid du Colombier 				break;
3869a747e4fSDavid du Colombier 			}
3879a747e4fSDavid du Colombier 			if(eremove(e) != nil) {
3889a747e4fSDavid du Colombier 				lddisc("remove");
3899a747e4fSDavid du Colombier 				break;
3909a747e4fSDavid du Colombier 			}
3919a747e4fSDavid du Colombier 			break;
3929a747e4fSDavid du Colombier 		case FT_AWRITE:
3939a747e4fSDavid du Colombier 			mtime = 0;
3949a747e4fSDavid du Colombier 			goto write;
3959a747e4fSDavid du Colombier 		case FT_WRITE:
3969a747e4fSDavid du Colombier 			ctime += j.mtime;
3979a747e4fSDavid du Colombier 			mtime = ctime;
3989a747e4fSDavid du Colombier 		write:
3999a747e4fSDavid du Colombier 			x = emalloc9p(sizeof(Extent));
4009a747e4fSDavid du Colombier 			x->sect = s->sect;
4019a747e4fSDavid du Colombier 			x->addr = off;
4029a747e4fSDavid du Colombier 			x->off = j.offset;
4039a747e4fSDavid du Colombier 			x->size = j.size;
4049a747e4fSDavid du Colombier 			off += j.size;
4059a747e4fSDavid du Colombier 			e = elookup(j.fnum);
4069a747e4fSDavid du Colombier 			if(e == nil) {
4079a747e4fSDavid du Colombier 				lddisc("lookup");
4089a747e4fSDavid du Colombier 				break;
4099a747e4fSDavid du Colombier 			}
4109a747e4fSDavid du Colombier 			ewrite(e, x, parity, mtime);
4119a747e4fSDavid du Colombier 			break;
4129a747e4fSDavid du Colombier 		case FT_trunc:
4139a747e4fSDavid du Colombier 			ctime += j.mtime;
4149a747e4fSDavid du Colombier 			e = elookup(j.tnum);
4159a747e4fSDavid du Colombier 			if(e == nil) {
4169a747e4fSDavid du Colombier 				if(debug)
4179a747e4fSDavid du Colombier 					fprint(2, "-> create\n");
4189a747e4fSDavid du Colombier 				goto create;
4199a747e4fSDavid du Colombier 			}
4209a747e4fSDavid du Colombier 			etrunc(e, j.fnum, ctime);
4219a747e4fSDavid du Colombier 			break;
4229a747e4fSDavid du Colombier 		case FT_SUMMARY:
4239a747e4fSDavid du Colombier 		case FT_SUMBEG:
4249a747e4fSDavid du Colombier 		case FT_SUMEND:
4259a747e4fSDavid du Colombier 			s->sum += n;
4269a747e4fSDavid du Colombier 			break;
4279a747e4fSDavid du Colombier 		default:
4289a747e4fSDavid du Colombier 			damaged("load1 botch");
4299a747e4fSDavid du Colombier 		}
4309a747e4fSDavid du Colombier 	}
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier 	if(s->sum > Nsum)
4339a747e4fSDavid du Colombier 		s->sum = Nsum;
4349a747e4fSDavid du Colombier 
4359a747e4fSDavid du Colombier 	s->time = ctime;
4369a747e4fSDavid du Colombier 	if(ctime != NOTIME && ctime > ltime)
4379a747e4fSDavid du Colombier 		ltime = ctime;
4389a747e4fSDavid du Colombier }
4399a747e4fSDavid du Colombier 
4409a747e4fSDavid du Colombier void
load0(int parity)4419a747e4fSDavid du Colombier load0(int parity)
4429a747e4fSDavid du Colombier {
4439a747e4fSDavid du Colombier 	Sect *s;
4449a747e4fSDavid du Colombier 
4459a747e4fSDavid du Colombier 	if(debug)
4469a747e4fSDavid du Colombier 		fprint(2, "load %d\n", parity);
4479a747e4fSDavid du Colombier 	for(s = gens[parity].head; s != nil; s = s->next)
4489a747e4fSDavid du Colombier 		load1(s, parity);
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier void
loadfs(int ro)4529a747e4fSDavid du Colombier loadfs(int ro)
4539a747e4fSDavid du Colombier {
4549a747e4fSDavid du Colombier 	Gen *g;
4559a747e4fSDavid du Colombier 	Sect *s;
4569a747e4fSDavid du Colombier 	ulong u, v;
4579a747e4fSDavid du Colombier 	int i, j, n;
4589a747e4fSDavid du Colombier 	uchar hdr[MAXHDR];
4599a747e4fSDavid du Colombier 
4609a747e4fSDavid du Colombier 	readonly = ro;
4619a747e4fSDavid du Colombier 	fmtinstall('J', Jconv);
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier 	for(i = 0; i < 2; i++) {
4649a747e4fSDavid du Colombier 		g = &gens[i];
4659a747e4fSDavid du Colombier 		g->gnum = -1;
4669a747e4fSDavid du Colombier 		g->low = nsects;
4679a747e4fSDavid du Colombier 		g->high = -1;
4689a747e4fSDavid du Colombier 		g->count = 0;
4699a747e4fSDavid du Colombier 		g->head = nil;
4709a747e4fSDavid du Colombier 		g->tail = nil;
4719a747e4fSDavid du Colombier 	}
4729a747e4fSDavid du Colombier 
4739a747e4fSDavid du Colombier 	for(i = 0; i < nsects; i++) {
4749a747e4fSDavid du Colombier 		readdata(i, hdr, MAXHDR, 0);
4759a747e4fSDavid du Colombier 		if(memcmp(hdr, magic, MAGSIZE) == 0) {
4769a747e4fSDavid du Colombier 			n = MAGSIZE + getc3(&hdr[MAGSIZE], &u);
4779a747e4fSDavid du Colombier 			getc3(&hdr[n], &v);
4789a747e4fSDavid du Colombier 			if(debug)
4799a747e4fSDavid du Colombier 				fprint(2, "%d: %ld %ld\n", i, u, v);
4809a747e4fSDavid du Colombier 			for(j = 0; j < 2; j++) {
4819a747e4fSDavid du Colombier 				g = &gens[j];
4829a747e4fSDavid du Colombier 				if(g->gnum == u) {
4839a747e4fSDavid du Colombier 					g->count++;
4849a747e4fSDavid du Colombier 					if(v < g->low)
4859a747e4fSDavid du Colombier 						g->low = v;
4869a747e4fSDavid du Colombier 					if(v > g->high)
4879a747e4fSDavid du Colombier 						g->high = v;
4889a747e4fSDavid du Colombier 					break;
4899a747e4fSDavid du Colombier 				}
4909a747e4fSDavid du Colombier 				else if(g->gnum < 0) {
4919a747e4fSDavid du Colombier 					g->gnum = u;
4929a747e4fSDavid du Colombier 					g->count = 1;
4939a747e4fSDavid du Colombier 					g->low = v;
4949a747e4fSDavid du Colombier 					g->high = v;
4959a747e4fSDavid du Colombier 					break;
4969a747e4fSDavid du Colombier 				}
4979a747e4fSDavid du Colombier 			}
4989a747e4fSDavid du Colombier 			if(j == 2)
4999a747e4fSDavid du Colombier 				damaged("unexpected generation");
5009a747e4fSDavid du Colombier 		}
5019a747e4fSDavid du Colombier 		else if(hdr[0] == 0xFF) {
5029a747e4fSDavid du Colombier 			nfree++;
5039a747e4fSDavid du Colombier 			s = emalloc9p(sizeof(Sect));
5049a747e4fSDavid du Colombier 			s->sect = i;
5059a747e4fSDavid du Colombier 			s->next = freehead;
5069a747e4fSDavid du Colombier 			freehead = s;
5079a747e4fSDavid du Colombier 			if(freetail == nil)
5089a747e4fSDavid du Colombier 				freetail = s;
5099a747e4fSDavid du Colombier 		}
5109a747e4fSDavid du Colombier 		else
5119a747e4fSDavid du Colombier 			nbad++;
5129a747e4fSDavid du Colombier 	}
5139a747e4fSDavid du Colombier 
5149a747e4fSDavid du Colombier 	if(nbad > 0)
5159a747e4fSDavid du Colombier 		damaged("bad sectors");
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier 	if(gens[0].gnum < 0)
5189a747e4fSDavid du Colombier 		damaged("no data");
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier 	if(gens[1].gnum < 0) {		// Window 3 death
5219a747e4fSDavid du Colombier 		if(diags)
5229a747e4fSDavid du Colombier 			fprint(2, "%s: window 3 damage\n", argv0);
5239a747e4fSDavid du Colombier 		g = &gens[1];
5249a747e4fSDavid du Colombier 		g->gnum = gens[0].gnum + 1;
5259a747e4fSDavid du Colombier 		g->low = 0;
5269a747e4fSDavid du Colombier 		g->high = 0;
5279a747e4fSDavid du Colombier 		g->count = 1;
5289a747e4fSDavid du Colombier 		if(!readonly)
5299a747e4fSDavid du Colombier 			newsum(g, 0);
5309a747e4fSDavid du Colombier 	}
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier 	if(gens[0].gnum > gens[1].gnum)
5339a747e4fSDavid du Colombier 		gswap();
5349a747e4fSDavid du Colombier 
5359a747e4fSDavid du Colombier 	for(i = 0; i < 2; i++) {
5369a747e4fSDavid du Colombier 		g = &gens[i];
5379a747e4fSDavid du Colombier 		n = g->count;
5389a747e4fSDavid du Colombier 		if(n <= g->high - g->low)
5399a747e4fSDavid du Colombier 			damaged("missing sectors");
5409a747e4fSDavid du Colombier 		g->vect = emalloc9p(n * sizeof(Sect *));
5419a747e4fSDavid du Colombier 		for(j = 0; j < n; j++) {
5429a747e4fSDavid du Colombier 			s = emalloc9p(sizeof(Sect));
5439a747e4fSDavid du Colombier 			s->sect = -1;
5449a747e4fSDavid du Colombier 			g->vect[j] = s;
5459a747e4fSDavid du Colombier 		}
5469a747e4fSDavid du Colombier 	}
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	if(debug) {
5499a747e4fSDavid du Colombier 		for(j = 0; j < 2; j++) {
5509a747e4fSDavid du Colombier 			g = &gens[j];
5519a747e4fSDavid du Colombier 			print("%d\t%d\t%d-%d\n", g->gnum, g->count, g->low, g->high);
5529a747e4fSDavid du Colombier 		}
5539a747e4fSDavid du Colombier 	}
5549a747e4fSDavid du Colombier 
5559a747e4fSDavid du Colombier 	for(i = 0; i < nsects; i++) {
5569a747e4fSDavid du Colombier 		readdata(i, hdr, MAXHDR, 0);
5579a747e4fSDavid du Colombier 		if(memcmp(hdr, magic, MAGSIZE) == 0) {
5589a747e4fSDavid du Colombier 			n = MAGSIZE + getc3(&hdr[MAGSIZE], &u);
5599a747e4fSDavid du Colombier 			n += getc3(&hdr[n], &v);
5609a747e4fSDavid du Colombier 			g = nil;
5619a747e4fSDavid du Colombier 			for(j = 0; j < 2; j++) {
5629a747e4fSDavid du Colombier 				g = &gens[j];
5639a747e4fSDavid du Colombier 				if(g->gnum == u)
5649a747e4fSDavid du Colombier 					break;
5659a747e4fSDavid du Colombier 			}
5669a747e4fSDavid du Colombier 			if(j == 2)
5679a747e4fSDavid du Colombier 				damaged("generation botch");
5689a747e4fSDavid du Colombier 			s = g->vect[v - g->low];
5699a747e4fSDavid du Colombier 			s->seq = v;
5709a747e4fSDavid du Colombier 			s->toff = n;
5719a747e4fSDavid du Colombier 			if(s->sect < 0)
5729a747e4fSDavid du Colombier 				s->sect = i;
5739a747e4fSDavid du Colombier 			else if(v == g->high && g->dup == nil) {
5749a747e4fSDavid du Colombier 				s = emalloc9p(sizeof(Sect));
5759a747e4fSDavid du Colombier 				s->sect = i;
5769a747e4fSDavid du Colombier 				g->dup = s;
5779a747e4fSDavid du Colombier 			}
5789a747e4fSDavid du Colombier 			else
5799a747e4fSDavid du Colombier 				damaged("dup block");
5809a747e4fSDavid du Colombier 		}
5819a747e4fSDavid du Colombier 	}
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier 	for(j = 0; j < 2; j++) {
5849a747e4fSDavid du Colombier 		g = &gens[j];
5859a747e4fSDavid du Colombier 		for(i = 0; i < g->count; i++) {
5869a747e4fSDavid du Colombier 			s = g->vect[i];
5879a747e4fSDavid du Colombier 			if(g->tail == nil)
5889a747e4fSDavid du Colombier 				g->head = s;
5899a747e4fSDavid du Colombier 			else
5909a747e4fSDavid du Colombier 				g->tail->next = s;
5919a747e4fSDavid du Colombier 			g->tail = s;
5929a747e4fSDavid du Colombier 			s->next = nil;
5939a747e4fSDavid du Colombier 		}
5949a747e4fSDavid du Colombier 		free(g->vect);
5959a747e4fSDavid du Colombier 	}
5969a747e4fSDavid du Colombier 
5979a747e4fSDavid du Colombier 	cursect = -1;
5989a747e4fSDavid du Colombier 
5999a747e4fSDavid du Colombier 	if(!readonly) {
6009a747e4fSDavid du Colombier 		checkdata();
6019a747e4fSDavid du Colombier 		checksweep();
6029a747e4fSDavid du Colombier 	}
6039a747e4fSDavid du Colombier 
6049a747e4fSDavid du Colombier 	load0(1);
6059a747e4fSDavid du Colombier 	load0(0);
6069a747e4fSDavid du Colombier 
6079a747e4fSDavid du Colombier 	if(ltime != 0) {
6089a747e4fSDavid du Colombier 		u = now();
6099a747e4fSDavid du Colombier 		if(u < ltime) {
6109a747e4fSDavid du Colombier 			delta = ltime - u;
6119a747e4fSDavid du Colombier 			if(diags)
6129a747e4fSDavid du Colombier 				fprint(2, "%s: check clock: delta = %lud\n", argv0, delta);
6139a747e4fSDavid du Colombier 		}
6149a747e4fSDavid du Colombier 	}
6159a747e4fSDavid du Colombier 
6169a747e4fSDavid du Colombier 	limit = 80 * nsects * sectsize / 100;
6179a747e4fSDavid du Colombier 	maxwrite = sectsize - MAXHDR - Nwrite - Nsum;
6189a747e4fSDavid du Colombier 	if(maxwrite > WRSIZE)
6199a747e4fSDavid du Colombier 		maxwrite = WRSIZE;
6209a747e4fSDavid du Colombier }
6219a747e4fSDavid du Colombier 
6229a747e4fSDavid du Colombier static int
sputw(Sect * s,Jrec * j,int mtime,Extent * x,void * a)6239a747e4fSDavid du Colombier sputw(Sect *s, Jrec *j, int mtime, Extent *x, void *a)
6249a747e4fSDavid du Colombier {
6259a747e4fSDavid du Colombier 	ulong t;
6269a747e4fSDavid du Colombier 	int err, n, r;
6279a747e4fSDavid du Colombier 	uchar buff[Nmax], type[1];
6289a747e4fSDavid du Colombier 
6299a747e4fSDavid du Colombier 	if(debug)
6309a747e4fSDavid du Colombier 		fprint(2, "put %J\n", j);
6319a747e4fSDavid du Colombier 
6329a747e4fSDavid du Colombier 	if(mtime) {
6339a747e4fSDavid du Colombier 		t = j->mtime;
6349a747e4fSDavid du Colombier 		if(s->time == NOTIME) {
6359a747e4fSDavid du Colombier 			put4(buff, t);
6369a747e4fSDavid du Colombier 			if(!writedata(1, s->sect, buff, 4, s->toff)) {
6379a747e4fSDavid du Colombier 				dupsect(s, 1);
6389a747e4fSDavid du Colombier 				writedata(0, s->sect, buff, 4, s->toff);
6399a747e4fSDavid du Colombier 			}
6409a747e4fSDavid du Colombier 			s->time = t;
6419a747e4fSDavid du Colombier 			j->mtime = 0;
6429a747e4fSDavid du Colombier 		}
6439a747e4fSDavid du Colombier 		else {
6449a747e4fSDavid du Colombier 			j->mtime = t - s->time;
6459a747e4fSDavid du Colombier 			s->time = t;
6469a747e4fSDavid du Colombier 		}
6479a747e4fSDavid du Colombier 	}
6489a747e4fSDavid du Colombier 
6499a747e4fSDavid du Colombier 	n = convJ2M(j, buff);
6509a747e4fSDavid du Colombier 	if(n < 0)
6519a747e4fSDavid du Colombier 		damaged("convJ2M");
6529a747e4fSDavid du Colombier 
6539a747e4fSDavid du Colombier 	// Window 4
6549a747e4fSDavid du Colombier 	err = 2;
6559a747e4fSDavid du Colombier 	for(;;) {
6569a747e4fSDavid du Colombier 		err--;
6579a747e4fSDavid du Colombier 		if(!err)
6589a747e4fSDavid du Colombier 			dupsect(s, 1);	// Window 4 damage
6599a747e4fSDavid du Colombier 		t = s->coff + 1;
6609a747e4fSDavid du Colombier 		if(!writedata(err, s->sect, buff, n, t))
6619a747e4fSDavid du Colombier 			continue;
6629a747e4fSDavid du Colombier 
6639a747e4fSDavid du Colombier 		t += n;
6649a747e4fSDavid du Colombier 		r = n;
6659a747e4fSDavid du Colombier 		if(x != nil) {
6669a747e4fSDavid du Colombier 			x->sect = s->sect;
6679a747e4fSDavid du Colombier 			x->addr = t;
6689a747e4fSDavid du Colombier 			if(!writedata(err, s->sect, a, j->size, t))
6699a747e4fSDavid du Colombier 				continue;
6709a747e4fSDavid du Colombier 			t += j->size;
6719a747e4fSDavid du Colombier 			r += j->size;
6729a747e4fSDavid du Colombier 		}
6739a747e4fSDavid du Colombier 
6749a747e4fSDavid du Colombier 		type[0] = j->type;
6759a747e4fSDavid du Colombier 		if(!writedata(err, s->sect, type, 1, s->coff))
6769a747e4fSDavid du Colombier 			continue;
6779a747e4fSDavid du Colombier 		r++;
6789a747e4fSDavid du Colombier 		break;
6799a747e4fSDavid du Colombier 	}
6809a747e4fSDavid du Colombier 	s->coff = t;
6819a747e4fSDavid du Colombier 	return r;
6829a747e4fSDavid du Colombier }
6839a747e4fSDavid du Colombier 
6849a747e4fSDavid du Colombier static void
summarize(void)6859a747e4fSDavid du Colombier summarize(void)
6869a747e4fSDavid du Colombier {
6879a747e4fSDavid du Colombier 	Gen *g;
6889a747e4fSDavid du Colombier 	uchar *b;
6899a747e4fSDavid du Colombier 	Entry *e;
6909a747e4fSDavid du Colombier 	Extent *x;
6919a747e4fSDavid du Colombier 	Jrec j, sum;
6929a747e4fSDavid du Colombier 	Sect *s, *t;
6939a747e4fSDavid du Colombier 	ulong off, ctime;
6949a747e4fSDavid du Colombier 	int n, bytes, more, mtime, sumd;
6959a747e4fSDavid du Colombier 
6969a747e4fSDavid du Colombier 	g = &gens[eparity];
6979a747e4fSDavid du Colombier 	s = g->head;
6989a747e4fSDavid du Colombier 	g->head = s->next;
6999a747e4fSDavid du Colombier 	if(g->head == nil)
7009a747e4fSDavid du Colombier 		g->tail = nil;
7019a747e4fSDavid du Colombier 	g = &gens[eparity^1];
7029a747e4fSDavid du Colombier 	t = g->tail;
7039a747e4fSDavid du Colombier 	b = sectbuff;
7049a747e4fSDavid du Colombier 	x = nil;
7059a747e4fSDavid du Colombier 
7069a747e4fSDavid du Colombier 	if(debug)
7079a747e4fSDavid du Colombier 		fprint(2, "summarize\n");
7089a747e4fSDavid du Colombier 
7099a747e4fSDavid du Colombier 	for(;;) {	// Window 1
7109a747e4fSDavid du Colombier 		readdata(s->sect, b, sectsize, 0);
7119a747e4fSDavid du Colombier 		off = s->toff;
7129a747e4fSDavid du Colombier 		ctime = get4(&b[off]);
7139a747e4fSDavid du Colombier 		off += 4;
7149a747e4fSDavid du Colombier 		sumd = 0;
7159a747e4fSDavid du Colombier 
7169a747e4fSDavid du Colombier 		cursect = s->sect;
7179a747e4fSDavid du Colombier 		while(b[off] != 0xFF) {
7189a747e4fSDavid du Colombier 			n = convM2J(&j, &b[off]);
7199a747e4fSDavid du Colombier 			if(n < 0)
7209a747e4fSDavid du Colombier 				damaged("bad Jrec");
7219a747e4fSDavid du Colombier 			if(debug)
7229a747e4fSDavid du Colombier 				fprint(2, "read %J\n", &j);
7239a747e4fSDavid du Colombier 			off += n;
7249a747e4fSDavid du Colombier 			bytes = n;
7259a747e4fSDavid du Colombier 			mtime = 0;
7269a747e4fSDavid du Colombier 			switch(j.type) {
7279a747e4fSDavid du Colombier 			case FT_create:
7289a747e4fSDavid du Colombier 				ctime += j.mtime;
7299a747e4fSDavid du Colombier 				mtime = 1;
7309a747e4fSDavid du Colombier 			create:
7319a747e4fSDavid du Colombier 				e = elookup(j.fnum);
7329a747e4fSDavid du Colombier 				if(e == nil)
7339a747e4fSDavid du Colombier 					continue;
7349a747e4fSDavid du Colombier 				break;
7359a747e4fSDavid du Colombier 			case FT_chmod:
7369a747e4fSDavid du Colombier 				e = elookup(j.fnum);
7379a747e4fSDavid du Colombier 				if(e == nil || j.mnum != e->mnum)
7389a747e4fSDavid du Colombier 					continue;
7399a747e4fSDavid du Colombier 				break;
7409a747e4fSDavid du Colombier 			case FT_REMOVE:
7419a747e4fSDavid du Colombier 				e = elookup(j.fnum);
7429a747e4fSDavid du Colombier 				if(e == nil)
7439a747e4fSDavid du Colombier 					continue;
7449a747e4fSDavid du Colombier 				break;
7459a747e4fSDavid du Colombier 			case FT_trunc:
7469a747e4fSDavid du Colombier 				ctime += j.mtime;
7479a747e4fSDavid du Colombier 				mtime = 1;
7489a747e4fSDavid du Colombier 				e = elookup(j.tnum);
7499a747e4fSDavid du Colombier 				if(e == nil) {
7509a747e4fSDavid du Colombier 					if(debug)
7519a747e4fSDavid du Colombier 						fprint(2, "-> create\n");
7529a747e4fSDavid du Colombier 					j.type = FT_create;
7539a747e4fSDavid du Colombier 					goto create;
7549a747e4fSDavid du Colombier 				}
7559a747e4fSDavid du Colombier 				break;
7569a747e4fSDavid du Colombier 			case FT_AWRITE:
7579a747e4fSDavid du Colombier 				goto write;
7589a747e4fSDavid du Colombier 			case FT_WRITE:
7599a747e4fSDavid du Colombier 				ctime += j.mtime;
7609a747e4fSDavid du Colombier 				mtime = 1;
7619a747e4fSDavid du Colombier 			write:
7629a747e4fSDavid du Colombier 				e = elookup(j.fnum);
7639a747e4fSDavid du Colombier 				if(e == nil) {
7649a747e4fSDavid du Colombier 					off += j.size;
7659a747e4fSDavid du Colombier 					continue;
7669a747e4fSDavid du Colombier 				}
7679a747e4fSDavid du Colombier 				x = esum(e, s->sect, off, &more);
7689a747e4fSDavid du Colombier 				if(x == nil) {
7699a747e4fSDavid du Colombier 					damaged("missing extent");
7709a747e4fSDavid du Colombier 					off += j.size;
7719a747e4fSDavid du Colombier 					continue;
7729a747e4fSDavid du Colombier 				}
7739a747e4fSDavid du Colombier 				if(more) {
7749a747e4fSDavid du Colombier 					j.type = FT_AWRITE;
7759a747e4fSDavid du Colombier 					mtime = 0;
7769a747e4fSDavid du Colombier 				}
7779a747e4fSDavid du Colombier 				bytes += j.size;
7789a747e4fSDavid du Colombier 				break;
7799a747e4fSDavid du Colombier 			case FT_SUMMARY:
7809a747e4fSDavid du Colombier 			case FT_SUMBEG:
7819a747e4fSDavid du Colombier 			case FT_SUMEND:
7829a747e4fSDavid du Colombier 				continue;
7839a747e4fSDavid du Colombier 			default:
7849a747e4fSDavid du Colombier 				damaged("summarize botch");
7859a747e4fSDavid du Colombier 			}
7869a747e4fSDavid du Colombier 
7879a747e4fSDavid du Colombier 			if(!sumd) {
7889a747e4fSDavid du Colombier 				if(t->coff + Nsumbeg >= sectsize - 1)
7899a747e4fSDavid du Colombier 					t = newsum(g, t->seq + 1);
7909a747e4fSDavid du Colombier 				sum.type = FT_SUMBEG;
7919a747e4fSDavid du Colombier 				sum.seq = s->seq;
7929a747e4fSDavid du Colombier 				if(debug)
7939a747e4fSDavid du Colombier 					fprint(2, "+ %J\n", &sum);
7949a747e4fSDavid du Colombier 				t->sum += sputw(t, &sum, 0, nil, nil);
7959a747e4fSDavid du Colombier 				if(t->sum >= Nsum)
7969a747e4fSDavid du Colombier 					t->sum = Nsum;
7979a747e4fSDavid du Colombier 				sumd = 1;
7989a747e4fSDavid du Colombier 			}
7999a747e4fSDavid du Colombier 
8009a747e4fSDavid du Colombier 			if(t->coff + bytes >= sectsize - Nsum + t->sum - 1)
8019a747e4fSDavid du Colombier 				t = newsum(g, t->seq + 1);
8029a747e4fSDavid du Colombier 
8039a747e4fSDavid du Colombier 			if(mtime)
8049a747e4fSDavid du Colombier 				j.mtime = ctime;
8059a747e4fSDavid du Colombier 
8069a747e4fSDavid du Colombier 			switch(j.type) {
8079a747e4fSDavid du Colombier 			case FT_AWRITE:
8089a747e4fSDavid du Colombier 			case FT_WRITE:
8099a747e4fSDavid du Colombier 				sputw(t, &j, mtime, x, &b[off]);
8109a747e4fSDavid du Colombier 				off += j.size;
8119a747e4fSDavid du Colombier 				break;
8129a747e4fSDavid du Colombier 			default:
8139a747e4fSDavid du Colombier 				sputw(t, &j, mtime, nil, nil);
8149a747e4fSDavid du Colombier 			}
8159a747e4fSDavid du Colombier 		}
8169a747e4fSDavid du Colombier 		cursect = -1;
8179a747e4fSDavid du Colombier 
8189a747e4fSDavid du Colombier 		if(t->coff + Nsumbeg >= sectsize - 1)
8199a747e4fSDavid du Colombier 			t = newsum(g, t->seq + 1);
8209a747e4fSDavid du Colombier 		if(sumd)
8219a747e4fSDavid du Colombier 			sum.type = FT_SUMEND;
8229a747e4fSDavid du Colombier 		else {
8239a747e4fSDavid du Colombier 			sum.type = FT_SUMMARY;
8249a747e4fSDavid du Colombier 			sum.seq = s->seq;
8259a747e4fSDavid du Colombier 		}
8269a747e4fSDavid du Colombier 		if(debug)
8279a747e4fSDavid du Colombier 			fprint(2, "+ %J\n", &sum);
8289a747e4fSDavid du Colombier 		t->sum += sputw(t, &sum, 0, nil, nil);
8299a747e4fSDavid du Colombier 		if(t->sum >= Nsum)
8309a747e4fSDavid du Colombier 			t->sum = Nsum;
8319a747e4fSDavid du Colombier 
8329a747e4fSDavid du Colombier 		// Window 2
8339a747e4fSDavid du Colombier 		freesect(s);
8349a747e4fSDavid du Colombier 		g = &gens[eparity];
8359a747e4fSDavid du Colombier 		s = g->head;
8369a747e4fSDavid du Colombier 		if(s == nil) {
8379a747e4fSDavid du Colombier 			// Window 3
8389a747e4fSDavid du Colombier 			g->gnum += 2;
8399a747e4fSDavid du Colombier 			newsum(g, 0);
8409a747e4fSDavid du Colombier 			eparity ^= 1;
8419a747e4fSDavid du Colombier 			return;
8429a747e4fSDavid du Colombier 		}
8439a747e4fSDavid du Colombier 
8449a747e4fSDavid du Colombier 		if(nfree >= Nfree)
8459a747e4fSDavid du Colombier 			return;
8469a747e4fSDavid du Colombier 
8479a747e4fSDavid du Colombier 		g->head = s->next;
8489a747e4fSDavid du Colombier 		if(g->head == nil)
8499a747e4fSDavid du Colombier 			g->tail = nil;
8509a747e4fSDavid du Colombier 		g = &gens[eparity^1];
8519a747e4fSDavid du Colombier 	}
8529a747e4fSDavid du Colombier }
8539a747e4fSDavid du Colombier 
8549a747e4fSDavid du Colombier char *
need(int bytes)8559a747e4fSDavid du Colombier need(int bytes)
8569a747e4fSDavid du Colombier {
8579a747e4fSDavid du Colombier 	Gen *g;
8589a747e4fSDavid du Colombier 	int sums;
8599a747e4fSDavid du Colombier 	Sect *s, *t;
8609a747e4fSDavid du Colombier 
8619a747e4fSDavid du Colombier 	sums = 0;
8629a747e4fSDavid du Colombier 	for(;;) {
8639a747e4fSDavid du Colombier 		s = gens[eparity].tail;
8649a747e4fSDavid du Colombier 		if(s->coff + bytes < sectsize - Nsum + s->sum - 1)
8659a747e4fSDavid du Colombier 			return nil;
8669a747e4fSDavid du Colombier 
8679a747e4fSDavid du Colombier 		if(nfree >= Nfree)
8689a747e4fSDavid du Colombier 			break;
8699a747e4fSDavid du Colombier 
8709a747e4fSDavid du Colombier 		if(sums == 2) {
8719a747e4fSDavid du Colombier 			readonly = 1;
8729a747e4fSDavid du Colombier 			return "generation full";
8739a747e4fSDavid du Colombier 		}
8749a747e4fSDavid du Colombier 
8759a747e4fSDavid du Colombier 		summarize();
8769a747e4fSDavid du Colombier 		sums++;
8779a747e4fSDavid du Colombier 	}
8789a747e4fSDavid du Colombier 
8799a747e4fSDavid du Colombier 	g = &gens[eparity];
8809a747e4fSDavid du Colombier 	t = getsect();
8819a747e4fSDavid du Colombier 	t->seq = g->tail->seq + 1;
8829a747e4fSDavid du Colombier 	newsect(g, t);
8839a747e4fSDavid du Colombier 	return nil;
8849a747e4fSDavid du Colombier }
8859a747e4fSDavid du Colombier 
8869a747e4fSDavid du Colombier void
putw(Jrec * j,int mtime,Extent * x,void * a)8879a747e4fSDavid du Colombier putw(Jrec *j, int mtime, Extent *x, void *a)
8889a747e4fSDavid du Colombier {
8899a747e4fSDavid du Colombier 	sputw(gens[eparity].tail, j, mtime, x, a);
8909a747e4fSDavid du Colombier }
8919a747e4fSDavid du Colombier 
8929a747e4fSDavid du Colombier void
put(Jrec * j,int mtime)8939a747e4fSDavid du Colombier put(Jrec *j, int mtime)
8949a747e4fSDavid du Colombier {
8959a747e4fSDavid du Colombier 	sputw(gens[eparity].tail, j, mtime, nil, nil);
8969a747e4fSDavid du Colombier }
897