xref: /plan9-contrib/sys/src/cmd/venti/srv/mirrorarenas.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1368c31abSDavid du Colombier /*
2368c31abSDavid du Colombier  * Mirror one arena partition onto another.
3368c31abSDavid du Colombier  * Be careful to copy only new data.
4368c31abSDavid du Colombier  */
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier #include "stdinc.h"
7368c31abSDavid du Colombier #include "dat.h"
8368c31abSDavid du Colombier #include "fns.h"
9368c31abSDavid du Colombier 
10368c31abSDavid du Colombier Channel *writechan;
11368c31abSDavid du Colombier 
12368c31abSDavid du Colombier typedef struct Write Write;
13368c31abSDavid du Colombier struct Write
14368c31abSDavid du Colombier {
15368c31abSDavid du Colombier 	uchar *p;
16368c31abSDavid du Colombier 	int n;
17368c31abSDavid du Colombier 	uvlong o;
18368c31abSDavid du Colombier 	int error;
19368c31abSDavid du Colombier };
20368c31abSDavid du Colombier 
21368c31abSDavid du Colombier Part *src;
22368c31abSDavid du Colombier Part *dst;
23368c31abSDavid du Colombier int force;
24368c31abSDavid du Colombier int verbose;
25*f9e1cf08SDavid du Colombier int dosha1 = 1;
26368c31abSDavid du Colombier char *status;
27368c31abSDavid du Colombier uvlong astart, aend;
28368c31abSDavid du Colombier 
29368c31abSDavid du Colombier void
usage(void)30368c31abSDavid du Colombier usage(void)
31368c31abSDavid du Colombier {
32*f9e1cf08SDavid du Colombier 	fprint(2, "usage: mirrorarenas [-sv] src dst [ranges]\n");
33368c31abSDavid du Colombier 	threadexitsall("usage");
34368c31abSDavid du Colombier }
35368c31abSDavid du Colombier 
36368c31abSDavid du Colombier char *tagged;
37368c31abSDavid du Colombier 
38368c31abSDavid du Colombier void
tag(char * fmt,...)39368c31abSDavid du Colombier tag(char *fmt, ...)
40368c31abSDavid du Colombier {
41368c31abSDavid du Colombier 	va_list arg;
42368c31abSDavid du Colombier 
43368c31abSDavid du Colombier 	if(tagged){
44368c31abSDavid du Colombier 		free(tagged);
45368c31abSDavid du Colombier 		tagged = nil;
46368c31abSDavid du Colombier 	}
47368c31abSDavid du Colombier 	va_start(arg, fmt);
48368c31abSDavid du Colombier 	tagged = vsmprint(fmt, arg);
49368c31abSDavid du Colombier 	va_end(arg);
50368c31abSDavid du Colombier }
51368c31abSDavid du Colombier 
52368c31abSDavid du Colombier void
chat(char * fmt,...)53368c31abSDavid du Colombier chat(char *fmt, ...)
54368c31abSDavid du Colombier {
55368c31abSDavid du Colombier 	va_list arg;
56368c31abSDavid du Colombier 
57368c31abSDavid du Colombier 	if(tagged){
58368c31abSDavid du Colombier 		write(1, tagged, strlen(tagged));
59368c31abSDavid du Colombier 		free(tagged);
60368c31abSDavid du Colombier 		tagged = nil;
61368c31abSDavid du Colombier 	}
62368c31abSDavid du Colombier 	va_start(arg, fmt);
63368c31abSDavid du Colombier 	vfprint(1, fmt, arg);
64368c31abSDavid du Colombier 	va_end(arg);
65368c31abSDavid du Colombier }
66368c31abSDavid du Colombier 
67368c31abSDavid du Colombier #pragma varargck argpos tag 1
68368c31abSDavid du Colombier #pragma varargck argpos chat 1
69368c31abSDavid du Colombier 
70368c31abSDavid du Colombier 
71368c31abSDavid du Colombier int
ereadpart(Part * p,u64int offset,u8int * buf,u32int count)72368c31abSDavid du Colombier ereadpart(Part *p, u64int offset, u8int *buf, u32int count)
73368c31abSDavid du Colombier {
74368c31abSDavid du Colombier 	if(readpart(p, offset, buf, count) != count){
75368c31abSDavid du Colombier 		chat("%T readpart %s at %#llux+%ud: %r\n", p->name, offset, count);
76368c31abSDavid du Colombier 		return -1;
77368c31abSDavid du Colombier 	}
78368c31abSDavid du Colombier 	return 0;
79368c31abSDavid du Colombier }
80368c31abSDavid du Colombier 
81368c31abSDavid du Colombier int
ewritepart(Part * p,u64int offset,u8int * buf,u32int count)82368c31abSDavid du Colombier ewritepart(Part *p, u64int offset, u8int *buf, u32int count)
83368c31abSDavid du Colombier {
84368c31abSDavid du Colombier 	if(writepart(p, offset, buf, count) != count || flushpart(p) < 0){
85368c31abSDavid du Colombier 		chat("%T writepart %s at %#llux+%ud: %r\n", p->name, offset, count);
86368c31abSDavid du Colombier 		return -1;
87368c31abSDavid du Colombier 	}
88368c31abSDavid du Colombier 	return 0;
89368c31abSDavid du Colombier }
90368c31abSDavid du Colombier 
91368c31abSDavid du Colombier /*
92368c31abSDavid du Colombier  * Extra proc to do writes to dst, so that we can overlap reading
93368c31abSDavid du Colombier  * src with writing dst during copy.  This is an easy factor of two
94368c31abSDavid du Colombier  * (almost) in performance.
95368c31abSDavid du Colombier  */
96*f9e1cf08SDavid du Colombier static Write wsync;
97368c31abSDavid du Colombier static void
writeproc(void * v)98368c31abSDavid du Colombier writeproc(void *v)
99368c31abSDavid du Colombier {
100368c31abSDavid du Colombier 	Write *w;
101368c31abSDavid du Colombier 
102368c31abSDavid du Colombier 	USED(v);
103368c31abSDavid du Colombier 	while((w = recvp(writechan)) != nil){
104*f9e1cf08SDavid du Colombier 		if(w == &wsync)
105368c31abSDavid du Colombier 			continue;
106368c31abSDavid du Colombier 		if(ewritepart(dst, w->o, w->p, w->n) < 0)
107368c31abSDavid du Colombier 			w->error = 1;
108368c31abSDavid du Colombier 	}
109368c31abSDavid du Colombier }
110368c31abSDavid du Colombier 
111368c31abSDavid du Colombier int
copy(uvlong start,uvlong end,char * what,DigestState * ds)112368c31abSDavid du Colombier copy(uvlong start, uvlong end, char *what, DigestState *ds)
113368c31abSDavid du Colombier {
114368c31abSDavid du Colombier 	int i, n;
115368c31abSDavid du Colombier 	uvlong o;
116368c31abSDavid du Colombier 	static uchar tmp[2][1024*1024];
117368c31abSDavid du Colombier 	Write w[2];
118368c31abSDavid du Colombier 
119368c31abSDavid du Colombier 	assert(start <= end);
120368c31abSDavid du Colombier 	assert(astart <= start && start < aend);
121368c31abSDavid du Colombier 	assert(astart <= end && end <= aend);
122368c31abSDavid du Colombier 
123368c31abSDavid du Colombier 	if(verbose && start != end)
124368c31abSDavid du Colombier 		chat("%T   copy %,llud-%,llud %s\n", start, end, what);
125368c31abSDavid du Colombier 
126368c31abSDavid du Colombier 	i = 0;
127368c31abSDavid du Colombier 	memset(w, 0, sizeof w);
128368c31abSDavid du Colombier 	for(o=start; o<end; o+=n){
129368c31abSDavid du Colombier 		if(w[i].error)
130368c31abSDavid du Colombier 			goto error;
131368c31abSDavid du Colombier 		n = sizeof tmp[i];
132368c31abSDavid du Colombier 		if(o+n > end)
133368c31abSDavid du Colombier 			n = end - o;
134368c31abSDavid du Colombier 		if(ereadpart(src, o, tmp[i], n) < 0)
135368c31abSDavid du Colombier 			goto error;
136368c31abSDavid du Colombier 		w[i].p = tmp[i];
137368c31abSDavid du Colombier 		w[i].o = o;
138368c31abSDavid du Colombier 		w[i].n = n;
139368c31abSDavid du Colombier 		w[i].error = 0;
140368c31abSDavid du Colombier 		sendp(writechan, &w[i]);
141368c31abSDavid du Colombier 		if(ds)
142368c31abSDavid du Colombier 			sha1(tmp[i], n, nil, ds);
143368c31abSDavid du Colombier 		i = 1-i;
144368c31abSDavid du Colombier 	}
145368c31abSDavid du Colombier 	if(w[i].error)
146368c31abSDavid du Colombier 		goto error;
147368c31abSDavid du Colombier 
148368c31abSDavid du Colombier 	/*
149368c31abSDavid du Colombier 	 * wait for queued write to finish
150368c31abSDavid du Colombier 	 */
151*f9e1cf08SDavid du Colombier 	sendp(writechan, &wsync);
152368c31abSDavid du Colombier 	i = 1-i;
153368c31abSDavid du Colombier 	if(w[i].error)
154368c31abSDavid du Colombier 		return -1;
155368c31abSDavid du Colombier 	return 0;
156368c31abSDavid du Colombier 
157368c31abSDavid du Colombier error:
158368c31abSDavid du Colombier 	/*
159368c31abSDavid du Colombier 	 * sync with write proc
160368c31abSDavid du Colombier 	 */
161368c31abSDavid du Colombier 	w[i].p = nil;
162368c31abSDavid du Colombier 	w[i].o = 0;
163368c31abSDavid du Colombier 	w[i].n = 0;
164368c31abSDavid du Colombier 	w[i].error = 0;
165368c31abSDavid du Colombier 	sendp(writechan, &w[i]);
166368c31abSDavid du Colombier 	return -1;
167368c31abSDavid du Colombier }
168368c31abSDavid du Colombier 
169368c31abSDavid du Colombier /* single-threaded, for reference */
170368c31abSDavid du Colombier int
copy1(uvlong start,uvlong end,char * what,DigestState * ds)171368c31abSDavid du Colombier copy1(uvlong start, uvlong end, char *what, DigestState *ds)
172368c31abSDavid du Colombier {
173368c31abSDavid du Colombier 	int n;
174368c31abSDavid du Colombier 	uvlong o;
175368c31abSDavid du Colombier 	static uchar tmp[1024*1024];
176368c31abSDavid du Colombier 
177368c31abSDavid du Colombier 	assert(start <= end);
178368c31abSDavid du Colombier 	assert(astart <= start && start < aend);
179368c31abSDavid du Colombier 	assert(astart <= end && end <= aend);
180368c31abSDavid du Colombier 
181368c31abSDavid du Colombier 	if(verbose && start != end)
182368c31abSDavid du Colombier 		chat("%T   copy %,llud-%,llud %s\n", start, end, what);
183368c31abSDavid du Colombier 
184368c31abSDavid du Colombier 	for(o=start; o<end; o+=n){
185368c31abSDavid du Colombier 		n = sizeof tmp;
186368c31abSDavid du Colombier 		if(o+n > end)
187368c31abSDavid du Colombier 			n = end - o;
188368c31abSDavid du Colombier 		if(ereadpart(src, o, tmp, n) < 0)
189368c31abSDavid du Colombier 			return -1;
190368c31abSDavid du Colombier 		if(ds)
191368c31abSDavid du Colombier 			sha1(tmp, n, nil, ds);
192368c31abSDavid du Colombier 		if(ewritepart(dst, o, tmp, n) < 0)
193368c31abSDavid du Colombier 			return -1;
194368c31abSDavid du Colombier 	}
195368c31abSDavid du Colombier 	return 0;
196368c31abSDavid du Colombier }
197368c31abSDavid du Colombier 
198368c31abSDavid du Colombier int
asha1(Part * p,uvlong start,uvlong end,DigestState * ds)199368c31abSDavid du Colombier asha1(Part *p, uvlong start, uvlong end, DigestState *ds)
200368c31abSDavid du Colombier {
201368c31abSDavid du Colombier 	int n;
202368c31abSDavid du Colombier 	uvlong o;
203368c31abSDavid du Colombier 	static uchar tmp[1024*1024];
204368c31abSDavid du Colombier 
205368c31abSDavid du Colombier 	if(start == end)
206368c31abSDavid du Colombier 		return 0;
207368c31abSDavid du Colombier 	assert(start < end);
208368c31abSDavid du Colombier 
209368c31abSDavid du Colombier 	if(verbose)
210368c31abSDavid du Colombier 		chat("%T   sha1 %,llud-%,llud\n", start, end);
211368c31abSDavid du Colombier 
212368c31abSDavid du Colombier 	for(o=start; o<end; o+=n){
213368c31abSDavid du Colombier 		n = sizeof tmp;
214368c31abSDavid du Colombier 		if(o+n > end)
215368c31abSDavid du Colombier 			n = end - o;
216368c31abSDavid du Colombier 		if(ereadpart(p, o, tmp, n) < 0)
217368c31abSDavid du Colombier 			return -1;
218368c31abSDavid du Colombier 		sha1(tmp, n, nil, ds);
219368c31abSDavid du Colombier 	}
220368c31abSDavid du Colombier 	return 0;
221368c31abSDavid du Colombier }
222368c31abSDavid du Colombier 
223368c31abSDavid du Colombier uvlong
rdown(uvlong a,int b)224368c31abSDavid du Colombier rdown(uvlong a, int b)
225368c31abSDavid du Colombier {
226368c31abSDavid du Colombier 	return a-a%b;
227368c31abSDavid du Colombier }
228368c31abSDavid du Colombier 
229368c31abSDavid du Colombier uvlong
rup(uvlong a,int b)230368c31abSDavid du Colombier rup(uvlong a, int b)
231368c31abSDavid du Colombier {
232368c31abSDavid du Colombier 	if(a%b == 0)
233368c31abSDavid du Colombier 		return a;
234368c31abSDavid du Colombier 	return a+b-a%b;
235368c31abSDavid du Colombier }
236368c31abSDavid du Colombier 
237368c31abSDavid du Colombier void
mirror(Arena * sa,Arena * da)238368c31abSDavid du Colombier mirror(Arena *sa, Arena *da)
239368c31abSDavid du Colombier {
240368c31abSDavid du Colombier 	vlong v, si, di, end;
241*f9e1cf08SDavid du Colombier 	int clumpmax, blocksize, sealed;
242368c31abSDavid du Colombier 	static uchar buf[MaxIoSize];
243368c31abSDavid du Colombier 	ArenaHead h;
244368c31abSDavid du Colombier 	DigestState xds, *ds;
245368c31abSDavid du Colombier 	vlong shaoff, base;
246368c31abSDavid du Colombier 
247368c31abSDavid du Colombier 	base = sa->base;
248368c31abSDavid du Colombier 	blocksize = sa->blocksize;
249368c31abSDavid du Colombier 	end = sa->base + sa->size;
250368c31abSDavid du Colombier 
251368c31abSDavid du Colombier 	astart = base - blocksize;
252368c31abSDavid du Colombier 	aend = end + blocksize;
253368c31abSDavid du Colombier 
254368c31abSDavid du Colombier 	tag("%T %s (%,llud-%,llud)\n", sa->name, astart, aend);
255368c31abSDavid du Colombier 
256368c31abSDavid du Colombier 	if(force){
257368c31abSDavid du Colombier 		copy(astart, aend, "all", nil);
258368c31abSDavid du Colombier 		return;
259368c31abSDavid du Colombier 	}
260368c31abSDavid du Colombier 
261368c31abSDavid du Colombier 	if(sa->diskstats.sealed && da->diskstats.sealed && scorecmp(da->score, zeroscore) != 0){
262368c31abSDavid du Colombier 		if(scorecmp(sa->score, da->score) == 0){
263368c31abSDavid du Colombier 			if(verbose)
264368c31abSDavid du Colombier 				chat("%T %s: %V sealed mirrored\n", sa->name, sa->score);
265368c31abSDavid du Colombier 			return;
266368c31abSDavid du Colombier 		}
267368c31abSDavid du Colombier 		chat("%T %s: warning: sealed score mismatch %V vs %V\n", sa->name, sa->score, da->score);
268368c31abSDavid du Colombier 		/* Keep executing; will correct seal if possible. */
269368c31abSDavid du Colombier 	}
270368c31abSDavid du Colombier 	if(!sa->diskstats.sealed && da->diskstats.sealed && scorecmp(da->score, zeroscore) != 0){
271368c31abSDavid du Colombier 		chat("%T %s: dst is sealed, src is not\n", sa->name);
272368c31abSDavid du Colombier 		status = "errors";
273368c31abSDavid du Colombier 		return;
274368c31abSDavid du Colombier 	}
275368c31abSDavid du Colombier 	if(sa->diskstats.used < da->diskstats.used){
276368c31abSDavid du Colombier 		chat("%T %s: src used %,lld < dst used %,lld\n", sa->name, sa->diskstats.used, da->diskstats.used);
277368c31abSDavid du Colombier 		status = "errors";
278368c31abSDavid du Colombier 		return;
279368c31abSDavid du Colombier 	}
280368c31abSDavid du Colombier 
281368c31abSDavid du Colombier 	if(da->clumpmagic != sa->clumpmagic){
282368c31abSDavid du Colombier 		/*
283368c31abSDavid du Colombier 		 * Write this now to reduce the window in which
284368c31abSDavid du Colombier 		 * the head and tail disagree about clumpmagic.
285368c31abSDavid du Colombier 		 */
286368c31abSDavid du Colombier 		da->clumpmagic = sa->clumpmagic;
287368c31abSDavid du Colombier 		memset(buf, 0, sizeof buf);
288368c31abSDavid du Colombier 		packarena(da, buf);
289368c31abSDavid du Colombier 		if(ewritepart(dst, end, buf, blocksize) < 0)
290368c31abSDavid du Colombier 			return;
291368c31abSDavid du Colombier 	}
292368c31abSDavid du Colombier 
293368c31abSDavid du Colombier 	memset(&h, 0, sizeof h);
294368c31abSDavid du Colombier 	h.version = da->version;
295368c31abSDavid du Colombier 	strcpy(h.name, da->name);
296368c31abSDavid du Colombier 	h.blocksize = da->blocksize;
297368c31abSDavid du Colombier 	h.size = da->size + 2*da->blocksize;
298368c31abSDavid du Colombier 	h.clumpmagic = da->clumpmagic;
299368c31abSDavid du Colombier 	memset(buf, 0, sizeof buf);
300368c31abSDavid du Colombier 	packarenahead(&h, buf);
301368c31abSDavid du Colombier 	if(ewritepart(dst, base - blocksize, buf, blocksize) < 0)
302368c31abSDavid du Colombier 		return;
303368c31abSDavid du Colombier 
304368c31abSDavid du Colombier 	shaoff = 0;
305368c31abSDavid du Colombier 	ds = nil;
306*f9e1cf08SDavid du Colombier 	sealed = sa->diskstats.sealed && scorecmp(sa->score, zeroscore) != 0;
307*f9e1cf08SDavid du Colombier 	if(sealed && dosha1){
308368c31abSDavid du Colombier 		/* start sha1 state with header */
309368c31abSDavid du Colombier 		memset(&xds, 0, sizeof xds);
310368c31abSDavid du Colombier 		ds = &xds;
311368c31abSDavid du Colombier 		sha1(buf, blocksize, nil, ds);
312368c31abSDavid du Colombier 		shaoff = base;
313368c31abSDavid du Colombier 	}
314368c31abSDavid du Colombier 
315368c31abSDavid du Colombier 	if(sa->diskstats.used != da->diskstats.used){
316368c31abSDavid du Colombier 		di = base+rdown(da->diskstats.used, blocksize);
317368c31abSDavid du Colombier 		si = base+rup(sa->diskstats.used, blocksize);
318368c31abSDavid du Colombier 		if(ds && asha1(dst, shaoff, di, ds) < 0)
319368c31abSDavid du Colombier 			return;
320368c31abSDavid du Colombier 		if(copy(di, si, "data", ds) < 0)
321368c31abSDavid du Colombier 			return;
322368c31abSDavid du Colombier 		shaoff = si;
323368c31abSDavid du Colombier 	}
324368c31abSDavid du Colombier 
325368c31abSDavid du Colombier 	clumpmax = sa->clumpmax;
326368c31abSDavid du Colombier 	di = end - da->diskstats.clumps/clumpmax * blocksize;
327368c31abSDavid du Colombier 	si = end - (sa->diskstats.clumps+clumpmax-1)/clumpmax * blocksize;
328368c31abSDavid du Colombier 
329368c31abSDavid du Colombier 	if(sa->diskstats.sealed){
330368c31abSDavid du Colombier 		/*
331368c31abSDavid du Colombier 		 * might be a small hole between the end of the
332368c31abSDavid du Colombier 		 * data and the beginning of the directory.
333368c31abSDavid du Colombier 		 */
334368c31abSDavid du Colombier 		v = base+rup(sa->diskstats.used, blocksize);
335368c31abSDavid du Colombier 		if(ds && asha1(dst, shaoff, v, ds) < 0)
336368c31abSDavid du Colombier 			return;
337368c31abSDavid du Colombier 		if(copy(v, si, "hole", ds) < 0)
338368c31abSDavid du Colombier 			return;
339368c31abSDavid du Colombier 		shaoff = si;
340368c31abSDavid du Colombier 	}
341368c31abSDavid du Colombier 
342368c31abSDavid du Colombier 	if(da->diskstats.clumps != sa->diskstats.clumps){
343368c31abSDavid du Colombier 		if(ds && asha1(dst, shaoff, si, ds) < 0)
344368c31abSDavid du Colombier 			return;
345368c31abSDavid du Colombier 		if(copy(si, di, "directory", ds) < 0)	/* si < di  because clumpinfo blocks grow down */
346368c31abSDavid du Colombier 			return;
347368c31abSDavid du Colombier 		shaoff = di;
348368c31abSDavid du Colombier 	}
349368c31abSDavid du Colombier 
350368c31abSDavid du Colombier 	da->ctime = sa->ctime;
351368c31abSDavid du Colombier 	da->wtime = sa->wtime;
352368c31abSDavid du Colombier 	da->diskstats = sa->diskstats;
353368c31abSDavid du Colombier 	da->diskstats.sealed = 0;
354368c31abSDavid du Colombier 
355368c31abSDavid du Colombier 	/*
356368c31abSDavid du Colombier 	 * Repack the arena tail information
357368c31abSDavid du Colombier 	 * and save it for next time...
358368c31abSDavid du Colombier 	 */
359368c31abSDavid du Colombier 	memset(buf, 0, sizeof buf);
360368c31abSDavid du Colombier 	packarena(da, buf);
361368c31abSDavid du Colombier 	if(ewritepart(dst, end, buf, blocksize) < 0)
362368c31abSDavid du Colombier 		return;
363368c31abSDavid du Colombier 
364*f9e1cf08SDavid du Colombier 	if(sealed){
365368c31abSDavid du Colombier 		/*
366368c31abSDavid du Colombier 		 * ... but on the final pass, copy the encoding
367368c31abSDavid du Colombier 		 * of the tail information from the source
368368c31abSDavid du Colombier 		 * arena itself.  There are multiple possible
369368c31abSDavid du Colombier 		 * ways to write the tail info out (the exact
370368c31abSDavid du Colombier 		 * details have changed as venti went through
371368c31abSDavid du Colombier 		 * revisions), and to keep the SHA1 hash the
372368c31abSDavid du Colombier 		 * same, we have to use what the disk uses.
373368c31abSDavid du Colombier 		 */
374368c31abSDavid du Colombier 		if(asha1(dst, shaoff, end, ds) < 0
375368c31abSDavid du Colombier 		|| copy(end, end+blocksize-VtScoreSize, "tail", ds) < 0)
376368c31abSDavid du Colombier 			return;
377*f9e1cf08SDavid du Colombier 		if(dosha1){
378368c31abSDavid du Colombier 			memset(buf, 0, VtScoreSize);
379368c31abSDavid du Colombier 			sha1(buf, VtScoreSize, da->score, ds);
380368c31abSDavid du Colombier 			if(scorecmp(sa->score, da->score) == 0){
381368c31abSDavid du Colombier 				if(verbose)
382368c31abSDavid du Colombier 					chat("%T %s: %V sealed mirrored\n", sa->name, sa->score);
383368c31abSDavid du Colombier 				if(ewritepart(dst, end+blocksize-VtScoreSize, da->score, VtScoreSize) < 0)
384368c31abSDavid du Colombier 					return;
385368c31abSDavid du Colombier 			}else{
386368c31abSDavid du Colombier 				chat("%T %s: sealing dst: score mismatch: %V vs %V\n", sa->name, sa->score, da->score);
387368c31abSDavid du Colombier 				memset(&xds, 0, sizeof xds);
388368c31abSDavid du Colombier 				asha1(dst, base-blocksize, end+blocksize-VtScoreSize, &xds);
389368c31abSDavid du Colombier 				sha1(buf, VtScoreSize, 0, &xds);
390368c31abSDavid du Colombier 				chat("%T   reseal: %V\n", da->score);
391368c31abSDavid du Colombier 				status = "errors";
392368c31abSDavid du Colombier 			}
393368c31abSDavid du Colombier 		}else{
394*f9e1cf08SDavid du Colombier 			if(verbose)
395*f9e1cf08SDavid du Colombier 				chat("%T %s: %V mirrored\n", sa->name, sa->score);
396*f9e1cf08SDavid du Colombier 			if(ewritepart(dst, end+blocksize-VtScoreSize, sa->score, VtScoreSize) < 0)
397*f9e1cf08SDavid du Colombier 				return;
398*f9e1cf08SDavid du Colombier 		}
399*f9e1cf08SDavid du Colombier 	}else{
400368c31abSDavid du Colombier 		chat("%T %s: %,lld used mirrored\n",
401368c31abSDavid du Colombier 			sa->name, sa->diskstats.used);
402368c31abSDavid du Colombier 	}
403368c31abSDavid du Colombier }
404368c31abSDavid du Colombier 
405368c31abSDavid du Colombier void
mirrormany(ArenaPart * sp,ArenaPart * dp,char * range)406368c31abSDavid du Colombier mirrormany(ArenaPart *sp, ArenaPart *dp, char *range)
407368c31abSDavid du Colombier {
408368c31abSDavid du Colombier 	int i, lo, hi;
409368c31abSDavid du Colombier 	char *s, *t;
410368c31abSDavid du Colombier 	Arena *sa, *da;
411368c31abSDavid du Colombier 
412368c31abSDavid du Colombier 	if(range == nil){
413368c31abSDavid du Colombier 		for(i=0; i<sp->narenas; i++){
414368c31abSDavid du Colombier 			sa = sp->arenas[i];
415368c31abSDavid du Colombier 			da = dp->arenas[i];
416368c31abSDavid du Colombier 			mirror(sa, da);
417368c31abSDavid du Colombier 		}
418368c31abSDavid du Colombier 		return;
419368c31abSDavid du Colombier 	}
420368c31abSDavid du Colombier 	if(strcmp(range, "none") == 0)
421368c31abSDavid du Colombier 		return;
422368c31abSDavid du Colombier 
423368c31abSDavid du Colombier 	for(s=range; *s; s=t){
424368c31abSDavid du Colombier 		t = strchr(s, ',');
425368c31abSDavid du Colombier 		if(t)
426368c31abSDavid du Colombier 			*t++ = 0;
427368c31abSDavid du Colombier 		else
428368c31abSDavid du Colombier 			t = s+strlen(s);
429368c31abSDavid du Colombier 		if(*s == '-')
430368c31abSDavid du Colombier 			lo = 0;
431368c31abSDavid du Colombier 		else
432368c31abSDavid du Colombier 			lo = strtol(s, &s, 0);
433368c31abSDavid du Colombier 		hi = lo;
434368c31abSDavid du Colombier 		if(*s == '-'){
435368c31abSDavid du Colombier 			s++;
436368c31abSDavid du Colombier 			if(*s == 0)
437368c31abSDavid du Colombier 				hi = sp->narenas-1;
438368c31abSDavid du Colombier 			else
439368c31abSDavid du Colombier 				hi = strtol(s, &s, 0);
440368c31abSDavid du Colombier 		}
441368c31abSDavid du Colombier 		if(*s != 0){
442368c31abSDavid du Colombier 			chat("%T bad arena range: %s\n", s);
443368c31abSDavid du Colombier 			continue;
444368c31abSDavid du Colombier 		}
445368c31abSDavid du Colombier 		for(i=lo; i<=hi; i++){
446368c31abSDavid du Colombier 			sa = sp->arenas[i];
447368c31abSDavid du Colombier 			da = dp->arenas[i];
448368c31abSDavid du Colombier 			mirror(sa, da);
449368c31abSDavid du Colombier 		}
450368c31abSDavid du Colombier 	}
451368c31abSDavid du Colombier }
452368c31abSDavid du Colombier 
453368c31abSDavid du Colombier 
454368c31abSDavid du Colombier void
threadmain(int argc,char ** argv)455368c31abSDavid du Colombier threadmain(int argc, char **argv)
456368c31abSDavid du Colombier {
457368c31abSDavid du Colombier 	int i;
458368c31abSDavid du Colombier 	Arena *sa, *da;
459368c31abSDavid du Colombier 	ArenaPart *s, *d;
460368c31abSDavid du Colombier 	char *ranges;
461368c31abSDavid du Colombier 
462368c31abSDavid du Colombier 	ventifmtinstall();
463368c31abSDavid du Colombier 
464368c31abSDavid du Colombier 	ARGBEGIN{
465368c31abSDavid du Colombier 	case 'F':
466368c31abSDavid du Colombier 		force = 1;
467368c31abSDavid du Colombier 		break;
468368c31abSDavid du Colombier 	case 'v':
469368c31abSDavid du Colombier 		verbose++;
470368c31abSDavid du Colombier 		break;
471*f9e1cf08SDavid du Colombier 	case 's':
472*f9e1cf08SDavid du Colombier 		dosha1 = 0;
473*f9e1cf08SDavid du Colombier 		break;
474368c31abSDavid du Colombier 	default:
475368c31abSDavid du Colombier 		usage();
476368c31abSDavid du Colombier 	}ARGEND
477368c31abSDavid du Colombier 
478368c31abSDavid du Colombier 	if(argc != 2 && argc != 3)
479368c31abSDavid du Colombier 		usage();
480368c31abSDavid du Colombier 	ranges = nil;
481368c31abSDavid du Colombier 	if(argc == 3)
482368c31abSDavid du Colombier 		ranges = argv[2];
483368c31abSDavid du Colombier 
484368c31abSDavid du Colombier 	if((src = initpart(argv[0], OREAD)) == nil)
485368c31abSDavid du Colombier 		sysfatal("initpart %s: %r", argv[0]);
486368c31abSDavid du Colombier 	if((dst = initpart(argv[1], ORDWR)) == nil)
487368c31abSDavid du Colombier 		sysfatal("initpart %s: %r", argv[1]);
488368c31abSDavid du Colombier 	if((s = initarenapart(src)) == nil)
489368c31abSDavid du Colombier 		sysfatal("initarenapart %s: %r", argv[0]);
490368c31abSDavid du Colombier 	for(i=0; i<s->narenas; i++)
491368c31abSDavid du Colombier 		delarena(s->arenas[i]);
492368c31abSDavid du Colombier 	if((d = initarenapart(dst)) == nil)
493368c31abSDavid du Colombier 		sysfatal("loadarenapart %s: %r", argv[1]);
494368c31abSDavid du Colombier 	for(i=0; i<d->narenas; i++)
495368c31abSDavid du Colombier 		delarena(d->arenas[i]);
496368c31abSDavid du Colombier 
497368c31abSDavid du Colombier 	/*
498368c31abSDavid du Colombier 	 * The arena geometries must match or all bets are off.
499368c31abSDavid du Colombier 	 */
500368c31abSDavid du Colombier 	if(s->narenas != d->narenas)
501368c31abSDavid du Colombier 		sysfatal("arena count mismatch: %d vs %d", s->narenas, d->narenas);
502368c31abSDavid du Colombier 	for(i=0; i<s->narenas; i++){
503368c31abSDavid du Colombier 		sa = s->arenas[i];
504368c31abSDavid du Colombier 		da = d->arenas[i];
505368c31abSDavid du Colombier 		if(sa->version != da->version)
506368c31abSDavid du Colombier 			sysfatal("arena %d: version mismatch: %d vs %d", i, sa->version, da->version);
507368c31abSDavid du Colombier 		if(sa->blocksize != da->blocksize)
508368c31abSDavid du Colombier 			sysfatal("arena %d: blocksize mismatch: %d vs %d", i, sa->blocksize, da->blocksize);
509368c31abSDavid du Colombier 		if(sa->size != da->size)
510368c31abSDavid du Colombier 			sysfatal("arena %d: size mismatch: %,lld vs %,lld", i, sa->size, da->size);
511368c31abSDavid du Colombier 		if(strcmp(sa->name, da->name) != 0)
512368c31abSDavid du Colombier 			sysfatal("arena %d: name mismatch: %s vs %s", i, sa->name, da->name);
513368c31abSDavid du Colombier 	}
514368c31abSDavid du Colombier 
515368c31abSDavid du Colombier 	/*
516368c31abSDavid du Colombier 	 * Mirror one arena at a time.
517368c31abSDavid du Colombier 	 */
518368c31abSDavid du Colombier 	writechan = chancreate(sizeof(void*), 0);
519368c31abSDavid du Colombier 	vtproc(writeproc, nil);
520368c31abSDavid du Colombier 	mirrormany(s, d, ranges);
521368c31abSDavid du Colombier 	sendp(writechan, nil);
522368c31abSDavid du Colombier 	threadexitsall(status);
523368c31abSDavid du Colombier }
524