1*368c31abSDavid du Colombier #include "stdinc.h"
2*368c31abSDavid du Colombier #include "dat.h"
3*368c31abSDavid du Colombier #include "fns.h"
4*368c31abSDavid du Colombier
5*368c31abSDavid du Colombier static int verbose;
6*368c31abSDavid du Colombier static int fd;
7*368c31abSDavid du Colombier static int fd1;
8*368c31abSDavid du Colombier static uchar *data;
9*368c31abSDavid du Colombier static uchar *data1;
10*368c31abSDavid du Colombier static int blocksize;
11*368c31abSDavid du Colombier static int sleepms;
12*368c31abSDavid du Colombier
13*368c31abSDavid du Colombier void
usage(void)14*368c31abSDavid du Colombier usage(void)
15*368c31abSDavid du Colombier {
16*368c31abSDavid du Colombier fprint(2, "usage: cmparenas [-b blocksize] [-s ms] [-v] arenapart1 arenapart2 [name...]]\n");
17*368c31abSDavid du Colombier threadexitsall(0);
18*368c31abSDavid du Colombier }
19*368c31abSDavid du Colombier
20*368c31abSDavid du Colombier static int
preadblock(int fd,uchar * buf,int n,vlong off)21*368c31abSDavid du Colombier preadblock(int fd, uchar *buf, int n, vlong off)
22*368c31abSDavid du Colombier {
23*368c31abSDavid du Colombier int nr, m;
24*368c31abSDavid du Colombier
25*368c31abSDavid du Colombier for(nr = 0; nr < n; nr += m){
26*368c31abSDavid du Colombier m = n - nr;
27*368c31abSDavid du Colombier m = pread(fd, &buf[nr], m, off+nr);
28*368c31abSDavid du Colombier if(m <= 0){
29*368c31abSDavid du Colombier if(m == 0)
30*368c31abSDavid du Colombier werrstr("early eof");
31*368c31abSDavid du Colombier return -1;
32*368c31abSDavid du Colombier }
33*368c31abSDavid du Colombier }
34*368c31abSDavid du Colombier return 0;
35*368c31abSDavid du Colombier }
36*368c31abSDavid du Colombier
37*368c31abSDavid du Colombier static int
readblock(int fd,uchar * buf,int n)38*368c31abSDavid du Colombier readblock(int fd, uchar *buf, int n)
39*368c31abSDavid du Colombier {
40*368c31abSDavid du Colombier int nr, m;
41*368c31abSDavid du Colombier
42*368c31abSDavid du Colombier for(nr = 0; nr < n; nr += m){
43*368c31abSDavid du Colombier m = n - nr;
44*368c31abSDavid du Colombier m = read(fd, &buf[nr], m);
45*368c31abSDavid du Colombier if(m <= 0){
46*368c31abSDavid du Colombier if(m == 0)
47*368c31abSDavid du Colombier werrstr("early eof");
48*368c31abSDavid du Colombier return -1;
49*368c31abSDavid du Colombier }
50*368c31abSDavid du Colombier }
51*368c31abSDavid du Colombier return 0;
52*368c31abSDavid du Colombier }
53*368c31abSDavid du Colombier
54*368c31abSDavid du Colombier static int
printheader(char * name,ArenaHead * head,int fd)55*368c31abSDavid du Colombier printheader(char *name, ArenaHead *head, int fd)
56*368c31abSDavid du Colombier {
57*368c31abSDavid du Colombier Arena arena;
58*368c31abSDavid du Colombier vlong baseoff, lo, hi, off;
59*368c31abSDavid du Colombier int clumpmax;
60*368c31abSDavid du Colombier
61*368c31abSDavid du Colombier off = seek(fd, 0, 1);
62*368c31abSDavid du Colombier seek(fd, off + head->size - head->blocksize, 0);
63*368c31abSDavid du Colombier if(readblock(fd, data, head->blocksize) < 0){
64*368c31abSDavid du Colombier fprint(2, "%s: reading arena tail: %r\n", name);
65*368c31abSDavid du Colombier return -1;
66*368c31abSDavid du Colombier }
67*368c31abSDavid du Colombier seek(fd, off, 0);
68*368c31abSDavid du Colombier
69*368c31abSDavid du Colombier memset(&arena, 0, sizeof arena);
70*368c31abSDavid du Colombier if(unpackarena(&arena, data) < 0){
71*368c31abSDavid du Colombier fprint(2, "%s: unpack arena tail: %r\n", name);
72*368c31abSDavid du Colombier return -1;
73*368c31abSDavid du Colombier }
74*368c31abSDavid du Colombier arena.blocksize = head->blocksize;
75*368c31abSDavid du Colombier arena.base = off + head->blocksize;
76*368c31abSDavid du Colombier arena.clumpmax = arena.blocksize / ClumpInfoSize;
77*368c31abSDavid du Colombier arena.size = head->size - 2*head->blocksize;
78*368c31abSDavid du Colombier
79*368c31abSDavid du Colombier fprint(2, "%s: base=%llx size=%llx blocksize=%x\n", name, off, head->size, head->blocksize);
80*368c31abSDavid du Colombier
81*368c31abSDavid du Colombier baseoff = head->blocksize;
82*368c31abSDavid du Colombier fprint(2, "\t%llx-%llx: head\n", (vlong)0, baseoff);
83*368c31abSDavid du Colombier lo = baseoff;
84*368c31abSDavid du Colombier hi = baseoff + arena.diskstats.used;
85*368c31abSDavid du Colombier fprint(2, "\t%llx-%llx: data (%llx)\n", lo, hi, hi - lo);
86*368c31abSDavid du Colombier hi = head->size - head->blocksize;
87*368c31abSDavid du Colombier clumpmax = head->blocksize / ClumpInfoSize;
88*368c31abSDavid du Colombier if(clumpmax > 0)
89*368c31abSDavid du Colombier lo = hi - (u64int)arena.diskstats.clumps/clumpmax * head->blocksize;
90*368c31abSDavid du Colombier else
91*368c31abSDavid du Colombier lo = hi;
92*368c31abSDavid du Colombier fprint(2, "\t%llx-%llx: clumps (%llx)\n", lo, hi, hi - lo);
93*368c31abSDavid du Colombier fprint(2, "\t%llx-%llx: tail\n", hi, hi + head->blocksize);
94*368c31abSDavid du Colombier
95*368c31abSDavid du Colombier fprint(2, "arena:\n");
96*368c31abSDavid du Colombier printarena(2, &arena);
97*368c31abSDavid du Colombier return 0;
98*368c31abSDavid du Colombier }
99*368c31abSDavid du Colombier
100*368c31abSDavid du Colombier static void
cmparena(char * name,vlong len)101*368c31abSDavid du Colombier cmparena(char *name, vlong len)
102*368c31abSDavid du Colombier {
103*368c31abSDavid du Colombier ArenaHead head;
104*368c31abSDavid du Colombier DigestState s;
105*368c31abSDavid du Colombier u64int n, e;
106*368c31abSDavid du Colombier u32int bs;
107*368c31abSDavid du Colombier int i, j;
108*368c31abSDavid du Colombier char buf[20];
109*368c31abSDavid du Colombier
110*368c31abSDavid du Colombier fprint(2, "cmp %s\n", name);
111*368c31abSDavid du Colombier
112*368c31abSDavid du Colombier memset(&s, 0, sizeof s);
113*368c31abSDavid du Colombier
114*368c31abSDavid du Colombier /*
115*368c31abSDavid du Colombier * read a little bit, which will include the header
116*368c31abSDavid du Colombier */
117*368c31abSDavid du Colombier if(readblock(fd, data, HeadSize) < 0){
118*368c31abSDavid du Colombier fprint(2, "%s: reading header: %r\n", name);
119*368c31abSDavid du Colombier return;
120*368c31abSDavid du Colombier }
121*368c31abSDavid du Colombier if(unpackarenahead(&head, data) < 0){
122*368c31abSDavid du Colombier fprint(2, "%s: corrupt arena header: %r\n", name);
123*368c31abSDavid du Colombier return;
124*368c31abSDavid du Colombier }
125*368c31abSDavid du Colombier if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
126*368c31abSDavid du Colombier fprint(2, "%s: warning: unknown arena version %d\n", name, head.version);
127*368c31abSDavid du Colombier if(len != 0 && len != head.size)
128*368c31abSDavid du Colombier fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len);
129*368c31abSDavid du Colombier if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
130*368c31abSDavid du Colombier fprint(2, "%s: warning: unexpected name %s\n", name, head.name);
131*368c31abSDavid du Colombier
132*368c31abSDavid du Colombier if(readblock(fd1, data1, HeadSize) < 0){
133*368c31abSDavid du Colombier fprint(2, "%s: reading header: %r\n", name);
134*368c31abSDavid du Colombier return;
135*368c31abSDavid du Colombier }
136*368c31abSDavid du Colombier if(unpackarenahead(&head, data) < 0){
137*368c31abSDavid du Colombier fprint(2, "%s: corrupt arena header: %r\n", name);
138*368c31abSDavid du Colombier return;
139*368c31abSDavid du Colombier }
140*368c31abSDavid du Colombier if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
141*368c31abSDavid du Colombier fprint(2, "%s: warning: unknown arena version %d\n", name, head.version);
142*368c31abSDavid du Colombier if(len != 0 && len != head.size)
143*368c31abSDavid du Colombier fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len);
144*368c31abSDavid du Colombier if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
145*368c31abSDavid du Colombier fprint(2, "%s: warning: unexpected name %s\n", name, head.name);
146*368c31abSDavid du Colombier
147*368c31abSDavid du Colombier seek(fd, -HeadSize, 1);
148*368c31abSDavid du Colombier seek(fd1, -HeadSize, 1);
149*368c31abSDavid du Colombier
150*368c31abSDavid du Colombier if(printheader(name, &head, fd) < 0)
151*368c31abSDavid du Colombier return;
152*368c31abSDavid du Colombier
153*368c31abSDavid du Colombier /*
154*368c31abSDavid du Colombier * now we know how much to read
155*368c31abSDavid du Colombier * read everything but the last block, which is special
156*368c31abSDavid du Colombier */
157*368c31abSDavid du Colombier e = head.size;
158*368c31abSDavid du Colombier bs = blocksize;
159*368c31abSDavid du Colombier for(n = 0; n < e; n += bs){
160*368c31abSDavid du Colombier if(n + bs > e)
161*368c31abSDavid du Colombier bs = e - n;
162*368c31abSDavid du Colombier if(readblock(fd, data, bs) < 0){
163*368c31abSDavid du Colombier fprint(2, "%s: read data: %r\n", name);
164*368c31abSDavid du Colombier return;
165*368c31abSDavid du Colombier }
166*368c31abSDavid du Colombier if(readblock(fd1, data1, bs) < 0){
167*368c31abSDavid du Colombier fprint(2, "%s: read data: %r\n", name);
168*368c31abSDavid du Colombier return;
169*368c31abSDavid du Colombier }
170*368c31abSDavid du Colombier if(memcmp(data, data1, bs) != 0){
171*368c31abSDavid du Colombier print("mismatch at %llx\n", n);
172*368c31abSDavid du Colombier for(i=0; i<bs; i+=16){
173*368c31abSDavid du Colombier if(memcmp(data+i, data1+i, 16) != 0){
174*368c31abSDavid du Colombier snprint(buf, sizeof buf, "%llx", n+i);
175*368c31abSDavid du Colombier print("%s ", buf);
176*368c31abSDavid du Colombier for(j=0; j<16; j++){
177*368c31abSDavid du Colombier print(" %.2ux", data[i+j]);
178*368c31abSDavid du Colombier if(j == 7)
179*368c31abSDavid du Colombier print(" -");
180*368c31abSDavid du Colombier }
181*368c31abSDavid du Colombier print("\n");
182*368c31abSDavid du Colombier print("%*s ", (int)strlen(buf), "");
183*368c31abSDavid du Colombier for(j=0; j<16; j++){
184*368c31abSDavid du Colombier print(" %.2ux", data1[i+j]);
185*368c31abSDavid du Colombier if(j == 7)
186*368c31abSDavid du Colombier print(" -");
187*368c31abSDavid du Colombier }
188*368c31abSDavid du Colombier print("\n");
189*368c31abSDavid du Colombier }
190*368c31abSDavid du Colombier }
191*368c31abSDavid du Colombier }
192*368c31abSDavid du Colombier }
193*368c31abSDavid du Colombier }
194*368c31abSDavid du Colombier
195*368c31abSDavid du Colombier static int
shouldcheck(char * name,char ** s,int n)196*368c31abSDavid du Colombier shouldcheck(char *name, char **s, int n)
197*368c31abSDavid du Colombier {
198*368c31abSDavid du Colombier int i;
199*368c31abSDavid du Colombier
200*368c31abSDavid du Colombier if(n == 0)
201*368c31abSDavid du Colombier return 1;
202*368c31abSDavid du Colombier
203*368c31abSDavid du Colombier for(i=0; i<n; i++){
204*368c31abSDavid du Colombier if(s[i] && strcmp(name, s[i]) == 0){
205*368c31abSDavid du Colombier s[i] = nil;
206*368c31abSDavid du Colombier return 1;
207*368c31abSDavid du Colombier }
208*368c31abSDavid du Colombier }
209*368c31abSDavid du Colombier return 0;
210*368c31abSDavid du Colombier }
211*368c31abSDavid du Colombier
212*368c31abSDavid du Colombier char *
readap(int fd,ArenaPart * ap)213*368c31abSDavid du Colombier readap(int fd, ArenaPart *ap)
214*368c31abSDavid du Colombier {
215*368c31abSDavid du Colombier char *table;
216*368c31abSDavid du Colombier
217*368c31abSDavid du Colombier if(preadblock(fd, data, 8192, PartBlank) < 0)
218*368c31abSDavid du Colombier sysfatal("read arena part header: %r");
219*368c31abSDavid du Colombier if(unpackarenapart(ap, data) < 0)
220*368c31abSDavid du Colombier sysfatal("corrupted arena part header: %r");
221*368c31abSDavid du Colombier fprint(2, "# arena part version=%d blocksize=%d arenabase=%d\n",
222*368c31abSDavid du Colombier ap->version, ap->blocksize, ap->arenabase);
223*368c31abSDavid du Colombier ap->tabbase = (PartBlank+HeadSize+ap->blocksize-1)&~(ap->blocksize-1);
224*368c31abSDavid du Colombier ap->tabsize = ap->arenabase - ap->tabbase;
225*368c31abSDavid du Colombier table = malloc(ap->tabsize+1);
226*368c31abSDavid du Colombier if(preadblock(fd, (uchar*)table, ap->tabsize, ap->tabbase) < 0)
227*368c31abSDavid du Colombier sysfatal("reading arena part directory: %r");
228*368c31abSDavid du Colombier table[ap->tabsize] = 0;
229*368c31abSDavid du Colombier return table;
230*368c31abSDavid du Colombier }
231*368c31abSDavid du Colombier
232*368c31abSDavid du Colombier void
threadmain(int argc,char * argv[])233*368c31abSDavid du Colombier threadmain(int argc, char *argv[])
234*368c31abSDavid du Colombier {
235*368c31abSDavid du Colombier int i, nline;
236*368c31abSDavid du Colombier char *p, *q, *table, *table1, *f[10], line[256];
237*368c31abSDavid du Colombier vlong start, stop;
238*368c31abSDavid du Colombier ArenaPart ap;
239*368c31abSDavid du Colombier ArenaPart ap1;
240*368c31abSDavid du Colombier
241*368c31abSDavid du Colombier ventifmtinstall();
242*368c31abSDavid du Colombier blocksize = MaxIoSize;
243*368c31abSDavid du Colombier ARGBEGIN{
244*368c31abSDavid du Colombier case 'b':
245*368c31abSDavid du Colombier blocksize = unittoull(EARGF(usage()));
246*368c31abSDavid du Colombier break;
247*368c31abSDavid du Colombier case 's':
248*368c31abSDavid du Colombier sleepms = atoi(EARGF(usage()));
249*368c31abSDavid du Colombier break;
250*368c31abSDavid du Colombier case 'v':
251*368c31abSDavid du Colombier verbose++;
252*368c31abSDavid du Colombier break;
253*368c31abSDavid du Colombier default:
254*368c31abSDavid du Colombier usage();
255*368c31abSDavid du Colombier break;
256*368c31abSDavid du Colombier }ARGEND
257*368c31abSDavid du Colombier
258*368c31abSDavid du Colombier if(argc < 2)
259*368c31abSDavid du Colombier usage();
260*368c31abSDavid du Colombier
261*368c31abSDavid du Colombier data = vtmalloc(blocksize);
262*368c31abSDavid du Colombier data1 = vtmalloc(blocksize);
263*368c31abSDavid du Colombier if((fd = open(argv[0], OREAD)) < 0)
264*368c31abSDavid du Colombier sysfatal("open %s: %r", argv[0]);
265*368c31abSDavid du Colombier if((fd1 = open(argv[1], OREAD)) < 0)
266*368c31abSDavid du Colombier sysfatal("open %s: %r", argv[0]);
267*368c31abSDavid du Colombier
268*368c31abSDavid du Colombier table = readap(fd, &ap);
269*368c31abSDavid du Colombier table1 = readap(fd1, &ap1);
270*368c31abSDavid du Colombier if(strcmp(table, table1) != 0)
271*368c31abSDavid du Colombier sysfatal("arena partitions do not have identical tables");
272*368c31abSDavid du Colombier
273*368c31abSDavid du Colombier nline = atoi(table);
274*368c31abSDavid du Colombier p = strchr(table, '\n');
275*368c31abSDavid du Colombier if(p)
276*368c31abSDavid du Colombier p++;
277*368c31abSDavid du Colombier for(i=0; i<nline; i++){
278*368c31abSDavid du Colombier if(p == nil){
279*368c31abSDavid du Colombier fprint(2, "warning: unexpected arena table end\n");
280*368c31abSDavid du Colombier break;
281*368c31abSDavid du Colombier }
282*368c31abSDavid du Colombier q = strchr(p, '\n');
283*368c31abSDavid du Colombier if(q)
284*368c31abSDavid du Colombier *q++ = 0;
285*368c31abSDavid du Colombier if(strlen(p) >= sizeof line){
286*368c31abSDavid du Colombier fprint(2, "warning: long arena table line: %s\n", p);
287*368c31abSDavid du Colombier p = q;
288*368c31abSDavid du Colombier continue;
289*368c31abSDavid du Colombier }
290*368c31abSDavid du Colombier strcpy(line, p);
291*368c31abSDavid du Colombier memset(f, 0, sizeof f);
292*368c31abSDavid du Colombier if(tokenize(line, f, nelem(f)) < 3){
293*368c31abSDavid du Colombier fprint(2, "warning: bad arena table line: %s\n", p);
294*368c31abSDavid du Colombier p = q;
295*368c31abSDavid du Colombier continue;
296*368c31abSDavid du Colombier }
297*368c31abSDavid du Colombier p = q;
298*368c31abSDavid du Colombier if(shouldcheck(f[0], argv+1, argc-1)){
299*368c31abSDavid du Colombier start = strtoull(f[1], 0, 0);
300*368c31abSDavid du Colombier stop = strtoull(f[2], 0, 0);
301*368c31abSDavid du Colombier if(stop <= start){
302*368c31abSDavid du Colombier fprint(2, "%s: bad start,stop %lld,%lld\n", f[0], stop, start);
303*368c31abSDavid du Colombier continue;
304*368c31abSDavid du Colombier }
305*368c31abSDavid du Colombier if(seek(fd, start, 0) < 0)
306*368c31abSDavid du Colombier fprint(2, "%s: seek to start: %r\n", f[0]);
307*368c31abSDavid du Colombier if(seek(fd1, start, 0) < 0)
308*368c31abSDavid du Colombier fprint(2, "%s: seek to start: %r\n", f[0]);
309*368c31abSDavid du Colombier cmparena(f[0], stop - start);
310*368c31abSDavid du Colombier }
311*368c31abSDavid du Colombier }
312*368c31abSDavid du Colombier for(i=2; i<argc; i++)
313*368c31abSDavid du Colombier if(argv[i] != 0)
314*368c31abSDavid du Colombier fprint(2, "%s: did not find arena\n", argv[i]);
315*368c31abSDavid du Colombier
316*368c31abSDavid du Colombier threadexitsall(nil);
317*368c31abSDavid du Colombier }
318