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