]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
dfc130f3 | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
2bd0ea18 | 7 | * published by the Free Software Foundation. |
dfc130f3 | 8 | * |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
dfc130f3 | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
2bd0ea18 NS |
17 | */ |
18 | ||
19 | #include "logprint.h" | |
20 | ||
dfb5b7da | 21 | #define CLEARED_BLKS (-5) |
2bd0ea18 NS |
22 | #define ZEROED_LOG (-4) |
23 | #define FULL_READ (-3) | |
24 | #define PARTIAL_READ (-2) | |
25 | #define BAD_HEADER (-1) | |
26 | #define NO_ERROR (0) | |
27 | ||
28 | static int logBBsize; | |
29 | char *trans_type[] = { | |
30 | "", | |
31 | "SETATTR", | |
32 | "SETATTR_SIZE", | |
33 | "INACTIVE", | |
34 | "CREATE", | |
35 | "CREATE_TRUNC", | |
36 | "TRUNCATE_FILE", | |
37 | "REMOVE", | |
38 | "LINK", | |
39 | "RENAME", | |
40 | "MKDIR", | |
41 | "RMDIR", | |
42 | "SYMLINK", | |
43 | "SET_DMATTRS", | |
44 | "GROWFS", | |
45 | "STRAT_WRITE", | |
46 | "DIOSTRAT", | |
47 | "WRITE_SYNC", | |
48 | "WRITEID", | |
49 | "ADDAFORK", | |
50 | "ATTRINVAL", | |
51 | "ATRUNCATE", | |
52 | "ATTR_SET", | |
53 | "ATTR_RM", | |
54 | "ATTR_FLAG", | |
55 | "CLEAR_AGI_BUCKET", | |
56 | "QM_SBCHANGE", | |
57 | "DUMMY1", | |
58 | "DUMMY2", | |
59 | "QM_QUOTAOFF", | |
60 | "QM_DQALLOC", | |
61 | "QM_SETQLIM", | |
62 | "QM_DQCLUSTER", | |
63 | "QM_QINOCREATE", | |
64 | "QM_QUOTAOFF_END", | |
65 | "SB_UNIT", | |
66 | "FSYNC_TS", | |
67 | "GROWFSRT_ALLOC", | |
68 | "GROWFSRT_ZERO", | |
69 | "GROWFSRT_FREE", | |
70 | "SWAPEXT", | |
46eca962 | 71 | "SB_COUNT", |
2bd0ea18 NS |
72 | }; |
73 | ||
74 | typedef struct xlog_split_item { | |
75 | struct xlog_split_item *si_next; | |
76 | struct xlog_split_item *si_prev; | |
77 | xlog_tid_t si_tid; | |
78 | int si_skip; | |
79 | } xlog_split_item_t; | |
80 | ||
81 | xlog_split_item_t *split_list = 0; | |
82 | ||
83 | void | |
84 | print_xlog_op_line(void) | |
85 | { | |
86 | printf("--------------------------------------" | |
dfc130f3 | 87 | "--------------------------------------\n"); |
2bd0ea18 NS |
88 | } /* print_xlog_op_line */ |
89 | ||
dfb5b7da | 90 | void |
91 | print_xlog_xhdr_line(void) | |
92 | { | |
93 | printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" | |
94 | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); | |
95 | } /* print_xlog_xhdr_line */ | |
96 | ||
2bd0ea18 NS |
97 | void |
98 | print_xlog_record_line(void) | |
99 | { | |
100 | printf("======================================" | |
dfc130f3 | 101 | "======================================\n"); |
2bd0ea18 NS |
102 | } /* print_xlog_record_line */ |
103 | ||
104 | void | |
105 | print_stars(void) | |
106 | { | |
107 | printf("***********************************" | |
dfc130f3 | 108 | "***********************************\n"); |
dfb5b7da | 109 | } /* print_stars */ |
2bd0ea18 NS |
110 | |
111 | /* | |
112 | * Given a pointer to a data segment, print out the data as if it were | |
113 | * a log operation header. | |
114 | */ | |
115 | void | |
116 | xlog_print_op_header(xlog_op_header_t *op_head, | |
117 | int i, | |
118 | xfs_caddr_t *ptr) | |
119 | { | |
120 | xlog_op_header_t hbuf; | |
121 | ||
122 | /* | |
123 | * bcopy because on 64/n32, partial reads can cause the op_head | |
124 | * pointer to come in pointing to an odd-numbered byte | |
125 | */ | |
126 | bcopy(op_head, &hbuf, sizeof(xlog_op_header_t)); | |
127 | op_head = &hbuf; | |
128 | *ptr += sizeof(xlog_op_header_t); | |
129 | printf("Oper (%d): tid: %x len: %d clientid: %s ", i, | |
130 | INT_GET(op_head->oh_tid, ARCH_CONVERT), | |
131 | INT_GET(op_head->oh_len, ARCH_CONVERT), | |
132 | (op_head->oh_clientid == XFS_TRANSACTION ? "TRANS" : | |
133 | (op_head->oh_clientid == XFS_LOG ? "LOG" : "ERROR"))); | |
134 | printf("flags: "); | |
135 | if (op_head->oh_flags) { | |
136 | if (op_head->oh_flags & XLOG_START_TRANS) | |
137 | printf("START "); | |
138 | if (op_head->oh_flags & XLOG_COMMIT_TRANS) | |
139 | printf("COMMIT "); | |
140 | if (op_head->oh_flags & XLOG_WAS_CONT_TRANS) | |
141 | printf("WAS_CONT "); | |
142 | if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) | |
143 | printf("UNMOUNT "); | |
144 | if (op_head->oh_flags & XLOG_CONTINUE_TRANS) | |
145 | printf("CONTINUE "); | |
146 | if (op_head->oh_flags & XLOG_END_TRANS) | |
147 | printf("END "); | |
148 | } else { | |
149 | printf("none"); | |
150 | } | |
151 | printf("\n"); | |
152 | } /* xlog_print_op_header */ | |
153 | ||
154 | ||
155 | void | |
156 | xlog_print_add_to_trans(xlog_tid_t tid, | |
157 | int skip) | |
158 | { | |
159 | xlog_split_item_t *item; | |
160 | ||
161 | item = (xlog_split_item_t *)calloc(sizeof(xlog_split_item_t), 1); | |
162 | item->si_tid = tid; | |
163 | item->si_skip = skip; | |
164 | item->si_next = split_list; | |
165 | item->si_prev = 0; | |
166 | if (split_list) | |
167 | split_list->si_prev = item; | |
168 | split_list = item; | |
169 | } /* xlog_print_add_to_trans */ | |
170 | ||
171 | ||
172 | int | |
173 | xlog_print_find_tid(xlog_tid_t tid, uint was_cont) | |
174 | { | |
175 | xlog_split_item_t *listp = split_list; | |
176 | ||
177 | if (!split_list) { | |
178 | if (was_cont != 0) /* Not first time we have used this tid */ | |
179 | return 1; | |
180 | else | |
181 | return 0; | |
182 | } | |
183 | while (listp) { | |
184 | if (listp->si_tid == tid) | |
185 | break; | |
186 | listp = listp->si_next; | |
187 | } | |
188 | if (!listp) { | |
189 | return 0; | |
190 | } | |
191 | if (--listp->si_skip == 0) { | |
192 | if (listp == split_list) { /* delete at head */ | |
193 | split_list = listp->si_next; | |
194 | if (split_list) | |
195 | split_list->si_prev = NULL; | |
196 | } else { | |
197 | if (listp->si_next) | |
198 | listp->si_next->si_prev = listp->si_prev; | |
199 | listp->si_prev->si_next = listp->si_next; | |
200 | } | |
201 | free(listp); | |
202 | } | |
203 | return 1; | |
204 | } /* xlog_print_find_tid */ | |
205 | ||
206 | int | |
207 | xlog_print_trans_header(xfs_caddr_t *ptr, int len) | |
208 | { | |
209 | xfs_trans_header_t *h; | |
210 | xfs_caddr_t cptr = *ptr; | |
211 | __uint32_t magic; | |
212 | char *magic_c = (char *)&magic; | |
213 | ||
214 | *ptr += len; | |
dfc130f3 | 215 | |
2bd0ea18 | 216 | magic=*(__uint32_t*)cptr; /* XXX INT_GET soon */ |
dfc130f3 | 217 | |
150a512d | 218 | if (len >= 4) { |
2bd0ea18 | 219 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
dfc130f3 RC |
220 | printf("%c%c%c%c:", |
221 | magic_c[3], magic_c[2], magic_c[1], magic_c[0]); | |
2bd0ea18 | 222 | #else |
dfc130f3 RC |
223 | printf("%c%c%c%c:", |
224 | magic_c[0], magic_c[1], magic_c[2], magic_c[3]); | |
2bd0ea18 | 225 | #endif |
150a512d | 226 | } |
2bd0ea18 NS |
227 | if (len != sizeof(xfs_trans_header_t)) { |
228 | printf(" Not enough data to decode further\n"); | |
229 | return 1; | |
230 | } | |
231 | h = (xfs_trans_header_t *)cptr; | |
232 | printf(" type: %s tid: %x num_items: %d\n", | |
233 | trans_type[h->th_type], h->th_tid, h->th_num_items); | |
234 | return 0; | |
235 | } /* xlog_print_trans_header */ | |
236 | ||
237 | ||
238 | int | |
239 | xlog_print_trans_buffer(xfs_caddr_t *ptr, int len, int *i, int num_ops) | |
240 | { | |
241 | xfs_buf_log_format_t *f; | |
242 | xfs_buf_log_format_v1_t *old_f; | |
243 | xfs_agi_t *agi; | |
244 | xfs_agf_t *agf; | |
245 | xfs_disk_dquot_t *dq; | |
246 | xlog_op_header_t *head = 0; | |
247 | int num, skip; | |
248 | int super_block = 0; | |
249 | int bucket, col, buckets; | |
250 | __int64_t blkno; | |
251 | xfs_buf_log_format_t lbuf; | |
252 | int size, blen, map_size, struct_size; | |
253 | long long x, y; | |
dfc130f3 | 254 | |
2bd0ea18 NS |
255 | /* |
256 | * bcopy to ensure 8-byte alignment for the long longs in | |
257 | * buf_log_format_t structure | |
258 | */ | |
c3cf3190 | 259 | bcopy(*ptr, &lbuf, MIN(sizeof(xfs_buf_log_format_t), len)); |
2bd0ea18 NS |
260 | f = &lbuf; |
261 | *ptr += len; | |
262 | ||
263 | if (f->blf_type == XFS_LI_BUF) { | |
264 | blkno = f->blf_blkno; | |
265 | size = f->blf_size; | |
266 | blen = f->blf_len; | |
267 | map_size = f->blf_map_size; | |
268 | struct_size = sizeof(xfs_buf_log_format_t); | |
269 | } else { | |
270 | old_f = (xfs_buf_log_format_v1_t*)f; | |
271 | blkno = old_f->blf_blkno; | |
272 | size = old_f->blf_size; | |
273 | blen = old_f->blf_len; | |
274 | map_size = old_f->blf_map_size; | |
275 | struct_size = sizeof(xfs_buf_log_format_v1_t); | |
276 | } | |
277 | switch (f->blf_type) { | |
278 | case XFS_LI_BUF: | |
279 | printf("BUF: "); | |
280 | break; | |
281 | case XFS_LI_6_1_BUF: | |
282 | printf("6.1 BUF: "); | |
283 | break; | |
284 | case XFS_LI_5_3_BUF: | |
285 | printf("5.3 BUF: "); | |
286 | break; | |
2bd0ea18 NS |
287 | default: |
288 | printf("UNKNOWN BUF: "); | |
289 | break; | |
290 | } | |
291 | if (len >= struct_size) { | |
292 | ASSERT((len - sizeof(struct_size)) % sizeof(int) == 0); | |
293 | printf("#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d\n", | |
5b64e00a | 294 | size, (long long)blkno, (unsigned long long)blkno, blen, map_size); |
2bd0ea18 NS |
295 | if (blkno == 0) |
296 | super_block = 1; | |
297 | } else { | |
298 | ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ | |
299 | printf("#regs: %d Not printing rest of data\n", f->blf_size); | |
300 | return size; | |
301 | } | |
302 | num = size-1; | |
303 | ||
304 | /* Check if all regions in this log item were in the given LR ptr */ | |
305 | if (*i+num > num_ops-1) { | |
306 | skip = num - (num_ops-1-*i); | |
307 | num = num_ops-1-*i; | |
308 | } else { | |
309 | skip = 0; | |
310 | } | |
311 | while (num-- > 0) { | |
312 | (*i)++; | |
313 | head = (xlog_op_header_t *)*ptr; | |
314 | xlog_print_op_header(head, *i, ptr); | |
315 | if (super_block) { | |
316 | printf("SUPER BLOCK Buffer: "); | |
317 | if (INT_GET(head->oh_len, ARCH_CONVERT) < 4*8) { | |
318 | printf("Out of space\n"); | |
319 | } else { | |
320 | printf("\n"); | |
321 | /* | |
322 | * bcopy because *ptr may not be 8-byte aligned | |
323 | */ | |
324 | bcopy(*ptr, &x, sizeof(long long)); | |
325 | bcopy(*ptr+8, &y, sizeof(long long)); | |
dfc130f3 RC |
326 | printf("icount: %lld ifree: %lld ", |
327 | INT_GET(x, ARCH_CONVERT), | |
328 | INT_GET(y, ARCH_CONVERT)); | |
2bd0ea18 NS |
329 | bcopy(*ptr+16, &x, sizeof(long long)); |
330 | bcopy(*ptr+24, &y, sizeof(long long)); | |
dfc130f3 RC |
331 | printf("fdblks: %lld frext: %lld\n", |
332 | INT_GET(x, ARCH_CONVERT), | |
333 | INT_GET(y, ARCH_CONVERT)); | |
2bd0ea18 NS |
334 | } |
335 | super_block = 0; | |
336 | } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGI_MAGIC) { | |
337 | agi = (xfs_agi_t *)(*ptr); | |
338 | printf("AGI Buffer: XAGI "); | |
339 | if (INT_GET(head->oh_len, ARCH_CONVERT) < | |
340 | sizeof(xfs_agi_t) - | |
341 | XFS_AGI_UNLINKED_BUCKETS*sizeof(xfs_agino_t)) { | |
342 | printf("out of space\n"); | |
343 | } else { | |
344 | printf("\n"); | |
345 | printf("ver: %d ", | |
346 | INT_GET(agi->agi_versionnum, ARCH_CONVERT)); | |
347 | printf("seq#: %d len: %d cnt: %d root: %d\n", | |
348 | INT_GET(agi->agi_seqno, ARCH_CONVERT), | |
349 | INT_GET(agi->agi_length, ARCH_CONVERT), | |
350 | INT_GET(agi->agi_count, ARCH_CONVERT), | |
351 | INT_GET(agi->agi_root, ARCH_CONVERT)); | |
352 | printf("level: %d free#: 0x%x newino: 0x%x\n", | |
353 | INT_GET(agi->agi_level, ARCH_CONVERT), | |
354 | INT_GET(agi->agi_freecount, ARCH_CONVERT), | |
355 | INT_GET(agi->agi_newino, ARCH_CONVERT)); | |
356 | if (INT_GET(head->oh_len, ARCH_CONVERT) == 128) { | |
357 | buckets = 17; | |
358 | } else if (INT_GET(head->oh_len, ARCH_CONVERT) == 256) { | |
359 | buckets = 32 + 17; | |
360 | } else { | |
c3cf3190 NS |
361 | if (head->oh_flags & XLOG_CONTINUE_TRANS) { |
362 | printf("AGI unlinked data skipped "); | |
363 | printf("(CONTINUE set, no space)\n"); | |
364 | continue; | |
365 | } | |
2bd0ea18 NS |
366 | buckets = XFS_AGI_UNLINKED_BUCKETS; |
367 | } | |
368 | for (bucket = 0; bucket < buckets;) { | |
369 | printf("bucket[%d - %d]: ", bucket, bucket+3); | |
370 | for (col = 0; col < 4; col++, bucket++) { | |
371 | if (bucket < buckets) { | |
372 | printf("0x%x ", | |
373 | INT_GET(agi->agi_unlinked[bucket], ARCH_CONVERT)); | |
374 | } | |
375 | } | |
376 | printf("\n"); | |
377 | } | |
378 | } | |
379 | } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGF_MAGIC) { | |
380 | agf = (xfs_agf_t *)(*ptr); | |
381 | printf("AGF Buffer: XAGF "); | |
382 | if (INT_GET(head->oh_len, ARCH_CONVERT) < sizeof(xfs_agf_t)) { | |
383 | printf("Out of space\n"); | |
384 | } else { | |
385 | printf("\n"); | |
386 | printf("ver: %d seq#: %d len: %d \n", | |
387 | INT_GET(agf->agf_versionnum, ARCH_CONVERT), | |
388 | INT_GET(agf->agf_seqno, ARCH_CONVERT), | |
389 | INT_GET(agf->agf_length, ARCH_CONVERT)); | |
390 | printf("root BNO: %d CNT: %d\n", | |
391 | INT_GET(agf->agf_roots[XFS_BTNUM_BNOi], | |
392 | ARCH_CONVERT), | |
393 | INT_GET(agf->agf_roots[XFS_BTNUM_CNTi], | |
394 | ARCH_CONVERT)); | |
395 | printf("level BNO: %d CNT: %d\n", | |
396 | INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], | |
397 | ARCH_CONVERT), | |
398 | INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], | |
399 | ARCH_CONVERT)); | |
400 | printf("1st: %d last: %d cnt: %d " | |
401 | "freeblks: %d longest: %d\n", | |
402 | INT_GET(agf->agf_flfirst, ARCH_CONVERT), | |
403 | INT_GET(agf->agf_fllast, ARCH_CONVERT), | |
404 | INT_GET(agf->agf_flcount, ARCH_CONVERT), | |
405 | INT_GET(agf->agf_freeblks, ARCH_CONVERT), | |
406 | INT_GET(agf->agf_longest, ARCH_CONVERT)); | |
407 | } | |
408 | } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_DQUOT_MAGIC) { | |
409 | dq = (xfs_disk_dquot_t *)(*ptr); | |
410 | printf("DQUOT Buffer: DQ "); | |
411 | if (INT_GET(head->oh_len, ARCH_CONVERT) < | |
412 | sizeof(xfs_disk_dquot_t)) { | |
413 | printf("Out of space\n"); | |
414 | } | |
415 | else { | |
416 | printf("\n"); | |
417 | printf("ver: %d flags: 0x%x id: %d \n", | |
418 | INT_GET(dq->d_version, ARCH_CONVERT), | |
419 | INT_GET(dq->d_flags, ARCH_CONVERT), | |
420 | INT_GET(dq->d_id, ARCH_CONVERT)); | |
421 | printf("blk limits hard: %llu soft: %llu\n", | |
5b64e00a | 422 | (unsigned long long) |
2bd0ea18 | 423 | INT_GET(dq->d_blk_hardlimit, ARCH_CONVERT), |
5b64e00a | 424 | (unsigned long long) |
2bd0ea18 NS |
425 | INT_GET(dq->d_blk_softlimit, ARCH_CONVERT)); |
426 | printf("blk count: %llu warns: %d timer: %d\n", | |
5b64e00a | 427 | (unsigned long long) |
2bd0ea18 NS |
428 | INT_GET(dq->d_bcount, ARCH_CONVERT), |
429 | INT_GET(dq->d_bwarns, ARCH_CONVERT), | |
430 | INT_GET(dq->d_btimer, ARCH_CONVERT)); | |
431 | printf("ino limits hard: %llu soft: %llu\n", | |
5b64e00a | 432 | (unsigned long long) |
2bd0ea18 | 433 | INT_GET(dq->d_ino_hardlimit, ARCH_CONVERT), |
5b64e00a | 434 | (unsigned long long) |
2bd0ea18 NS |
435 | INT_GET(dq->d_ino_softlimit, ARCH_CONVERT)); |
436 | printf("ino count: %llu warns: %d timer: %d\n", | |
5b64e00a | 437 | (unsigned long long) |
2bd0ea18 NS |
438 | INT_GET(dq->d_icount, ARCH_CONVERT), |
439 | INT_GET(dq->d_iwarns, ARCH_CONVERT), | |
440 | INT_GET(dq->d_itimer, ARCH_CONVERT)); | |
441 | } | |
442 | } else { | |
443 | printf("BUF DATA\n"); | |
444 | if (print_data) { | |
445 | uint *dp = (uint *)*ptr; | |
446 | int nums = INT_GET(head->oh_len, ARCH_CONVERT) >> 2; | |
447 | int i = 0; | |
448 | ||
449 | while (i < nums) { | |
450 | if ((i % 8) == 0) | |
451 | printf("%2x ", i); | |
452 | printf("%8x ", *dp); | |
453 | dp++; | |
454 | i++; | |
455 | if ((i % 8) == 0) | |
456 | printf("\n"); | |
457 | } | |
458 | printf("\n"); | |
459 | } | |
460 | } | |
461 | *ptr += INT_GET(head->oh_len, ARCH_CONVERT); | |
462 | } | |
463 | if (head && head->oh_flags & XLOG_CONTINUE_TRANS) | |
464 | skip++; | |
465 | return skip; | |
466 | } /* xlog_print_trans_buffer */ | |
467 | ||
468 | ||
469 | int | |
470 | xlog_print_trans_efd(xfs_caddr_t *ptr, uint len) | |
471 | { | |
472 | xfs_efd_log_format_t *f; | |
473 | xfs_extent_t *ex; | |
474 | int i; | |
475 | xfs_efd_log_format_t lbuf; | |
dfc130f3 | 476 | |
2bd0ea18 NS |
477 | /* |
478 | * bcopy to ensure 8-byte alignment for the long longs in | |
479 | * xfs_efd_log_format_t structure | |
480 | */ | |
f63b46a2 | 481 | bcopy(*ptr, &lbuf, len); |
2bd0ea18 NS |
482 | f = &lbuf; |
483 | *ptr += len; | |
484 | if (len >= sizeof(xfs_efd_log_format_t)) { | |
485 | printf("EFD: #regs: %d num_extents: %d id: 0x%llx\n", | |
5b64e00a | 486 | f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id); |
2bd0ea18 | 487 | ex = f->efd_extents; |
f63b46a2 NS |
488 | len -= (sizeof(xfs_efd_log_format_t) - sizeof(xfs_extent_t)); |
489 | for (i = 0; len > 0 && i < f->efd_nextents; i++) { | |
5b64e00a NS |
490 | printf("(s: 0x%llx, l: %d) ", |
491 | (unsigned long long)ex->ext_start, ex->ext_len); | |
2bd0ea18 | 492 | if (i % 4 == 3) printf("\n"); |
f63b46a2 | 493 | len -= sizeof(xfs_extent_t); |
2bd0ea18 NS |
494 | ex++; |
495 | } | |
496 | if (i % 4 != 0) printf("\n"); | |
497 | return 0; | |
498 | } else { | |
499 | printf("EFD: Not enough data to decode further\n"); | |
500 | return 1; | |
501 | } | |
502 | } /* xlog_print_trans_efd */ | |
503 | ||
504 | ||
505 | int | |
506 | xlog_print_trans_efi(xfs_caddr_t *ptr, uint len) | |
507 | { | |
508 | xfs_efi_log_format_t *f; | |
509 | xfs_extent_t *ex; | |
510 | int i; | |
511 | xfs_efi_log_format_t lbuf; | |
512 | ||
513 | /* | |
514 | * bcopy to ensure 8-byte alignment for the long longs in | |
515 | * xfs_efi_log_format_t structure | |
516 | */ | |
f63b46a2 | 517 | bcopy(*ptr, &lbuf, len); |
2bd0ea18 NS |
518 | f = &lbuf; |
519 | *ptr += len; | |
520 | if (len >= sizeof(xfs_efi_log_format_t)) { | |
521 | printf("EFI: #regs: %d num_extents: %d id: 0x%llx\n", | |
5b64e00a | 522 | f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id); |
2bd0ea18 | 523 | ex = f->efi_extents; |
f63b46a2 NS |
524 | len -= (sizeof(xfs_efi_log_format_t) - sizeof(xfs_extent_t)); |
525 | for (i=0; len > 0 && i < f->efi_nextents; i++) { | |
5b64e00a NS |
526 | printf("(s: 0x%llx, l: %d) ", |
527 | (unsigned long long)ex->ext_start, ex->ext_len); | |
2bd0ea18 | 528 | if (i % 4 == 3) printf("\n"); |
f63b46a2 | 529 | len -= sizeof(xfs_extent_t); |
2bd0ea18 NS |
530 | ex++; |
531 | } | |
532 | if (i % 4 != 0) printf("\n"); | |
533 | return 0; | |
534 | } else { | |
535 | printf("EFI: Not enough data to decode further\n"); | |
536 | return 1; | |
537 | } | |
538 | } /* xlog_print_trans_efi */ | |
539 | ||
540 | ||
c3cf3190 NS |
541 | int |
542 | xlog_print_trans_qoff(xfs_caddr_t *ptr, uint len) | |
543 | { | |
544 | xfs_qoff_logformat_t *f; | |
545 | xfs_qoff_logformat_t lbuf; | |
546 | ||
f63b46a2 | 547 | bcopy(*ptr, &lbuf, MIN(sizeof(xfs_qoff_logformat_t), len)); |
c3cf3190 NS |
548 | f = &lbuf; |
549 | *ptr += len; | |
550 | if (len >= sizeof(xfs_qoff_logformat_t)) { | |
551 | printf("QOFF: #regs: %d flags: 0x%x\n", f->qf_size, f->qf_flags); | |
552 | return 0; | |
553 | } else { | |
554 | printf("QOFF: Not enough data to decode further\n"); | |
555 | return 1; | |
556 | } | |
557 | } /* xlog_print_trans_qoff */ | |
558 | ||
559 | ||
2bd0ea18 NS |
560 | void |
561 | xlog_print_trans_inode_core(xfs_dinode_core_t *ip) | |
562 | { | |
563 | printf("INODE CORE\n"); | |
564 | printf("magic 0x%hx mode 0%ho version %d format %d\n", | |
565 | ip->di_magic, ip->di_mode, (int)ip->di_version, | |
566 | (int)ip->di_format); | |
567 | printf("nlink %hd uid %d gid %d\n", | |
568 | ip->di_nlink, ip->di_uid, ip->di_gid); | |
569 | printf("atime 0x%x mtime 0x%x ctime 0x%x\n", | |
570 | ip->di_atime.t_sec, ip->di_mtime.t_sec, ip->di_ctime.t_sec); | |
571 | printf("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n", | |
5b64e00a NS |
572 | (unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks, |
573 | ip->di_extsize, ip->di_nextents); | |
2bd0ea18 NS |
574 | printf("naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n", |
575 | ip->di_anextents, (int)ip->di_forkoff, ip->di_dmevmask, | |
576 | ip->di_dmstate); | |
577 | printf("flags 0x%x gen 0x%x\n", | |
578 | ip->di_flags, ip->di_gen); | |
579 | } | |
580 | ||
581 | void | |
582 | xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size) | |
583 | { | |
584 | xfs_ino_t ino; | |
585 | int count; | |
586 | int i; | |
587 | char namebuf[257]; | |
588 | xfs_dir_sf_entry_t *sfep; | |
589 | ||
dfc130f3 RC |
590 | /* XXX need to determine whether this is v1 or v2, then |
591 | print appropriate structure */ | |
592 | ||
2bd0ea18 | 593 | printf("SHORTFORM DIRECTORY size %d\n", |
dfc130f3 RC |
594 | size); |
595 | /* bail out for now */ | |
596 | ||
597 | return; | |
598 | ||
2bd0ea18 NS |
599 | printf("SHORTFORM DIRECTORY size %d count %d\n", |
600 | size, sfp->hdr.count); | |
601 | bcopy(&(sfp->hdr.parent), &ino, sizeof(ino)); | |
5b64e00a | 602 | printf(".. ino 0x%llx\n", (unsigned long long)INT_GET(ino, ARCH_CONVERT)); |
2bd0ea18 NS |
603 | |
604 | count = (uint)(sfp->hdr.count); | |
605 | sfep = &(sfp->list[0]); | |
606 | for (i = 0; i < count; i++) { | |
607 | bcopy(&(sfep->inumber), &ino, sizeof(ino)); | |
608 | bcopy((sfep->name), namebuf, sfep->namelen); | |
609 | namebuf[sfep->namelen] = '\0'; | |
610 | printf("%s ino 0x%llx namelen %d\n", | |
5b64e00a | 611 | namebuf, (unsigned long long)ino, sfep->namelen); |
2bd0ea18 NS |
612 | sfep = XFS_DIR_SF_NEXTENTRY(sfep); |
613 | } | |
614 | } | |
615 | ||
616 | int | |
617 | xlog_print_trans_inode(xfs_caddr_t *ptr, int len, int *i, int num_ops) | |
618 | { | |
619 | xfs_inode_log_format_t *f; | |
620 | xfs_inode_log_format_t_v1 *old_f; | |
621 | xfs_dinode_core_t dino; | |
622 | xlog_op_header_t *op_head; | |
623 | int version; | |
624 | xfs_inode_log_format_t lbuf = {0}; | |
625 | int mode; | |
626 | int size; | |
627 | ||
628 | /* | |
629 | * print inode type header region | |
630 | * | |
631 | * bcopy to ensure 8-byte alignment for the long longs in | |
632 | * xfs_inode_log_format_t structure | |
633 | * | |
634 | * len can be smaller than xfs_inode_log_format_t sometimes... (?) | |
635 | */ | |
636 | bcopy(*ptr, &lbuf, MIN(sizeof(xfs_inode_log_format_t), len)); | |
637 | version = lbuf.ilf_type; | |
638 | f = &lbuf; | |
639 | (*i)++; /* bump index */ | |
640 | *ptr += len; | |
641 | if (version == XFS_LI_5_3_INODE) { | |
642 | old_f = (xfs_inode_log_format_t_v1 *)f; | |
643 | if (len == sizeof(xfs_inode_log_format_t_v1)) { | |
644 | printf("5.3 INODE: #regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n", | |
5b64e00a | 645 | old_f->ilf_size, (unsigned long long)old_f->ilf_ino, |
2bd0ea18 NS |
646 | old_f->ilf_fields, old_f->ilf_dsize); |
647 | } else { | |
648 | ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ | |
649 | printf("5.3 INODE: #regs: %d Not printing rest of data\n", | |
650 | old_f->ilf_size); | |
651 | return old_f->ilf_size; | |
652 | } | |
653 | } else { | |
654 | if (len == sizeof(xfs_inode_log_format_t)) { | |
655 | if (version == XFS_LI_6_1_INODE) | |
656 | printf("6.1 INODE: "); | |
657 | else printf("INODE: "); | |
658 | printf("#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n", | |
5b64e00a NS |
659 | f->ilf_size, (unsigned long long)f->ilf_ino, |
660 | f->ilf_fields, f->ilf_dsize); | |
2bd0ea18 | 661 | printf(" blkno: %lld len: %d boff: %d\n", |
5b64e00a | 662 | (long long)f->ilf_blkno, f->ilf_len, f->ilf_boffset); |
2bd0ea18 NS |
663 | } else { |
664 | ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ | |
665 | printf("INODE: #regs: %d Not printing rest of data\n", | |
666 | f->ilf_size); | |
667 | return f->ilf_size; | |
668 | } | |
669 | } | |
670 | ||
671 | if (*i >= num_ops) /* end of LR */ | |
672 | return f->ilf_size-1; | |
673 | ||
674 | /* core inode comes 2nd */ | |
675 | op_head = (xlog_op_header_t *)*ptr; | |
676 | xlog_print_op_header(op_head, *i, ptr); | |
dfc130f3 | 677 | |
2bd0ea18 NS |
678 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { |
679 | return f->ilf_size-1; | |
680 | } | |
dfc130f3 | 681 | |
2bd0ea18 | 682 | bcopy(*ptr, &dino, sizeof(dino)); |
322f2a29 | 683 | mode = dino.di_mode & S_IFMT; |
2bd0ea18 NS |
684 | size = (int)dino.di_size; |
685 | xlog_print_trans_inode_core(&dino); | |
686 | *ptr += sizeof(xfs_dinode_core_t); | |
687 | ||
688 | if (*i == num_ops-1 && f->ilf_size == 3) { | |
a981f202 | 689 | return 1; |
2bd0ea18 NS |
690 | } |
691 | ||
692 | /* does anything come next */ | |
693 | op_head = (xlog_op_header_t *)*ptr; | |
694 | switch (f->ilf_fields & XFS_ILOG_NONCORE) { | |
695 | case XFS_ILOG_DEXT: { | |
696 | ASSERT(f->ilf_size == 3); | |
697 | (*i)++; | |
698 | xlog_print_op_header(op_head, *i, ptr); | |
699 | printf("EXTENTS inode data\n"); | |
700 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
701 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { | |
702 | return 1; | |
703 | } | |
704 | break; | |
705 | } | |
706 | case XFS_ILOG_DBROOT: { | |
707 | ASSERT(f->ilf_size == 3); | |
708 | (*i)++; | |
709 | xlog_print_op_header(op_head, *i, ptr); | |
710 | printf("BTREE inode data\n"); | |
711 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
712 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { | |
713 | return 1; | |
714 | } | |
715 | break; | |
716 | } | |
717 | case XFS_ILOG_DDATA: { | |
718 | ASSERT(f->ilf_size == 3); | |
719 | (*i)++; | |
720 | xlog_print_op_header(op_head, *i, ptr); | |
721 | printf("LOCAL inode data\n"); | |
322f2a29 | 722 | if (mode == S_IFDIR) { |
2bd0ea18 NS |
723 | xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size); |
724 | } | |
725 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
a981f202 NS |
726 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { |
727 | return 1; | |
728 | } | |
729 | break; | |
730 | } | |
731 | case XFS_ILOG_AEXT: { | |
732 | ASSERT(f->ilf_size == 3); | |
733 | (*i)++; | |
734 | xlog_print_op_header(op_head, *i, ptr); | |
735 | printf("EXTENTS inode attr\n"); | |
736 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
737 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { | |
738 | return 1; | |
739 | } | |
740 | break; | |
741 | } | |
742 | case XFS_ILOG_ABROOT: { | |
743 | ASSERT(f->ilf_size == 3); | |
744 | (*i)++; | |
745 | xlog_print_op_header(op_head, *i, ptr); | |
746 | printf("BTREE inode attr\n"); | |
747 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
748 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { | |
749 | return 1; | |
750 | } | |
751 | break; | |
752 | } | |
753 | case XFS_ILOG_ADATA: { | |
754 | ASSERT(f->ilf_size == 3); | |
755 | (*i)++; | |
756 | xlog_print_op_header(op_head, *i, ptr); | |
757 | printf("LOCAL inode attr\n"); | |
322f2a29 | 758 | if (mode == S_IFDIR) { |
a981f202 NS |
759 | xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size); |
760 | } | |
761 | *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
762 | if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { | |
2bd0ea18 | 763 | return 1; |
a981f202 | 764 | } |
2bd0ea18 NS |
765 | break; |
766 | } | |
767 | case XFS_ILOG_DEV: { | |
768 | ASSERT(f->ilf_size == 2); | |
769 | printf("DEV inode: no extra region\n"); | |
770 | break; | |
771 | } | |
772 | case XFS_ILOG_UUID: { | |
773 | ASSERT(f->ilf_size == 2); | |
774 | printf("UUID inode: no extra region\n"); | |
775 | break; | |
776 | } | |
777 | case 0: { | |
778 | ASSERT(f->ilf_size == 2); | |
779 | break; | |
780 | } | |
781 | default: { | |
782 | xlog_panic("xlog_print_trans_inode: illegal inode type"); | |
783 | } | |
784 | } | |
785 | return 0; | |
786 | } /* xlog_print_trans_inode */ | |
787 | ||
788 | ||
c3cf3190 NS |
789 | int |
790 | xlog_print_trans_dquot(xfs_caddr_t *ptr, int len, int *i, int num_ops) | |
791 | { | |
792 | xfs_dq_logformat_t *f; | |
793 | xfs_dq_logformat_t lbuf = {0}; | |
794 | xfs_disk_dquot_t ddq; | |
878c1b90 | 795 | xlog_op_header_t *head = NULL; |
c3cf3190 NS |
796 | int num, skip; |
797 | ||
798 | /* | |
799 | * print dquot header region | |
800 | * | |
801 | * bcopy to ensure 8-byte alignment for the long longs in | |
802 | * xfs_dq_logformat_t structure | |
803 | */ | |
804 | bcopy(*ptr, &lbuf, MIN(sizeof(xfs_dq_logformat_t), len)); | |
805 | f = &lbuf; | |
806 | (*i)++; /* bump index */ | |
807 | *ptr += len; | |
dfc130f3 | 808 | |
c3cf3190 NS |
809 | if (len == sizeof(xfs_dq_logformat_t)) { |
810 | printf("#regs: %d id: 0x%x", f->qlf_size, f->qlf_id); | |
811 | printf(" blkno: %lld len: %d boff: %d\n", | |
812 | (long long)f->qlf_blkno, f->qlf_len, f->qlf_boffset); | |
813 | } else { | |
814 | ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ | |
815 | printf("DQUOT: #regs: %d Not printing rest of data\n", | |
816 | f->qlf_size); | |
817 | return f->qlf_size; | |
818 | } | |
819 | num = f->qlf_size-1; | |
820 | ||
821 | /* Check if all regions in this log item were in the given LR ptr */ | |
822 | if (*i+num > num_ops-1) { | |
823 | skip = num - (num_ops-1-*i); | |
824 | num = num_ops-1-*i; | |
825 | } else { | |
826 | skip = 0; | |
827 | } | |
828 | ||
829 | while (num-- > 0) { | |
830 | head = (xlog_op_header_t *)*ptr; | |
831 | xlog_print_op_header(head, *i, ptr); | |
832 | ASSERT(INT_GET(head->oh_len, ARCH_CONVERT) == sizeof(xfs_disk_dquot_t)); | |
833 | bcopy(*ptr, &ddq, sizeof(xfs_disk_dquot_t)); | |
834 | printf("DQUOT: magic 0x%hx flags 0%ho\n", | |
835 | INT_GET(ddq.d_magic, ARCH_CONVERT), | |
836 | INT_GET(ddq.d_flags, ARCH_CONVERT)); | |
837 | *ptr += INT_GET(head->oh_len, ARCH_CONVERT); | |
838 | } | |
839 | if (head && head->oh_flags & XLOG_CONTINUE_TRANS) | |
840 | skip++; | |
841 | return skip; | |
842 | } /* xlog_print_trans_dquot */ | |
843 | ||
2bd0ea18 NS |
844 | |
845 | /****************************************************************************** | |
846 | * | |
847 | * Log print routines | |
848 | * | |
849 | ****************************************************************************** | |
850 | */ | |
851 | ||
852 | void | |
853 | xlog_print_lseek(xlog_t *log, int fd, xfs_daddr_t blkno, int whence) | |
854 | { | |
855 | #define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) | |
856 | xfs_off_t offset; | |
857 | ||
858 | if (whence == SEEK_SET) | |
859 | offset = BBTOOFF64(blkno+log->l_logBBstart); | |
860 | else | |
861 | offset = BBTOOFF64(blkno); | |
862 | if (lseek64(fd, offset, whence) < 0) { | |
e7134dda NS |
863 | fprintf(stderr, "%s: lseek64 to %lld failed: %s\n", |
864 | progname, (long long)offset, strerror(errno)); | |
2bd0ea18 NS |
865 | exit(1); |
866 | } | |
867 | } /* xlog_print_lseek */ | |
868 | ||
869 | ||
870 | void | |
871 | print_lsn(xfs_caddr_t string, | |
872 | xfs_lsn_t *lsn, | |
dfc130f3 | 873 | xfs_arch_t arch) |
2bd0ea18 | 874 | { |
dfc130f3 | 875 | printf("%s: %u,%u", string, |
46eca962 | 876 | CYCLE_LSN(INT_GET(*lsn, arch)), BLOCK_LSN(INT_GET(*lsn, arch))); |
2bd0ea18 NS |
877 | } |
878 | ||
879 | ||
880 | int | |
dfb5b7da | 881 | xlog_print_record(int fd, |
882 | int num_ops, | |
883 | int len, | |
884 | int *read_type, | |
885 | xfs_caddr_t *partial_buf, | |
886 | xlog_rec_header_t *rhead, | |
887 | xlog_rec_ext_header_t *xhdrs) | |
2bd0ea18 | 888 | { |
2bd0ea18 NS |
889 | xfs_caddr_t buf, ptr; |
890 | int read_len, skip; | |
dfb5b7da | 891 | int ret, n, i, j, k; |
2bd0ea18 NS |
892 | |
893 | if (print_no_print) | |
894 | return NO_ERROR; | |
dfc130f3 | 895 | |
2bd0ea18 | 896 | if (!len) { |
dfc130f3 RC |
897 | printf("\n"); |
898 | return NO_ERROR; | |
2bd0ea18 NS |
899 | } |
900 | ||
901 | /* read_len must read up to some block boundary */ | |
902 | read_len = (int) BBTOB(BTOBB(len)); | |
903 | ||
904 | /* read_type => don't malloc() new buffer, use old one */ | |
905 | if (*read_type == FULL_READ) { | |
906 | if ((ptr = buf = (xfs_caddr_t)malloc(read_len)) == NULL) { | |
dfb5b7da | 907 | fprintf(stderr, "%s: xlog_print_record: malloc failed\n", progname); |
2bd0ea18 NS |
908 | exit(1); |
909 | } | |
910 | } else { | |
911 | read_len -= *read_type; | |
912 | buf = (xfs_caddr_t)((__psint_t)(*partial_buf) + (__psint_t)(*read_type)); | |
913 | ptr = *partial_buf; | |
914 | } | |
915 | if ((ret = (int) read(fd, buf, read_len)) == -1) { | |
dfb5b7da | 916 | fprintf(stderr, "%s: xlog_print_record: read error\n", progname); |
2bd0ea18 NS |
917 | exit(1); |
918 | } | |
919 | /* Did we overflow the end? */ | |
920 | if (*read_type == FULL_READ && | |
46eca962 NS |
921 | BLOCK_LSN(INT_GET(rhead->h_lsn, ARCH_CONVERT)) + BTOBB(read_len) >= |
922 | logBBsize) { | |
923 | *read_type = BBTOB(logBBsize - BLOCK_LSN(INT_GET(rhead->h_lsn, ARCH_CONVERT))-1); | |
2bd0ea18 NS |
924 | *partial_buf = buf; |
925 | return PARTIAL_READ; | |
926 | } | |
dfc130f3 | 927 | |
2bd0ea18 NS |
928 | /* Did we read everything? */ |
929 | if ((ret == 0 && read_len != 0) || ret != read_len) { | |
930 | *read_type = ret; | |
931 | *partial_buf = buf; | |
932 | return PARTIAL_READ; | |
933 | } | |
934 | if (*read_type != FULL_READ) | |
935 | read_len += *read_type; | |
dfc130f3 | 936 | |
dfb5b7da | 937 | /* Everything read in. Start from beginning of buffer |
938 | * Unpack the data, by putting the saved cycle-data back | |
939 | * into the first word of each BB. | |
940 | * Do some checks. | |
46eca962 | 941 | */ |
2bd0ea18 NS |
942 | buf = ptr; |
943 | for (i = 0; ptr < buf + read_len; ptr += BBSIZE, i++) { | |
dfb5b7da | 944 | xlog_rec_header_t *rechead = (xlog_rec_header_t *)ptr; |
945 | ||
946 | /* sanity checks */ | |
2bd0ea18 | 947 | if (INT_GET(rechead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { |
dfb5b7da | 948 | /* data should not have magicno as first word |
949 | * as it should by cycle# | |
950 | */ | |
2bd0ea18 NS |
951 | free(buf); |
952 | return -1; | |
953 | } else { | |
dfb5b7da | 954 | /* verify cycle# |
955 | * FIXME: cycle+1 should be a macro pv#900369 | |
956 | */ | |
2bd0ea18 NS |
957 | if (INT_GET(rhead->h_cycle, ARCH_CONVERT) != |
958 | INT_GET(*(uint *)ptr, ARCH_CONVERT)) { | |
959 | if (*read_type == FULL_READ) | |
960 | return -1; | |
961 | else if (INT_GET(rhead->h_cycle, ARCH_CONVERT) + 1 != | |
962 | INT_GET(*(uint *)ptr, ARCH_CONVERT)) | |
963 | return -1; | |
964 | } | |
965 | } | |
dfb5b7da | 966 | |
967 | /* copy back the data from the header */ | |
968 | if (i < XLOG_HEADER_CYCLE_SIZE / BBSIZE) { | |
969 | /* from 1st header */ | |
970 | INT_SET(*(uint *)ptr, ARCH_CONVERT, | |
971 | INT_GET(rhead->h_cycle_data[i], ARCH_CONVERT)); | |
972 | } | |
973 | else { | |
974 | ASSERT(xhdrs != NULL); | |
975 | /* from extra headers */ | |
976 | j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); | |
977 | k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); | |
978 | INT_SET(*(uint *)ptr, ARCH_CONVERT, | |
979 | INT_GET(xhdrs[j-1].xh_cycle_data[k], ARCH_CONVERT)); | |
980 | } | |
981 | ||
2bd0ea18 | 982 | } |
dfb5b7da | 983 | |
2bd0ea18 NS |
984 | ptr = buf; |
985 | for (i=0; i<num_ops; i++) { | |
dfb5b7da | 986 | xlog_op_header_t *op_head = (xlog_op_header_t *)ptr; |
987 | ||
2bd0ea18 | 988 | print_xlog_op_line(); |
2bd0ea18 NS |
989 | xlog_print_op_header(op_head, i, &ptr); |
990 | ||
991 | /* print transaction data */ | |
992 | if (print_no_data || | |
993 | ((XLOG_SET(op_head->oh_flags, XLOG_WAS_CONT_TRANS) || | |
dfc130f3 | 994 | XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) && |
2bd0ea18 NS |
995 | INT_GET(op_head->oh_len, ARCH_CONVERT) == 0)) { |
996 | for (n = 0; n < INT_GET(op_head->oh_len, ARCH_CONVERT); n++) { | |
997 | printf("%c", *ptr); | |
998 | ptr++; | |
999 | } | |
1000 | printf("\n"); | |
1001 | continue; | |
1002 | } | |
1003 | if (xlog_print_find_tid(INT_GET(op_head->oh_tid, ARCH_CONVERT), | |
1004 | op_head->oh_flags & XLOG_WAS_CONT_TRANS)) { | |
1005 | printf("Left over region from split log item\n"); | |
1006 | ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
1007 | continue; | |
1008 | } | |
1009 | if (INT_GET(op_head->oh_len, ARCH_CONVERT) != 0) { | |
1010 | if (*(uint *)ptr == XFS_TRANS_HEADER_MAGIC) { | |
1011 | skip = xlog_print_trans_header(&ptr, | |
1012 | INT_GET(op_head->oh_len, ARCH_CONVERT)); | |
1013 | } else { | |
1014 | switch (*(unsigned short *)ptr) { | |
1015 | case XFS_LI_5_3_BUF: | |
1016 | case XFS_LI_6_1_BUF: | |
2bd0ea18 NS |
1017 | case XFS_LI_BUF: { |
1018 | skip = xlog_print_trans_buffer(&ptr, | |
1019 | INT_GET(op_head->oh_len, ARCH_CONVERT), | |
1020 | &i, num_ops); | |
1021 | break; | |
1022 | } | |
1023 | case XFS_LI_5_3_INODE: | |
1024 | case XFS_LI_6_1_INODE: | |
1025 | case XFS_LI_INODE: { | |
1026 | skip = xlog_print_trans_inode(&ptr, | |
1027 | INT_GET(op_head->oh_len, ARCH_CONVERT), | |
1028 | &i, num_ops); | |
1029 | break; | |
1030 | } | |
c3cf3190 NS |
1031 | case XFS_LI_DQUOT: { |
1032 | skip = xlog_print_trans_dquot(&ptr, | |
1033 | INT_GET(op_head->oh_len, ARCH_CONVERT), | |
1034 | &i, num_ops); | |
1035 | break; | |
1036 | } | |
2bd0ea18 NS |
1037 | case XFS_LI_EFI: { |
1038 | skip = xlog_print_trans_efi(&ptr, | |
1039 | INT_GET(op_head->oh_len, ARCH_CONVERT)); | |
1040 | break; | |
1041 | } | |
1042 | case XFS_LI_EFD: { | |
1043 | skip = xlog_print_trans_efd(&ptr, | |
1044 | INT_GET(op_head->oh_len, ARCH_CONVERT)); | |
1045 | break; | |
1046 | } | |
c3cf3190 NS |
1047 | case XFS_LI_QUOTAOFF: { |
1048 | skip = xlog_print_trans_qoff(&ptr, | |
1049 | INT_GET(op_head->oh_len, ARCH_CONVERT)); | |
1050 | break; | |
1051 | } | |
2bd0ea18 NS |
1052 | case XLOG_UNMOUNT_TYPE: { |
1053 | printf("Unmount filesystem\n"); | |
1054 | skip = 0; | |
1055 | break; | |
1056 | } | |
1057 | default: { | |
1058 | fprintf(stderr, "%s: unknown log operation type (%x)\n", | |
dfc130f3 | 1059 | progname, *(unsigned short *)ptr); |
2c794e6e NS |
1060 | if (print_exit) { |
1061 | free(buf); | |
1062 | return BAD_HEADER; | |
1063 | } | |
2bd0ea18 NS |
1064 | skip = 0; |
1065 | ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); | |
1066 | } | |
1067 | } /* switch */ | |
1068 | } /* else */ | |
1069 | if (skip != 0) | |
1070 | xlog_print_add_to_trans(INT_GET(op_head->oh_tid, ARCH_CONVERT), skip); | |
1071 | } | |
1072 | } | |
1073 | printf("\n"); | |
1074 | free(buf); | |
1075 | return NO_ERROR; | |
1076 | } /* xlog_print_record */ | |
1077 | ||
1078 | ||
1079 | int | |
1080 | xlog_print_rec_head(xlog_rec_header_t *head, int *len) | |
1081 | { | |
1082 | int i; | |
1083 | char uub[64]; | |
1084 | int datalen,bbs; | |
dfc130f3 | 1085 | |
2bd0ea18 NS |
1086 | if (print_no_print) |
1087 | return INT_GET(head->h_num_logops, ARCH_CONVERT); | |
dfc130f3 | 1088 | |
46eca962 | 1089 | if (!head->h_magicno) |
dfc130f3 | 1090 | return ZEROED_LOG; |
2bd0ea18 NS |
1091 | |
1092 | if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) { | |
dfc130f3 RC |
1093 | printf("Header 0x%x wanted 0x%x\n", |
1094 | INT_GET(head->h_magicno, ARCH_CONVERT), | |
1095 | XLOG_HEADER_MAGIC_NUM); | |
2bd0ea18 NS |
1096 | return BAD_HEADER; |
1097 | } | |
dfc130f3 | 1098 | |
dfb5b7da | 1099 | /* check for cleared blocks written by xlog_clear_stale_blocks() */ |
46eca962 NS |
1100 | if (!head->h_len && !head->h_chksum && !head->h_prev_block && |
1101 | !head->h_num_logops && !head->h_size) | |
dfb5b7da | 1102 | return CLEARED_BLKS; |
1103 | ||
2bd0ea18 | 1104 | datalen=INT_GET(head->h_len, ARCH_CONVERT); |
dfb5b7da | 1105 | bbs=BTOBB(datalen); |
dfc130f3 RC |
1106 | |
1107 | printf("cycle: %d version: %d ", | |
1108 | INT_GET(head->h_cycle, ARCH_CONVERT), | |
1109 | INT_GET(head->h_version, ARCH_CONVERT)); | |
2bd0ea18 NS |
1110 | print_lsn(" lsn", &head->h_lsn, ARCH_CONVERT); |
1111 | print_lsn(" tail_lsn", &head->h_tail_lsn, ARCH_CONVERT); | |
1112 | printf("\n"); | |
1113 | printf("length of Log Record: %d prev offset: %d num ops: %d\n", | |
dfc130f3 RC |
1114 | datalen, |
1115 | INT_GET(head->h_prev_block, ARCH_CONVERT), | |
1116 | INT_GET(head->h_num_logops, ARCH_CONVERT)); | |
1117 | ||
2bd0ea18 | 1118 | if (print_overwrite) { |
dfc130f3 | 1119 | printf("cycle num overwrites: "); |
dfb5b7da | 1120 | for (i=0; i< MIN(bbs, XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) |
2bd0ea18 | 1121 | printf("%d - 0x%x ", |
dfc130f3 RC |
1122 | i, |
1123 | INT_GET(head->h_cycle_data[i], ARCH_CONVERT)); | |
1124 | printf("\n"); | |
2bd0ea18 | 1125 | } |
dfc130f3 | 1126 | |
2bd0ea18 NS |
1127 | uuid_unparse(head->h_fs_uuid, uub); |
1128 | printf("uuid: %s format: ", uub); | |
1129 | switch (INT_GET(head->h_fmt, ARCH_CONVERT)) { | |
dfc130f3 RC |
1130 | case XLOG_FMT_UNKNOWN: |
1131 | printf("unknown\n"); | |
1132 | break; | |
1133 | case XLOG_FMT_LINUX_LE: | |
1134 | printf("little endian linux\n"); | |
1135 | break; | |
1136 | case XLOG_FMT_LINUX_BE: | |
1137 | printf("big endian linux\n"); | |
1138 | break; | |
1139 | case XLOG_FMT_IRIX_BE: | |
1140 | printf("big endian irix\n"); | |
1141 | break; | |
1142 | default: | |
1143 | printf("? (%d)\n", INT_GET(head->h_fmt, ARCH_CONVERT)); | |
1144 | break; | |
2bd0ea18 | 1145 | } |
dfb5b7da | 1146 | printf("h_size: %d\n", INT_GET(head->h_size, ARCH_CONVERT)); |
1147 | ||
2bd0ea18 NS |
1148 | *len = INT_GET(head->h_len, ARCH_CONVERT); |
1149 | return(INT_GET(head->h_num_logops, ARCH_CONVERT)); | |
1150 | } /* xlog_print_rec_head */ | |
1151 | ||
dfb5b7da | 1152 | void |
1153 | xlog_print_rec_xhead(xlog_rec_ext_header_t *head, int coverage) | |
1154 | { | |
1155 | int i; | |
1156 | ||
1157 | print_xlog_xhdr_line(); | |
1158 | printf("extended-header: cycle: %d\n", INT_GET(head->xh_cycle, ARCH_CONVERT)); | |
1159 | ||
1160 | if (print_overwrite) { | |
1161 | printf("cycle num overwrites: "); | |
1162 | for (i = 0; i < coverage; i++) | |
1163 | printf("%d - 0x%x ", | |
1164 | i, | |
1165 | INT_GET(head->xh_cycle_data[i], ARCH_CONVERT)); | |
1166 | printf("\n"); | |
1167 | } | |
1168 | } /* xlog_print_rec_xhead */ | |
1169 | ||
2bd0ea18 NS |
1170 | static void |
1171 | print_xlog_bad_zeroed(xfs_daddr_t blkno) | |
1172 | { | |
dfc130f3 | 1173 | print_stars(); |
2bd0ea18 | 1174 | printf("* ERROR: found data after zeroed blocks block=%-21lld *\n", |
dfc130f3 RC |
1175 | (long long)blkno); |
1176 | print_stars(); | |
2bd0ea18 NS |
1177 | if (print_exit) |
1178 | xlog_exit("Bad log - data after zeroed blocks"); | |
1179 | } /* print_xlog_bad_zeroed */ | |
1180 | ||
1181 | static void | |
1182 | print_xlog_bad_header(xfs_daddr_t blkno, xfs_caddr_t buf) | |
1183 | { | |
dfc130f3 | 1184 | print_stars(); |
2bd0ea18 | 1185 | printf("* ERROR: header cycle=%-11d block=%-21lld *\n", |
5b64e00a | 1186 | GET_CYCLE(buf, ARCH_CONVERT), (long long)blkno); |
dfc130f3 | 1187 | print_stars(); |
2bd0ea18 NS |
1188 | if (print_exit) |
1189 | xlog_exit("Bad log record header"); | |
1190 | } /* print_xlog_bad_header */ | |
1191 | ||
1192 | void | |
1193 | print_xlog_bad_data(xfs_daddr_t blkno) | |
1194 | { | |
dfc130f3 RC |
1195 | print_stars(); |
1196 | printf("* ERROR: data block=%-21lld *\n", | |
1197 | (long long)blkno); | |
1198 | print_stars(); | |
2bd0ea18 NS |
1199 | if (print_exit) |
1200 | xlog_exit("Bad data in log"); | |
1201 | } /* print_xlog_bad_data */ | |
1202 | ||
dfb5b7da | 1203 | static void |
1204 | print_xlog_bad_reqd_hdrs(xfs_daddr_t blkno, int num_reqd, int num_hdrs) | |
1205 | { | |
1206 | print_stars(); | |
1207 | printf("* ERROR: for header block=%lld\n" | |
1208 | "* not enough hdrs for data length, " | |
1209 | "required num = %d, hdr num = %d\n", | |
1210 | (long long)blkno, num_reqd, num_hdrs); | |
1211 | print_stars(); | |
1212 | if (print_exit) | |
1213 | xlog_exit("Not enough headers for data length."); | |
1214 | } /* print_xlog_bad_reqd_hdrs */ | |
1215 | ||
1216 | static void | |
1217 | xlog_reallocate_xhdrs(int num_hdrs, xlog_rec_ext_header_t **ret_xhdrs) | |
1218 | { | |
1219 | int len = (num_hdrs-1) * sizeof(xlog_rec_ext_header_t); | |
1220 | ||
1221 | *ret_xhdrs = (xlog_rec_ext_header_t *)realloc(*ret_xhdrs, len); | |
1222 | if (*ret_xhdrs == NULL) { | |
1223 | fprintf(stderr, "%s: xlog_print: malloc failed for ext hdrs\n", progname); | |
1224 | exit(1); | |
1225 | } | |
1226 | } | |
1227 | ||
1228 | /* for V2 logs read each extra hdr and print it out */ | |
1229 | static int | |
1230 | xlog_print_extended_headers( | |
1231 | int fd, | |
1232 | int len, | |
1233 | xfs_daddr_t *blkno, | |
1234 | xlog_rec_header_t *hdr, | |
1235 | int *ret_num_hdrs, | |
1236 | xlog_rec_ext_header_t **ret_xhdrs) | |
1237 | { | |
1238 | int i, j; | |
1239 | int coverage_bb; | |
1240 | int num_hdrs; | |
1241 | int num_required; | |
1242 | char xhbuf[XLOG_HEADER_SIZE]; | |
1243 | xlog_rec_ext_header_t *x; | |
1244 | ||
1245 | num_required = howmany(len, XLOG_HEADER_CYCLE_SIZE); | |
1246 | num_hdrs = INT_GET(hdr->h_size, ARCH_CONVERT) / XLOG_HEADER_CYCLE_SIZE; | |
1247 | ||
1248 | if (num_required > num_hdrs) { | |
1249 | print_xlog_bad_reqd_hdrs((*blkno)-1, num_required, num_hdrs); | |
1250 | } | |
1251 | ||
1252 | if (num_hdrs == 1) { | |
1253 | free(*ret_xhdrs); | |
1254 | *ret_xhdrs = NULL; | |
1255 | *ret_num_hdrs = 1; | |
1256 | return 0; | |
1257 | } | |
1258 | ||
1259 | if (*ret_xhdrs == NULL || num_hdrs > *ret_num_hdrs) { | |
1260 | xlog_reallocate_xhdrs(num_hdrs, ret_xhdrs); | |
1261 | } | |
1262 | ||
1263 | *ret_num_hdrs = num_hdrs; | |
1264 | ||
1265 | /* don't include 1st header */ | |
1266 | for (i = 1, x = *ret_xhdrs; i < num_hdrs; i++, (*blkno)++, x++) { | |
1267 | /* read one extra header blk */ | |
1268 | if (read(fd, xhbuf, 512) == 0) { | |
1269 | printf("%s: physical end of log\n", progname); | |
1270 | print_xlog_record_line(); | |
1271 | /* reached the end so return 1 */ | |
1272 | return 1; | |
1273 | } | |
1274 | if (print_only_data) { | |
1275 | printf("BLKNO: %lld\n", (long long)*blkno); | |
1276 | xlog_recover_print_data(xhbuf, 512); | |
1277 | } | |
1278 | else { | |
1279 | if (i == num_hdrs - 1) { | |
1280 | /* last header */ | |
1281 | coverage_bb = BTOBB(len) % | |
1282 | (XLOG_HEADER_CYCLE_SIZE / BBSIZE); | |
1283 | } | |
1284 | else { | |
1285 | /* earliear header */ | |
1286 | coverage_bb = XLOG_HEADER_CYCLE_SIZE / BBSIZE; | |
1287 | } | |
1288 | xlog_print_rec_xhead((xlog_rec_ext_header_t*)xhbuf, coverage_bb); | |
1289 | } | |
1290 | ||
1291 | /* Copy from buffer into xhdrs array for later. | |
1292 | * Could endian convert here but then code later on | |
1293 | * will look asymmetric with the 1 hdr normal case | |
1294 | * which does endian coversion on access. | |
1295 | */ | |
1296 | x->xh_cycle = ((xlog_rec_ext_header_t*)xhbuf)->xh_cycle; | |
1297 | for (j = 0; j < XLOG_HEADER_CYCLE_SIZE / BBSIZE; j++) { | |
1298 | x->xh_cycle_data[j] = | |
1299 | ((xlog_rec_ext_header_t*)xhbuf)->xh_cycle_data[j]; | |
1300 | } | |
1301 | } | |
1302 | return 0; | |
1303 | } | |
1304 | ||
2bd0ea18 NS |
1305 | |
1306 | /* | |
1307 | * This code is gross and needs to be rewritten. | |
1308 | */ | |
1309 | void xfs_log_print(xlog_t *log, | |
dfc130f3 | 1310 | int fd, |
2bd0ea18 NS |
1311 | int print_block_start) |
1312 | { | |
dfb5b7da | 1313 | char hbuf[XLOG_HEADER_SIZE]; |
1314 | xlog_rec_header_t *hdr = (xlog_rec_header_t *)&hbuf[0]; | |
1315 | xlog_rec_ext_header_t *xhdrs = NULL; | |
1316 | int num_ops, len, num_hdrs = 1; | |
1317 | xfs_daddr_t block_end = 0, block_start, blkno, error; | |
1318 | xfs_daddr_t zeroed_blkno = 0, cleared_blkno = 0; | |
1319 | int read_type = FULL_READ; | |
1320 | xfs_caddr_t partial_buf; | |
1321 | int zeroed = 0; | |
1322 | int cleared = 0; | |
1323 | ||
2bd0ea18 | 1324 | logBBsize = log->l_logBBsize; |
dfc130f3 | 1325 | |
2bd0ea18 NS |
1326 | /* |
1327 | * Normally, block_start and block_end are the same value since we | |
1328 | * are printing the entire log. However, if the start block is given, | |
1329 | * we still end at the end of the logical log. | |
1330 | */ | |
27527004 | 1331 | if ((error = xlog_print_find_oldest(log, &block_end))) { |
dfb5b7da | 1332 | fprintf(stderr, "%s: problem finding oldest LR\n", progname); |
1333 | return; | |
2bd0ea18 NS |
1334 | } |
1335 | if (print_block_start == -1) | |
dfb5b7da | 1336 | block_start = block_end; |
2bd0ea18 | 1337 | else |
dfb5b7da | 1338 | block_start = print_block_start; |
2bd0ea18 | 1339 | xlog_print_lseek(log, fd, block_start, SEEK_SET); |
dfb5b7da | 1340 | blkno = block_start; |
dfc130f3 | 1341 | |
2bd0ea18 NS |
1342 | for (;;) { |
1343 | if (read(fd, hbuf, 512) == 0) { | |
1344 | printf("%s: physical end of log\n", progname); | |
1345 | print_xlog_record_line(); | |
1346 | break; | |
dfc130f3 | 1347 | } |
2bd0ea18 | 1348 | if (print_only_data) { |
dfb5b7da | 1349 | printf("BLKNO: %lld\n", (long long)blkno); |
1350 | xlog_recover_print_data(hbuf, 512); | |
1351 | blkno++; | |
1352 | goto loop; | |
2bd0ea18 | 1353 | } |
dfb5b7da | 1354 | num_ops = xlog_print_rec_head(hdr, &len); |
2bd0ea18 | 1355 | blkno++; |
dfc130f3 RC |
1356 | |
1357 | if (zeroed && num_ops != ZEROED_LOG) { | |
1358 | printf("%s: after %d zeroed blocks\n", progname, zeroed); | |
1359 | /* once we find zeroed blocks - that's all we expect */ | |
1360 | print_xlog_bad_zeroed(blkno-1); | |
1361 | /* reset count since we're assuming previous zeroed blocks | |
1362 | * were bad | |
1363 | */ | |
1364 | zeroed = 0; | |
1365 | } | |
1366 | ||
dfb5b7da | 1367 | if (num_ops == ZEROED_LOG || |
1368 | num_ops == CLEARED_BLKS || | |
1369 | num_ops == BAD_HEADER) { | |
dfc130f3 | 1370 | if (num_ops == ZEROED_LOG) { |
dfb5b7da | 1371 | if (zeroed == 0) |
1372 | zeroed_blkno = blkno-1; | |
dfc130f3 | 1373 | zeroed++; |
dfb5b7da | 1374 | } |
1375 | else if (num_ops == CLEARED_BLKS) { | |
1376 | if (cleared == 0) | |
1377 | cleared_blkno = blkno-1; | |
1378 | cleared++; | |
dfc130f3 RC |
1379 | } else { |
1380 | print_xlog_bad_header(blkno-1, hbuf); | |
1381 | } | |
1382 | ||
2bd0ea18 NS |
1383 | goto loop; |
1384 | } | |
dfc130f3 | 1385 | |
dfb5b7da | 1386 | if (INT_GET(hdr->h_version, ARCH_CONVERT) == 2) { |
1387 | if (xlog_print_extended_headers(fd, len, &blkno, hdr, &num_hdrs, &xhdrs) != 0) | |
1388 | break; | |
1389 | } | |
1390 | ||
1391 | error = xlog_print_record(fd, num_ops, len, &read_type, &partial_buf, hdr, xhdrs); | |
2bd0ea18 NS |
1392 | switch (error) { |
1393 | case 0: { | |
1394 | blkno += BTOBB(len); | |
1395 | if (print_block_start != -1 && | |
1396 | blkno >= block_end) /* If start specified, we */ | |
1397 | goto end; /* end early */ | |
1398 | break; | |
1399 | } | |
1400 | case -1: { | |
1401 | print_xlog_bad_data(blkno-1); | |
1402 | if (print_block_start != -1 && | |
1403 | blkno >= block_end) /* If start specified, */ | |
1404 | goto end; /* we end early */ | |
1405 | xlog_print_lseek(log, fd, blkno, SEEK_SET); | |
1406 | goto loop; | |
1407 | } | |
1408 | case PARTIAL_READ: { | |
dfc130f3 | 1409 | print_xlog_record_line(); |
2bd0ea18 | 1410 | printf("%s: physical end of log\n", progname); |
dfc130f3 | 1411 | print_xlog_record_line(); |
2bd0ea18 NS |
1412 | blkno = 0; |
1413 | xlog_print_lseek(log, fd, 0, SEEK_SET); | |
1414 | /* | |
1415 | * We may have hit the end of the log when we started at 0. | |
1416 | * In this case, just end. | |
1417 | */ | |
1418 | if (block_start == 0) | |
1419 | goto end; | |
1420 | goto partial_log_read; | |
1421 | } | |
1422 | default: xlog_panic("illegal value"); | |
1423 | } | |
1424 | print_xlog_record_line(); | |
1425 | loop: | |
1426 | if (blkno >= logBBsize) { | |
dfb5b7da | 1427 | if (cleared) { |
1428 | printf("%s: skipped %d cleared blocks in range: %lld - %lld\n", | |
83735711 NS |
1429 | progname, cleared, |
1430 | (long long)(cleared_blkno), | |
1431 | (long long)(cleared + cleared_blkno - 1)); | |
dfb5b7da | 1432 | if (cleared == logBBsize) |
1433 | printf("%s: totally cleared log\n", progname); | |
dfc130f3 | 1434 | |
dfb5b7da | 1435 | cleared=0; |
1436 | } | |
1437 | if (zeroed) { | |
1438 | printf("%s: skipped %d zeroed blocks in range: %lld - %lld\n", | |
83735711 NS |
1439 | progname, zeroed, |
1440 | (long long)(zeroed_blkno), | |
1441 | (long long)(zeroed + zeroed_blkno - 1)); | |
dfb5b7da | 1442 | if (zeroed == logBBsize) |
1443 | printf("%s: totally zeroed log\n", progname); | |
1444 | ||
1445 | zeroed=0; | |
1446 | } | |
1447 | printf("%s: physical end of log\n", progname); | |
1448 | print_xlog_record_line(); | |
1449 | break; | |
2bd0ea18 NS |
1450 | } |
1451 | } | |
1452 | ||
1453 | /* Do we need to print the first part of physical log? */ | |
1454 | if (block_start != 0) { | |
1455 | blkno = 0; | |
1456 | xlog_print_lseek(log, fd, 0, SEEK_SET); | |
1457 | for (;;) { | |
1458 | if (read(fd, hbuf, 512) == 0) { | |
1459 | xlog_panic("xlog_find_head: bad read"); | |
1460 | } | |
1461 | if (print_only_data) { | |
5b64e00a | 1462 | printf("BLKNO: %lld\n", (long long)blkno); |
2bd0ea18 NS |
1463 | xlog_recover_print_data(hbuf, 512); |
1464 | blkno++; | |
1465 | goto loop2; | |
1466 | } | |
dfb5b7da | 1467 | num_ops = xlog_print_rec_head(hdr, &len); |
2bd0ea18 | 1468 | blkno++; |
dfc130f3 | 1469 | |
dfb5b7da | 1470 | if (num_ops == ZEROED_LOG || |
1471 | num_ops == CLEARED_BLKS || | |
1472 | num_ops == BAD_HEADER) { | |
1473 | /* we only expect zeroed log entries or cleared log | |
1474 | * entries at the end of the _physical_ log, | |
1475 | * so treat them the same as bad blocks here | |
dfc130f3 | 1476 | */ |
2bd0ea18 | 1477 | print_xlog_bad_header(blkno-1, hbuf); |
dfc130f3 | 1478 | |
2bd0ea18 NS |
1479 | if (blkno >= block_end) |
1480 | break; | |
1481 | continue; | |
1482 | } | |
dfb5b7da | 1483 | |
1484 | if (INT_GET(hdr->h_version, ARCH_CONVERT) == 2) { | |
1485 | if (xlog_print_extended_headers(fd, len, &blkno, hdr, &num_hdrs, &xhdrs) != 0) | |
1486 | break; | |
1487 | } | |
1488 | ||
2bd0ea18 | 1489 | partial_log_read: |
dfb5b7da | 1490 | error= xlog_print_record(fd, |
1491 | num_ops, | |
1492 | len, | |
1493 | &read_type, | |
1494 | &partial_buf, | |
1495 | (xlog_rec_header_t *)hbuf, | |
1496 | xhdrs); | |
2bd0ea18 NS |
1497 | if (read_type != FULL_READ) |
1498 | len -= read_type; | |
1499 | read_type = FULL_READ; | |
1500 | if (!error) | |
1501 | blkno += BTOBB(len); | |
1502 | else { | |
1503 | print_xlog_bad_data(blkno-1); | |
1504 | xlog_print_lseek(log, fd, blkno, SEEK_SET); | |
1505 | goto loop2; | |
1506 | } | |
1507 | print_xlog_record_line(); | |
1508 | loop2: | |
1509 | if (blkno >= block_end) | |
1510 | break; | |
dfc130f3 | 1511 | } |
2bd0ea18 | 1512 | } |
dfc130f3 | 1513 | |
2bd0ea18 NS |
1514 | end: |
1515 | printf("%s: logical end of log\n", progname); | |
1516 | print_xlog_record_line(); | |
1517 | } |