Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : #include <stdio.h>
4 : #include <stdlib.h>
5 : #include <ctype.h>
6 : #include <string.h>
7 : #include <inttypes.h>
8 : #include <sys/types.h>
9 : #include <sys/stat.h>
10 : #include <fcntl.h>
11 : #include <unistd.h>
12 : #include <errno.h>
13 : #include <curses.h>
14 : #include <term.h>
15 : #include <time.h>
16 : #include <signal.h>
17 : #include <sys/ioctl.h>
18 : #include <sys/mount.h>
19 : #include <dirent.h>
20 :
21 : #include "copyright.cf"
22 :
23 : #include "hexedit.h"
24 : #include "libgfs2.h"
25 : #include "extended.h"
26 : #include "gfs2hex.h"
27 : #include "journal.h"
28 :
29 : /**
30 : * find_journal_block - figure out where a journal starts, given the name
31 : * Returns: journal block number, changes j_size to the journal size
32 : */
33 2 : uint64_t find_journal_block(const char *journal, uint64_t *j_size)
34 : {
35 : int journal_num;
36 2 : uint64_t jindex_block, jblock = 0;
37 : struct lgfs2_buffer_head *jindex_bh, *j_bh;
38 : struct gfs2_dinode *jdi;
39 :
40 2 : journal_num = atoi(journal + 7);
41 2 : if (journal_num < 0)
42 0 : return 0;
43 :
44 2 : jindex_block = masterblock("jindex");
45 2 : jindex_bh = lgfs2_bread(&sbd, jindex_block);
46 2 : di = (struct gfs2_dinode *)jindex_bh->b_data;
47 2 : do_dinode_extended(jindex_bh->b_data);
48 2 : if (journal_num > indirect->ii[0].dirents - 2) {
49 0 : lgfs2_brelse(jindex_bh);
50 0 : return 0;
51 : }
52 2 : jblock = indirect->ii[0].dirent[journal_num + 2].inum.in_addr;
53 2 : j_bh = lgfs2_bread(&sbd, jblock);
54 2 : jdi = (struct gfs2_dinode *)j_bh->b_data;
55 2 : *j_size = be64_to_cpu(jdi->di_size);
56 2 : lgfs2_brelse(j_bh);
57 2 : lgfs2_brelse(jindex_bh);
58 2 : return jblock;
59 : }
60 :
61 0 : static void check_journal_wrap(uint64_t seq, uint64_t *highest_seq)
62 : {
63 0 : if (seq < *highest_seq) {
64 0 : print_gfs2("------------------------------------------------"
65 : "------------------------------------------------");
66 0 : eol(0);
67 0 : print_gfs2("Journal wrapped here.");
68 0 : eol(0);
69 0 : print_gfs2("------------------------------------------------"
70 : "------------------------------------------------");
71 0 : eol(0);
72 : }
73 0 : *highest_seq = seq;
74 0 : }
75 :
76 : /**
77 : * fsck_readi - same as libgfs2's lgfs2_readi, but sets absolute block #
78 : * of the first bit of data read.
79 : */
80 0 : static int fsck_readi(struct lgfs2_inode *ip, void *rbuf, uint64_t roffset,
81 : unsigned int size, uint64_t *abs_block)
82 : {
83 : struct lgfs2_sbd *sdp;
84 : struct lgfs2_buffer_head *lbh;
85 : uint64_t lblock, dblock;
86 : unsigned int o;
87 0 : uint32_t extlen = 0;
88 : unsigned int amount;
89 0 : int not_new = 0;
90 : int isdir;
91 0 : int copied = 0;
92 :
93 0 : if (ip == NULL)
94 0 : return 0;
95 0 : sdp = ip->i_sbd;
96 0 : isdir = !!(S_ISDIR(ip->i_mode));
97 0 : *abs_block = 0;
98 0 : if (roffset >= ip->i_size)
99 0 : return 0;
100 0 : if ((roffset + size) > ip->i_size)
101 0 : size = ip->i_size - roffset;
102 0 : if (!size)
103 0 : return 0;
104 0 : if (isdir) {
105 0 : o = roffset % sdp->sd_jbsize;
106 0 : lblock = roffset / sdp->sd_jbsize;
107 : } else {
108 0 : lblock = roffset >> sdp->sd_bsize_shift;
109 0 : o = roffset & (sdp->sd_bsize - 1);
110 : }
111 :
112 0 : if (!ip->i_height) /* inode_is_stuffed */
113 0 : o += sizeof(struct gfs2_dinode);
114 0 : else if (isdir)
115 0 : o += sizeof(struct gfs2_meta_header);
116 :
117 0 : while (copied < size) {
118 0 : amount = size - copied;
119 0 : if (amount > sdp->sd_bsize - o)
120 0 : amount = sdp->sd_bsize - o;
121 0 : if (!extlen)
122 0 : if (lgfs2_block_map(ip, lblock, ¬_new, &dblock, &extlen, FALSE))
123 0 : exit(1);
124 0 : if (dblock) {
125 0 : lbh = lgfs2_bread(sdp, dblock);
126 0 : if (*abs_block == 0)
127 0 : *abs_block = lbh->b_blocknr;
128 0 : dblock++;
129 0 : extlen--;
130 : } else
131 0 : lbh = NULL;
132 0 : if (lbh) {
133 0 : memcpy(rbuf, lbh->b_data + o, amount);
134 0 : lgfs2_brelse(lbh);
135 : } else {
136 0 : memset(rbuf, 0, amount);
137 : }
138 0 : copied += amount;
139 0 : lblock++;
140 0 : o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
141 : }
142 0 : return copied;
143 : }
144 :
145 : /**
146 : * ld_is_pertinent - determine if a log descriptor is pertinent
147 : *
148 : * This function checks a log descriptor buffer to see if it contains
149 : * references to a given traced block, or its rgrp bitmap block.
150 : */
151 0 : static int ld_is_pertinent(const __be64 *b, const char *end, uint64_t tblk,
152 : struct lgfs2_rgrp_tree *rgd, uint64_t bitblk)
153 : {
154 0 : const __be64 *blk = b;
155 :
156 0 : if (!tblk)
157 0 : return 1;
158 :
159 0 : while (*blk && (char *)blk < end) {
160 0 : if (be64_to_cpu(*blk) == tblk || be64_to_cpu(*blk) == bitblk)
161 0 : return 1;
162 0 : blk++;
163 : }
164 0 : return 0;
165 : }
166 :
167 : /**
168 : * print_ld_blks - print all blocks given in a log descriptor
169 : * returns: the number of block numbers it printed
170 : */
171 0 : static int print_ld_blks(const __be64 *b, const char *end, int start_line,
172 : uint64_t tblk, uint64_t *tblk_off, uint64_t bitblk,
173 : struct lgfs2_rgrp_tree *rgd, uint64_t abs_block, int prnt,
174 : uint64_t *bblk_off, int is_meta_ld)
175 : {
176 0 : int bcount = 0, found_tblk = 0, found_bblk = 0;
177 : static char str[256];
178 : struct lgfs2_buffer_head *j_bmap_bh;
179 :
180 0 : if (tblk_off)
181 0 : *tblk_off = 0;
182 0 : if (bblk_off)
183 0 : *bblk_off = 0;
184 0 : while (*b && (char *)b < end) {
185 0 : if (!termlines ||
186 0 : (print_entry_ndx >= start_row[dmode] &&
187 0 : ((print_entry_ndx - start_row[dmode])+1) *
188 0 : lines_per_row[dmode] <= termlines - start_line - 2)) {
189 0 : if (prnt && bcount && bcount % 4 == 0) {
190 0 : eol(0);
191 0 : print_gfs2(" ");
192 : }
193 0 : bcount++;
194 0 : if (prnt) {
195 0 : if (is_meta_ld) {
196 0 : j_bmap_bh = lgfs2_bread(&sbd, abs_block +
197 : bcount);
198 0 : sprintf(str, "0x%"PRIx64" %2s",
199 : be64_to_cpu(*b),
200 0 : mtypes[lgfs2_get_block_type(j_bmap_bh->b_data)]);
201 0 : lgfs2_brelse(j_bmap_bh);
202 : } else {
203 0 : sprintf(str, "0x%"PRIx64, be64_to_cpu(*b));
204 : }
205 0 : print_gfs2("%-18.18s ", str);
206 : }
207 0 : if (!found_tblk && tblk_off)
208 0 : (*tblk_off)++;
209 0 : if (!found_bblk && bblk_off)
210 0 : (*bblk_off)++;
211 0 : if (tblk && (be64_to_cpu(*b) == tblk)) {
212 0 : found_tblk = 1;
213 0 : print_gfs2("<-------------------------0x%"PRIx64" ", tblk);
214 0 : eol(18 * (bcount % 4) + 1);
215 0 : print_gfs2(" ");
216 : }
217 0 : if (tblk && rgd && (be64_to_cpu(*b) == bitblk)) {
218 0 : int type, bmap = 0;
219 : uint64_t o;
220 : char *save_ptr;
221 :
222 0 : found_bblk = 1;
223 0 : print_gfs2("<-------------------------");
224 0 : if (is_meta_ld) {
225 0 : o = tblk - rgd->rt_data0;
226 0 : if (o >= ((uint64_t)rgd->rt_bits->bi_start +
227 0 : rgd->rt_bits->bi_len) *
228 : GFS2_NBBY)
229 0 : o += (sizeof(struct gfs2_rgrp) -
230 : sizeof(struct gfs2_meta_header))
231 : * GFS2_NBBY;
232 0 : bmap = o / sbd.sd_blocks_per_bitmap;
233 0 : save_ptr = rgd->rt_bits[bmap].bi_data;
234 0 : j_bmap_bh = lgfs2_bread(&sbd, abs_block +
235 : bcount);
236 0 : rgd->rt_bits[bmap].bi_data = j_bmap_bh->b_data;
237 0 : type = lgfs2_get_bitmap(&sbd, tblk, rgd);
238 0 : lgfs2_brelse(j_bmap_bh);
239 0 : if (type < 0) {
240 0 : perror("Error printing log descriptor blocks");
241 0 : exit(1);
242 : }
243 0 : rgd->rt_bits[bmap].bi_data = save_ptr;
244 0 : print_gfs2("bit for blk 0x%"PRIx64" is %d (%s)",
245 : tblk, type,
246 : allocdesc[type]);
247 : } else {
248 0 : print_gfs2("bitmap for blk 0x%"PRIx64" was revoked",
249 : tblk);
250 : }
251 0 : eol(18 * (bcount % 4) + 1);
252 0 : print_gfs2(" ");
253 : }
254 : }
255 0 : b++;
256 : }
257 0 : if (prnt)
258 0 : eol(0);
259 0 : if (tblk_off && (!found_tblk || !is_meta_ld))
260 0 : *tblk_off = 0;
261 0 : if (bblk_off && (!found_bblk || !is_meta_ld))
262 0 : *bblk_off = 0;
263 0 : return bcount;
264 : }
265 :
266 0 : static int is_wrap_pt(void *buf, uint64_t *highest_seq)
267 : {
268 0 : const struct lgfs2_metadata *mtype = get_block_type(buf);
269 :
270 0 : if (mtype != NULL && mtype->mh_type == GFS2_METATYPE_LH) {
271 0 : struct gfs2_log_header *lh = buf;
272 : uint64_t seq;
273 :
274 0 : seq = be64_to_cpu(lh->lh_sequence);
275 0 : if (seq < *highest_seq)
276 0 : return 1;
277 0 : *highest_seq = seq;
278 : }
279 0 : return 0;
280 : }
281 :
282 : /**
283 : * find_wrap_pt - figure out where a journal wraps
284 : * Returns: The wrap point, in bytes
285 : */
286 0 : static uint64_t find_wrap_pt(struct lgfs2_inode *ji, char *jbuf, uint64_t jblock, uint64_t j_size)
287 : {
288 0 : uint64_t jb = 0;
289 0 : uint64_t highest_seq = 0;
290 :
291 0 : for (jb = 0; jb < j_size; jb += sbd.sd_bsize) {
292 0 : int found = 0;
293 : int copied;
294 : uint64_t abs_block;
295 :
296 0 : copied = fsck_readi(ji, jbuf, jb, sbd.sd_bsize, &abs_block);
297 0 : if (!copied) /* end of file */
298 0 : break;
299 0 : found = is_wrap_pt(jbuf, &highest_seq);
300 0 : if (found)
301 0 : return jb;
302 : }
303 0 : return 0;
304 : }
305 :
306 : /**
307 : * process_ld - process a log descriptor
308 : */
309 0 : static int process_ld(uint64_t abs_block, uint64_t wrappt, uint64_t j_size,
310 : uint64_t jb, char *buf, int tblk,
311 : uint64_t *tblk_off, uint64_t bitblk,
312 : struct lgfs2_rgrp_tree *rgd, int *prnt, uint64_t *bblk_off)
313 : {
314 : __be64 *b;
315 0 : struct gfs2_log_descriptor *ld = (void *)buf;
316 0 : int ltndx, is_meta_ld = 0;
317 0 : int ld_blocks = 0;
318 0 : uint32_t ld_type = be32_to_cpu(ld->ld_type);
319 0 : uint32_t ld_length = be32_to_cpu(ld->ld_length);
320 0 : uint32_t ld_data1 = be32_to_cpu(ld->ld_data1);
321 0 : uint32_t logtypes[6] = {
322 : GFS2_LOG_DESC_METADATA,
323 : GFS2_LOG_DESC_REVOKE,
324 : GFS2_LOG_DESC_JDATA,
325 : 0, 0, 0
326 : };
327 0 : const char *logtypestr[6] = {
328 : "Metadata",
329 : "Revoke",
330 : "Jdata",
331 : "Unknown",
332 : "Unknown",
333 : "Unknown"
334 : };
335 0 : b = (__be64 *)(buf + sizeof(struct gfs2_log_descriptor));
336 0 : *prnt = ld_is_pertinent(b, (buf + sbd.sd_bsize), tblk, rgd, bitblk);
337 :
338 0 : if (*prnt) {
339 0 : print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log descriptor, ",
340 0 : abs_block, ((jb + wrappt) % j_size) / sbd.sd_bsize);
341 0 : print_gfs2("type %"PRIu32" ", ld_type);
342 :
343 0 : for (ltndx = 0;; ltndx++) {
344 0 : if (ld_type == logtypes[ltndx] ||
345 0 : logtypes[ltndx] == 0)
346 : break;
347 : }
348 0 : print_gfs2("(%s) ", logtypestr[ltndx]);
349 0 : print_gfs2("len:%"PRIu32", data1: %"PRIu32, ld_length, ld_data1);
350 0 : eol(0);
351 0 : print_gfs2(" ");
352 : }
353 0 : ld_blocks = ld_data1;
354 0 : if (ld_type == GFS2_LOG_DESC_METADATA)
355 0 : is_meta_ld = 1;
356 0 : ld_blocks -= print_ld_blks(b, (buf + sbd.sd_bsize), line, tblk, tblk_off,
357 : bitblk, rgd, abs_block, *prnt, bblk_off,
358 : is_meta_ld);
359 :
360 0 : return ld_blocks;
361 : }
362 :
363 : /**
364 : * meta_has_ref - check if a metadata block references a given block
365 : */
366 0 : static int meta_has_ref(uint64_t abs_block, int tblk)
367 : {
368 : const struct lgfs2_metadata *mtype;
369 : struct lgfs2_buffer_head *mbh;
370 0 : int structlen = 0, has_ref = 0;
371 : __be64 *b;
372 : struct gfs2_dinode *dinode;
373 :
374 0 : mbh = lgfs2_bread(&sbd, abs_block);
375 0 : mtype = get_block_type(mbh->b_data);
376 0 : if (mtype != NULL) {
377 0 : structlen = mtype->size;
378 0 : if (mtype->mh_type == GFS2_METATYPE_DI) {
379 0 : dinode = (struct gfs2_dinode *)mbh->b_data;
380 0 : if (be64_to_cpu(dinode->di_eattr) == tblk)
381 0 : has_ref = 1;
382 : }
383 : }
384 0 : b = (__be64 *)(mbh->b_data + structlen);
385 0 : while (!has_ref && mtype && (char *)b < mbh->b_data + sbd.sd_bsize) {
386 0 : if (be64_to_cpu(*b) == tblk)
387 0 : has_ref = 1;
388 0 : b++;
389 : }
390 0 : lgfs2_brelse(mbh);
391 0 : return has_ref;
392 : }
393 :
394 :
395 : /**
396 : * get_ldref - get a log descriptor reference block, given a block number
397 : *
398 : * Note that we can't pass in abs_block here, because journal wrap may
399 : * mean that the block we're interested in, in the journal, is before the
400 : * log descriptor that holds the reference we need.
401 : */
402 0 : static uint64_t get_ldref(uint64_t abs_ld, int offset_from_ld)
403 : {
404 : struct lgfs2_buffer_head *jbh;
405 : uint64_t refblk;
406 : __be64 *b;
407 :
408 0 : jbh = lgfs2_bread(&sbd, abs_ld);
409 0 : b = (__be64 *)(jbh->b_data + sizeof(struct gfs2_log_descriptor));
410 0 : b += offset_from_ld - 1;
411 0 : refblk = be64_to_cpu(*b);
412 0 : lgfs2_brelse(jbh);
413 0 : return refblk;
414 : }
415 :
416 0 : static void display_log_header(void *buf, uint64_t *highest_seq, uint64_t abs_block, uint64_t jb, uint64_t j_size)
417 : {
418 : const struct lgfs2_metafield *lh_flags_field;
419 : const struct lgfs2_metadata *mtype;
420 0 : struct gfs2_log_header *lh = buf;
421 : char flags_str[256];
422 :
423 0 : mtype = &lgfs2_metadata[LGFS2_MT_GFS2_LOG_HEADER];
424 0 : lh_flags_field = &mtype->fields[6]; /* lh_flags is the 7th field in the struct */
425 0 : check_journal_wrap(be64_to_cpu(lh->lh_sequence), highest_seq);
426 0 : lgfs2_field_str(flags_str, sizeof(flags_str), buf, lh_flags_field, (dmode == HEX_MODE));
427 0 : print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log header: Seq: 0x%"PRIx64", "
428 : "tail: 0x%"PRIx32", blk: 0x%"PRIx32" [%s]",
429 0 : abs_block, (jb % j_size) / sbd.sd_bsize, be64_to_cpu(lh->lh_sequence),
430 0 : be32_to_cpu(lh->lh_tail), be32_to_cpu(lh->lh_blkno), flags_str);
431 0 : }
432 :
433 : /**
434 : * dump_journal - dump a journal file's contents.
435 : * @journal: name of the journal to dump
436 : * @tblk: block number to trace in the journals
437 : *
438 : * This function dumps the contents of a journal. If a trace block is specified
439 : * then only information printed is: (1) log descriptors that reference that
440 : * block, (2) metadata in the journal that references the block, or (3)
441 : * rgrp bitmaps that reference that block's allocation bit status.
442 : */
443 0 : void dump_journal(const char *journal, uint64_t tblk)
444 : {
445 : const struct lgfs2_metadata *mtype;
446 0 : struct lgfs2_buffer_head *j_bh = NULL;
447 0 : uint64_t jblock, j_size, jb, abs_block, saveblk, wrappt = 0;
448 : int start_line, journal_num;
449 0 : struct lgfs2_inode *j_inode = NULL;
450 0 : int ld_blocks = 0, offset_from_ld = 0;
451 0 : uint64_t tblk_off = 0, bblk_off = 0, bitblk = 0;
452 0 : uint64_t highest_seq = 0;
453 0 : char *jbuf = NULL;
454 0 : char *buf = NULL;
455 0 : struct lgfs2_rgrp_tree *rgd = NULL;
456 0 : uint64_t abs_ld = 0;
457 :
458 0 : mtype = lgfs2_find_mtype(GFS2_METATYPE_LH);
459 :
460 0 : start_line = line;
461 0 : lines_per_row[dmode] = 1;
462 0 : journal_num = atoi(journal + 7);
463 0 : print_gfs2("Dumping journal #%d.", journal_num);
464 0 : if (tblk) {
465 0 : dmode = HEX_MODE;
466 0 : print_gfs2(" Tracing block 0x%"PRIx64, tblk);
467 : }
468 0 : eol(0);
469 0 : jblock = find_journal_block(journal, &j_size);
470 0 : if (!jblock)
471 0 : return;
472 :
473 0 : j_bh = lgfs2_bread(&sbd, jblock);
474 0 : j_inode = lgfs2_inode_get(&sbd, j_bh);
475 0 : if (j_inode == NULL) {
476 0 : fprintf(stderr, "Out of memory\n");
477 0 : exit(-1);
478 : }
479 0 : jbuf = malloc(sbd.sd_bsize);
480 0 : if (jbuf == NULL) {
481 0 : fprintf(stderr, "Out of memory\n");
482 0 : exit(-1);
483 : }
484 :
485 0 : if (tblk) {
486 : uint64_t wp;
487 :
488 0 : rgd = lgfs2_blk2rgrpd(&sbd, tblk);
489 0 : if (!rgd) {
490 0 : print_gfs2("Can't locate the rgrp for block 0x%"PRIx64,
491 : tblk);
492 0 : eol(0);
493 : } else {
494 : uint64_t o;
495 0 : int bmap = 0;
496 :
497 0 : print_gfs2("rgd: 0x%"PRIx64" for 0x%"PRIx32", ", rgd->rt_addr,
498 : rgd->rt_length);
499 0 : o = tblk - rgd->rt_data0;
500 0 : if (o >= (rgd->rt_bits->bi_start +
501 0 : rgd->rt_bits->bi_len) * (uint64_t)GFS2_NBBY)
502 0 : o += (sizeof(struct gfs2_rgrp) -
503 : sizeof(struct gfs2_meta_header))
504 : * GFS2_NBBY;
505 0 : bmap = o / sbd.sd_blocks_per_bitmap;
506 0 : bitblk = rgd->rt_addr + bmap;
507 0 : print_gfs2("bitmap: %d, bitblk: 0x%"PRIx64, bmap, bitblk);
508 0 : eol(0);
509 : }
510 :
511 0 : wrappt = find_wrap_pt(j_inode, jbuf, jblock, j_size);
512 0 : wp = wrappt / sbd.sd_bsize;
513 0 : print_gfs2("Starting at journal wrap block: 0x%"PRIx64" (j + 0x%"PRIx64")",
514 : jblock + wp, wp);
515 0 : eol(0);
516 : }
517 :
518 0 : for (jb = 0; jb < j_size; jb += sbd.sd_bsize) {
519 0 : int is_pertinent = 1;
520 0 : uint32_t block_type = 0;
521 0 : int error = fsck_readi(j_inode, (void *)jbuf,
522 0 : ((jb + wrappt) % j_size),
523 : sbd.sd_bsize, &abs_block);
524 0 : if (!error) /* end of file */
525 0 : break;
526 0 : buf = jbuf;
527 0 : offset_from_ld++;
528 0 : mtype = get_block_type(buf);
529 0 : if (mtype != NULL)
530 0 : block_type = mtype->mh_type;
531 :
532 0 : if (block_type == GFS2_METATYPE_LD) {
533 0 : ld_blocks = process_ld(abs_block, wrappt, j_size, jb,
534 : buf, tblk, &tblk_off,
535 : bitblk, rgd, &is_pertinent,
536 : &bblk_off);
537 0 : offset_from_ld = 0;
538 0 : abs_ld = abs_block;
539 0 : } else if (!tblk && block_type == GFS2_METATYPE_LH) {
540 0 : display_log_header(buf, &highest_seq, abs_block, jb + wrappt, j_size);
541 0 : eol(0);
542 0 : } else if ((ld_blocks > 0) && (block_type == GFS2_METATYPE_LB)) {
543 0 : __be64 *b = (__be64 *)(buf + sizeof(struct gfs2_meta_header));
544 :
545 0 : print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log descriptor"
546 : " continuation block", abs_block,
547 0 : ((jb + wrappt) % j_size) / sbd.sd_bsize);
548 0 : eol(0);
549 0 : print_gfs2(" ");
550 0 : ld_blocks -= print_ld_blks(b, (buf + sbd.sd_bsize), start_line,
551 : tblk, &tblk_off, 0, rgd, 0, 1, NULL, 0);
552 0 : } else if (block_type == 0) {
553 0 : continue;
554 : }
555 : /* Check if this metadata block references the block we're
556 : trying to trace. */
557 0 : if (details || (tblk && ((is_pertinent &&
558 0 : ((tblk_off && offset_from_ld == tblk_off) ||
559 0 : (bblk_off && offset_from_ld == bblk_off))) ||
560 0 : meta_has_ref(abs_block, tblk)))) {
561 0 : uint64_t ref_blk = 0;
562 :
563 0 : saveblk = block;
564 0 : block = abs_block;
565 0 : if (tblk && !details) {
566 0 : ref_blk = get_ldref(abs_ld, offset_from_ld);
567 0 : display(0, 1, tblk, ref_blk);
568 : } else {
569 0 : display(0, 0, 0, 0);
570 : }
571 0 : block = saveblk;
572 : }
573 : }
574 0 : if (j_inode != NULL)
575 0 : lgfs2_inode_put(&j_inode);
576 0 : lgfs2_brelse(j_bh);
577 0 : blockhist = -1; /* So we don't print anything else */
578 0 : free(jbuf);
579 0 : if (!termlines)
580 0 : fflush(stdout);
581 : }
|