|
Packit |
6ef888 |
#include "clusterautoconfig.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <stdio.h>
|
|
Packit |
6ef888 |
#include <stdlib.h>
|
|
Packit |
6ef888 |
#include <ctype.h>
|
|
Packit |
6ef888 |
#include <string.h>
|
|
Packit |
6ef888 |
#include <inttypes.h>
|
|
Packit |
6ef888 |
#include <sys/types.h>
|
|
Packit |
6ef888 |
#include <linux/types.h>
|
|
Packit |
6ef888 |
#include <sys/stat.h>
|
|
Packit |
6ef888 |
#include <fcntl.h>
|
|
Packit |
6ef888 |
#include <unistd.h>
|
|
Packit |
6ef888 |
#include <errno.h>
|
|
Packit |
6ef888 |
#include <curses.h>
|
|
Packit |
6ef888 |
#include <term.h>
|
|
Packit |
6ef888 |
#include <time.h>
|
|
Packit |
6ef888 |
#include <signal.h>
|
|
Packit |
6ef888 |
#include <sys/ioctl.h>
|
|
Packit |
6ef888 |
#include <sys/mount.h>
|
|
Packit |
6ef888 |
#include <dirent.h>
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <linux/gfs2_ondisk.h>
|
|
Packit |
6ef888 |
#include "copyright.cf"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include "hexedit.h"
|
|
Packit |
6ef888 |
#include "libgfs2.h"
|
|
Packit |
6ef888 |
#include "extended.h"
|
|
Packit |
6ef888 |
#include "gfs2hex.h"
|
|
Packit |
6ef888 |
#include "journal.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
extern uint64_t block;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* find_journal_block - figure out where a journal starts, given the name
|
|
Packit |
6ef888 |
* Returns: journal block number, changes j_size to the journal size
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
uint64_t find_journal_block(const char *journal, uint64_t *j_size)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int journal_num;
|
|
Packit |
6ef888 |
uint64_t jindex_block, jblock = 0;
|
|
Packit |
6ef888 |
int amtread;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *jindex_bh, *j_bh;
|
|
Packit |
6ef888 |
char jbuf[sbd.bsize];
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
journal_num = atoi(journal + 7);
|
|
Packit |
6ef888 |
if (journal_num < 0)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* Figure out the block of the jindex file */
|
|
Packit |
6ef888 |
if (sbd.gfs1)
|
|
Packit |
6ef888 |
jindex_block = sbd1->sb_jindex_di.no_addr;
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
jindex_block = masterblock("jindex");
|
|
Packit |
6ef888 |
/* read in the block */
|
|
Packit |
6ef888 |
jindex_bh = bread(&sbd, jindex_block);
|
|
Packit |
6ef888 |
/* get the dinode data from it. */
|
|
Packit |
6ef888 |
gfs2_dinode_in(&di, jindex_bh->b_data);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!sbd.gfs1)
|
|
Packit |
6ef888 |
do_dinode_extended(&di, jindex_bh); /* parse dir. */
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sbd.gfs1) {
|
|
Packit |
6ef888 |
struct gfs2_inode *jiinode;
|
|
Packit |
6ef888 |
struct gfs_jindex ji;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
jiinode = lgfs2_inode_get(&sbd, jindex_bh);
|
|
Packit |
6ef888 |
if (jiinode == NULL)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
amtread = gfs2_readi(jiinode, (void *)&jbuf,
|
|
Packit |
6ef888 |
journal_num * sizeof(struct gfs_jindex),
|
|
Packit |
6ef888 |
sizeof(struct gfs_jindex));
|
|
Packit |
6ef888 |
if (amtread) {
|
|
Packit |
6ef888 |
gfs_jindex_in(&ji, jbuf);
|
|
Packit |
6ef888 |
jblock = ji.ji_addr;
|
|
Packit |
6ef888 |
*j_size = (uint64_t)ji.ji_nsegment * 0x10;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
inode_put(&jiinode);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
struct gfs2_dinode jdi;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (journal_num > indirect->ii[0].dirents - 2)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
jblock = indirect->ii[0].dirent[journal_num + 2].block;
|
|
Packit |
6ef888 |
j_bh = bread(&sbd, jblock);
|
|
Packit |
6ef888 |
gfs2_dinode_in(&jdi, j_bh->b_data);
|
|
Packit |
6ef888 |
*j_size = jdi.di_size;
|
|
Packit |
6ef888 |
brelse(j_bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
brelse(jindex_bh);
|
|
Packit |
6ef888 |
return jblock;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void check_journal_wrap(uint64_t seq, uint64_t *highest_seq)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
if (seq < *highest_seq) {
|
|
Packit |
6ef888 |
print_gfs2("------------------------------------------------"
|
|
Packit |
6ef888 |
"------------------------------------------------");
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
print_gfs2("Journal wrapped here.");
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
print_gfs2("------------------------------------------------"
|
|
Packit |
6ef888 |
"------------------------------------------------");
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
*highest_seq = seq;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* fsck_readi - same as libgfs2's gfs2_readi, but sets absolute block #
|
|
Packit |
6ef888 |
* of the first bit of data read.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int fsck_readi(struct gfs2_inode *ip, void *rbuf, uint64_t roffset,
|
|
Packit |
6ef888 |
unsigned int size, uint64_t *abs_block)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_sbd *sdp;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *lbh;
|
|
Packit |
6ef888 |
uint64_t lblock, dblock;
|
|
Packit |
6ef888 |
unsigned int o;
|
|
Packit |
6ef888 |
uint32_t extlen = 0;
|
|
Packit |
6ef888 |
unsigned int amount;
|
|
Packit |
6ef888 |
int not_new = 0;
|
|
Packit |
6ef888 |
int isdir;
|
|
Packit |
6ef888 |
int copied = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (ip == NULL)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
sdp = ip->i_sbd;
|
|
Packit |
6ef888 |
isdir = !!(S_ISDIR(ip->i_di.di_mode));
|
|
Packit |
6ef888 |
*abs_block = 0;
|
|
Packit |
6ef888 |
if (roffset >= ip->i_di.di_size)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
if ((roffset + size) > ip->i_di.di_size)
|
|
Packit |
6ef888 |
size = ip->i_di.di_size - roffset;
|
|
Packit |
6ef888 |
if (!size)
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
if (isdir) {
|
|
Packit |
6ef888 |
o = roffset % sdp->sd_jbsize;
|
|
Packit |
6ef888 |
lblock = roffset / sdp->sd_jbsize;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
lblock = roffset >> sdp->sd_sb.sb_bsize_shift;
|
|
Packit |
6ef888 |
o = roffset & (sdp->bsize - 1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!ip->i_di.di_height) /* inode_is_stuffed */
|
|
Packit |
6ef888 |
o += sizeof(struct gfs2_dinode);
|
|
Packit |
6ef888 |
else if (isdir)
|
|
Packit |
6ef888 |
o += sizeof(struct gfs2_meta_header);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while (copied < size) {
|
|
Packit |
6ef888 |
amount = size - copied;
|
|
Packit |
6ef888 |
if (amount > sdp->bsize - o)
|
|
Packit |
6ef888 |
amount = sdp->bsize - o;
|
|
Packit |
6ef888 |
if (!extlen)
|
|
Packit |
6ef888 |
block_map(ip, lblock, ¬_new, &dblock, &extlen,
|
|
Packit |
6ef888 |
FALSE);
|
|
Packit |
6ef888 |
if (dblock) {
|
|
Packit |
6ef888 |
lbh = bread(sdp, dblock);
|
|
Packit |
6ef888 |
if (*abs_block == 0)
|
|
Packit |
6ef888 |
*abs_block = lbh->b_blocknr;
|
|
Packit |
6ef888 |
dblock++;
|
|
Packit |
6ef888 |
extlen--;
|
|
Packit |
6ef888 |
} else
|
|
Packit |
6ef888 |
lbh = NULL;
|
|
Packit |
6ef888 |
if (lbh) {
|
|
Packit |
6ef888 |
memcpy(rbuf, lbh->b_data + o, amount);
|
|
Packit |
6ef888 |
brelse(lbh);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
memset(rbuf, 0, amount);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
copied += amount;
|
|
Packit |
6ef888 |
lblock++;
|
|
Packit |
6ef888 |
o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return copied;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* ld_is_pertinent - determine if a log descriptor is pertinent
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function checks a log descriptor buffer to see if it contains
|
|
Packit |
6ef888 |
* references to a given traced block, or its rgrp bitmap block.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int ld_is_pertinent(const uint64_t *b, const char *end, uint64_t tblk,
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd, uint64_t bitblk)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
const uint64_t *blk = b;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!tblk)
|
|
Packit |
6ef888 |
return 1;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
while (*blk && (char *)blk < end) {
|
|
Packit |
6ef888 |
if (be64_to_cpu(*blk) == tblk || be64_to_cpu(*blk) == bitblk)
|
|
Packit |
6ef888 |
return 1;
|
|
Packit |
6ef888 |
blk++;
|
|
Packit |
6ef888 |
if (sbd.gfs1)
|
|
Packit |
6ef888 |
blk++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* print_ld_blks - print all blocks given in a log descriptor
|
|
Packit |
6ef888 |
* returns: the number of block numbers it printed
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int print_ld_blks(const uint64_t *b, const char *end, int start_line,
|
|
Packit |
6ef888 |
uint64_t tblk, uint64_t *tblk_off, uint64_t bitblk,
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd, uint64_t abs_block, int prnt,
|
|
Packit |
6ef888 |
uint64_t *bblk_off, int is_meta_ld)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
int bcount = 0, found_tblk = 0, found_bblk = 0;
|
|
Packit |
6ef888 |
static char str[256];
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *j_bmap_bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (tblk_off)
|
|
Packit |
6ef888 |
*tblk_off = 0;
|
|
Packit |
6ef888 |
if (bblk_off)
|
|
Packit |
6ef888 |
*bblk_off = 0;
|
|
Packit |
6ef888 |
while (*b && (char *)b < end) {
|
|
Packit |
6ef888 |
if (!termlines ||
|
|
Packit |
6ef888 |
(print_entry_ndx >= start_row[dmode] &&
|
|
Packit |
6ef888 |
((print_entry_ndx - start_row[dmode])+1) *
|
|
Packit |
6ef888 |
lines_per_row[dmode] <= termlines - start_line - 2)) {
|
|
Packit |
6ef888 |
if (prnt && bcount && bcount % 4 == 0) {
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
print_gfs2(" ");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
bcount++;
|
|
Packit |
6ef888 |
if (prnt) {
|
|
Packit |
6ef888 |
if (is_meta_ld) {
|
|
Packit |
6ef888 |
j_bmap_bh = bread(&sbd, abs_block +
|
|
Packit |
6ef888 |
bcount);
|
|
Packit |
6ef888 |
sprintf(str, "0x%llx %2s",
|
|
Packit |
6ef888 |
(unsigned long long)be64_to_cpu(*b),
|
|
Packit |
6ef888 |
mtypes[lgfs2_get_block_type(j_bmap_bh)]);
|
|
Packit |
6ef888 |
brelse(j_bmap_bh);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
sprintf(str, "0x%llx",
|
|
Packit |
6ef888 |
(unsigned long long)be64_to_cpu(*b));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
print_gfs2("%-18.18s ", str);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (!found_tblk && tblk_off)
|
|
Packit |
6ef888 |
(*tblk_off)++;
|
|
Packit |
6ef888 |
if (!found_bblk && bblk_off)
|
|
Packit |
6ef888 |
(*bblk_off)++;
|
|
Packit |
6ef888 |
if (tblk && (be64_to_cpu(*b) == tblk)) {
|
|
Packit |
6ef888 |
found_tblk = 1;
|
|
Packit |
6ef888 |
print_gfs2("<-------------------------0x%llx ",
|
|
Packit |
6ef888 |
(unsigned long long)tblk);
|
|
Packit |
6ef888 |
eol(18 * (bcount % 4) + 1);
|
|
Packit |
6ef888 |
print_gfs2(" ");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (tblk && rgd && (be64_to_cpu(*b) == bitblk)) {
|
|
Packit |
6ef888 |
int type, bmap = 0;
|
|
Packit |
6ef888 |
uint64_t o;
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *save_bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
found_bblk = 1;
|
|
Packit |
6ef888 |
print_gfs2("<-------------------------");
|
|
Packit |
6ef888 |
if (is_meta_ld) {
|
|
Packit |
6ef888 |
o = tblk - rgd->ri.ri_data0;
|
|
Packit |
6ef888 |
if (o >= (rgd->bits->bi_start +
|
|
Packit |
6ef888 |
rgd->bits->bi_len) *
|
|
Packit |
6ef888 |
GFS2_NBBY)
|
|
Packit |
6ef888 |
o += (sizeof(struct gfs2_rgrp) -
|
|
Packit |
6ef888 |
sizeof(struct gfs2_meta_header))
|
|
Packit |
6ef888 |
* GFS2_NBBY;
|
|
Packit |
6ef888 |
bmap = o / sbd.sd_blocks_per_bitmap;
|
|
Packit |
6ef888 |
save_bh = rgd->bits[bmap].bi_bh;
|
|
Packit |
6ef888 |
j_bmap_bh = bread(&sbd, abs_block +
|
|
Packit |
6ef888 |
bcount);
|
|
Packit |
6ef888 |
rgd->bits[bmap].bi_bh = j_bmap_bh;
|
|
Packit |
6ef888 |
type = lgfs2_get_bitmap(&sbd, tblk, rgd);
|
|
Packit |
6ef888 |
brelse(j_bmap_bh);
|
|
Packit |
6ef888 |
if (type < 0) {
|
|
Packit |
6ef888 |
perror("Error printing log descriptor blocks");
|
|
Packit |
6ef888 |
exit(1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
rgd->bits[bmap].bi_bh = save_bh;
|
|
Packit |
6ef888 |
print_gfs2("bit for blk 0x%llx is %d "
|
|
Packit |
6ef888 |
"(%s)",
|
|
Packit |
6ef888 |
(unsigned long long)tblk,
|
|
Packit |
6ef888 |
type,
|
|
Packit |
6ef888 |
allocdesc[sbd.gfs1][type]);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
print_gfs2("bitmap for blk 0x%llx "
|
|
Packit |
6ef888 |
"was revoked",
|
|
Packit |
6ef888 |
(unsigned long long)tblk);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
eol(18 * (bcount % 4) + 1);
|
|
Packit |
6ef888 |
print_gfs2(" ");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
b++;
|
|
Packit |
6ef888 |
if (sbd.gfs1)
|
|
Packit |
6ef888 |
b++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (prnt)
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
if (tblk_off && (!found_tblk || !is_meta_ld))
|
|
Packit |
6ef888 |
*tblk_off = 0;
|
|
Packit |
6ef888 |
if (bblk_off && (!found_bblk || !is_meta_ld))
|
|
Packit |
6ef888 |
*bblk_off = 0;
|
|
Packit |
6ef888 |
return bcount;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static int is_wrap_pt(char *buf, uint64_t *highest_seq)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_buffer_head tbh = { .b_data = buf };
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (get_block_type(&tbh, NULL) == GFS2_METATYPE_LH) {
|
|
Packit |
6ef888 |
uint64_t seq;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sbd.gfs1) {
|
|
Packit |
6ef888 |
struct gfs_log_header lh;
|
|
Packit |
6ef888 |
gfs_log_header_in(&lh, &tbh;;
|
|
Packit |
6ef888 |
seq = lh.lh_sequence;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
struct gfs2_log_header lh;
|
|
Packit |
6ef888 |
gfs2_log_header_in(&lh, buf);
|
|
Packit |
6ef888 |
seq = lh.lh_sequence;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (seq < *highest_seq)
|
|
Packit |
6ef888 |
return 1;
|
|
Packit |
6ef888 |
*highest_seq = seq;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* find_wrap_pt - figure out where a journal wraps
|
|
Packit |
6ef888 |
* Returns: The wrap point, in bytes
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t find_wrap_pt(struct gfs2_inode *ji, char *jbuf, uint64_t jblock, uint64_t j_size)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t jb = 0;
|
|
Packit |
6ef888 |
uint64_t highest_seq = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1 : sbd.bsize)) {
|
|
Packit |
6ef888 |
int found = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sbd.gfs1) {
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *j_bh;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
j_bh = bread(&sbd, jblock + jb);
|
|
Packit |
6ef888 |
found = is_wrap_pt(j_bh->b_data, &highest_seq);
|
|
Packit |
6ef888 |
brelse(j_bh);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
int copied;
|
|
Packit |
6ef888 |
uint64_t abs_block;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
copied = fsck_readi(ji, jbuf, jb, sbd.bsize, &abs_block);
|
|
Packit |
6ef888 |
if (!copied) /* end of file */
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
found = is_wrap_pt(jbuf, &highest_seq);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (found)
|
|
Packit |
6ef888 |
return jb;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* process_ld - process a log descriptor
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int process_ld(uint64_t abs_block, uint64_t wrappt, uint64_t j_size,
|
|
Packit |
6ef888 |
uint64_t jb, char *buf, int tblk,
|
|
Packit |
6ef888 |
uint64_t *tblk_off, uint64_t bitblk,
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd, int *prnt, uint64_t *bblk_off)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
uint64_t *b;
|
|
Packit |
6ef888 |
struct gfs2_log_descriptor ld;
|
|
Packit |
6ef888 |
int ltndx, is_meta_ld = 0;
|
|
Packit |
6ef888 |
int ld_blocks = 0;
|
|
Packit |
6ef888 |
uint32_t logtypes[2][6] = {
|
|
Packit |
6ef888 |
{GFS2_LOG_DESC_METADATA, GFS2_LOG_DESC_REVOKE,
|
|
Packit |
6ef888 |
GFS2_LOG_DESC_JDATA, 0, 0, 0},
|
|
Packit |
6ef888 |
{GFS_LOG_DESC_METADATA, GFS_LOG_DESC_IUL, GFS_LOG_DESC_IDA,
|
|
Packit |
6ef888 |
GFS_LOG_DESC_Q, GFS_LOG_DESC_LAST, 0}};
|
|
Packit |
6ef888 |
const char *logtypestr[2][6] = {
|
|
Packit |
6ef888 |
{"Metadata", "Revoke", "Jdata",
|
|
Packit |
6ef888 |
"Unknown", "Unknown", "Unknown"},
|
|
Packit |
6ef888 |
{"Metadata", "Unlinked inode", "Dealloc inode",
|
|
Packit |
6ef888 |
"Quota", "Final Entry", "Unknown"}};
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
gfs2_log_descriptor_in(&ld, buf);
|
|
Packit |
6ef888 |
if (sbd.gfs1)
|
|
Packit |
6ef888 |
b = (uint64_t *)(buf + sizeof(struct gfs_log_descriptor));
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
b = (uint64_t *)(buf + sizeof(struct gfs2_log_descriptor));
|
|
Packit |
6ef888 |
*prnt = ld_is_pertinent(b, (buf + sbd.bsize), tblk, rgd, bitblk);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (*prnt) {
|
|
Packit |
6ef888 |
print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log descriptor, ",
|
|
Packit |
6ef888 |
abs_block, ((jb + wrappt) % j_size) / sbd.bsize);
|
|
Packit |
6ef888 |
print_gfs2("type %d ", ld.ld_type);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (ltndx = 0;; ltndx++) {
|
|
Packit |
6ef888 |
if (ld.ld_type == logtypes[sbd.gfs1][ltndx] ||
|
|
Packit |
6ef888 |
logtypes[sbd.gfs1][ltndx] == 0)
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
print_gfs2("(%s) ", logtypestr[sbd.gfs1][ltndx]);
|
|
Packit |
6ef888 |
print_gfs2("len:%u, data1: %u", ld.ld_length, ld.ld_data1);
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
print_gfs2(" ");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
ld_blocks = ld.ld_data1;
|
|
Packit |
6ef888 |
if (ld.ld_type == GFS2_LOG_DESC_METADATA ||
|
|
Packit |
6ef888 |
ld.ld_type == GFS_LOG_DESC_METADATA)
|
|
Packit |
6ef888 |
is_meta_ld = 1;
|
|
Packit |
6ef888 |
ld_blocks -= print_ld_blks(b, (buf + sbd.bsize), line, tblk, tblk_off,
|
|
Packit |
6ef888 |
bitblk, rgd, abs_block, *prnt, bblk_off,
|
|
Packit |
6ef888 |
is_meta_ld);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
return ld_blocks;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* meta_has_ref - check if a metadata block references a given block
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static int meta_has_ref(uint64_t abs_block, int tblk)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *mbh;
|
|
Packit |
6ef888 |
int structlen, ty, has_ref = 0;
|
|
Packit |
6ef888 |
uint64_t *b;
|
|
Packit |
6ef888 |
struct gfs2_dinode *dinode;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
mbh = bread(&sbd, abs_block);
|
|
Packit |
6ef888 |
ty = get_block_type(mbh, &structlen);
|
|
Packit |
6ef888 |
if (ty == GFS2_METATYPE_DI) {
|
|
Packit |
6ef888 |
dinode = (struct gfs2_dinode *)mbh->b_data;
|
|
Packit |
6ef888 |
if (be64_to_cpu(dinode->di_eattr) == tblk)
|
|
Packit |
6ef888 |
has_ref = 1;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
b = (uint64_t *)(mbh->b_data + structlen);
|
|
Packit |
6ef888 |
while (!has_ref && ty && (char *)b < mbh->b_data + sbd.bsize) {
|
|
Packit |
6ef888 |
if (be64_to_cpu(*b) == tblk)
|
|
Packit |
6ef888 |
has_ref = 1;
|
|
Packit |
6ef888 |
b++;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
brelse(mbh);
|
|
Packit |
6ef888 |
return has_ref;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* get_ldref - get a log descriptor reference block, given a block number
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Note that we can't pass in abs_block here, because journal wrap may
|
|
Packit |
6ef888 |
* mean that the block we're interested in, in the journal, is before the
|
|
Packit |
6ef888 |
* log descriptor that holds the reference we need.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
static uint64_t get_ldref(uint64_t abs_ld, int offset_from_ld)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *jbh;
|
|
Packit |
6ef888 |
uint64_t *b, refblk;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
jbh = bread(&sbd, abs_ld);
|
|
Packit |
6ef888 |
b = (uint64_t *)(jbh->b_data + sizeof(struct gfs2_log_descriptor));
|
|
Packit |
6ef888 |
b += offset_from_ld - 1;
|
|
Packit |
6ef888 |
refblk = be64_to_cpu(*b);
|
|
Packit |
6ef888 |
brelse(jbh);
|
|
Packit |
6ef888 |
return refblk;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/**
|
|
Packit |
6ef888 |
* dump_journal - dump a journal file's contents.
|
|
Packit |
6ef888 |
* @journal: name of the journal to dump
|
|
Packit |
6ef888 |
* @tblk: block number to trace in the journals
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function dumps the contents of a journal. If a trace block is specified
|
|
Packit |
6ef888 |
* then only information printed is: (1) log descriptors that reference that
|
|
Packit |
6ef888 |
* block, (2) metadata in the journal that references the block, or (3)
|
|
Packit |
6ef888 |
* rgrp bitmaps that reference that block's allocation bit status.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
void dump_journal(const char *journal, int tblk)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct gfs2_buffer_head *j_bh = NULL, dummy_bh;
|
|
Packit |
6ef888 |
uint64_t jblock, j_size, jb, abs_block, saveblk, wrappt = 0;
|
|
Packit |
6ef888 |
int start_line, journal_num;
|
|
Packit |
6ef888 |
struct gfs2_inode *j_inode = NULL;
|
|
Packit |
6ef888 |
int ld_blocks = 0, offset_from_ld = 0;
|
|
Packit |
6ef888 |
uint64_t tblk_off = 0, bblk_off = 0, bitblk = 0;
|
|
Packit |
6ef888 |
uint64_t highest_seq = 0;
|
|
Packit |
6ef888 |
char *jbuf = NULL;
|
|
Packit |
6ef888 |
struct rgrp_tree *rgd = NULL;
|
|
Packit |
6ef888 |
uint64_t abs_ld = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
start_line = line;
|
|
Packit |
6ef888 |
lines_per_row[dmode] = 1;
|
|
Packit |
6ef888 |
journal_num = atoi(journal + 7);
|
|
Packit |
6ef888 |
print_gfs2("Dumping journal #%d.", journal_num);
|
|
Packit |
6ef888 |
if (tblk) {
|
|
Packit |
6ef888 |
dmode = HEX_MODE;
|
|
Packit |
6ef888 |
print_gfs2(" Tracing block 0x%llx", (unsigned long long)tblk);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
jblock = find_journal_block(journal, &j_size);
|
|
Packit |
6ef888 |
if (!jblock)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (!sbd.gfs1) {
|
|
Packit |
6ef888 |
j_bh = bread(&sbd, jblock);
|
|
Packit |
6ef888 |
j_inode = lgfs2_inode_get(&sbd, j_bh);
|
|
Packit |
6ef888 |
if (j_inode == NULL) {
|
|
Packit |
6ef888 |
fprintf(stderr, "Out of memory\n");
|
|
Packit |
6ef888 |
exit(-1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
jbuf = malloc(sbd.bsize);
|
|
Packit |
6ef888 |
if (jbuf == NULL) {
|
|
Packit |
6ef888 |
fprintf(stderr, "Out of memory\n");
|
|
Packit |
6ef888 |
exit(-1);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (tblk) {
|
|
Packit |
6ef888 |
uint64_t wp;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
rgd = gfs2_blk2rgrpd(&sbd, tblk);
|
|
Packit |
6ef888 |
if (!rgd) {
|
|
Packit |
6ef888 |
print_gfs2("Can't locate the rgrp for block 0x%x",
|
|
Packit |
6ef888 |
tblk);
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
uint64_t o;
|
|
Packit |
6ef888 |
int bmap = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
print_gfs2("rgd: 0x%llx for 0x%x, ", rgd->ri.ri_addr,
|
|
Packit |
6ef888 |
rgd->ri.ri_length);
|
|
Packit |
6ef888 |
o = tblk - rgd->ri.ri_data0;
|
|
Packit |
6ef888 |
if (o >= (rgd->bits->bi_start +
|
|
Packit |
6ef888 |
rgd->bits->bi_len) * (uint64_t)GFS2_NBBY)
|
|
Packit |
6ef888 |
o += (sizeof(struct gfs2_rgrp) -
|
|
Packit |
6ef888 |
sizeof(struct gfs2_meta_header))
|
|
Packit |
6ef888 |
* GFS2_NBBY;
|
|
Packit |
6ef888 |
bmap = o / sbd.sd_blocks_per_bitmap;
|
|
Packit |
6ef888 |
bitblk = rgd->ri.ri_addr + bmap;
|
|
Packit |
6ef888 |
print_gfs2("bitmap: %d, bitblk: 0x%llx", bmap,
|
|
Packit |
6ef888 |
(unsigned long long)bitblk);
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
wrappt = find_wrap_pt(j_inode, jbuf, jblock, j_size);
|
|
Packit |
6ef888 |
wp = wrappt / (sbd.gfs1 ? 1 : sbd.bsize);
|
|
Packit |
6ef888 |
print_gfs2("Starting at journal wrap block: 0x%llx "
|
|
Packit |
6ef888 |
"(j + 0x%llx)",
|
|
Packit |
6ef888 |
(unsigned long long)jblock + wp,
|
|
Packit |
6ef888 |
(unsigned long long)wp);
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1 : sbd.bsize)) {
|
|
Packit |
6ef888 |
int is_pertinent = 1;
|
|
Packit |
6ef888 |
uint32_t block_type = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sbd.gfs1) {
|
|
Packit |
6ef888 |
if (j_bh)
|
|
Packit |
6ef888 |
brelse(j_bh);
|
|
Packit |
6ef888 |
abs_block = jblock + ((jb + wrappt) % j_size);
|
|
Packit |
6ef888 |
j_bh = bread(&sbd, abs_block);
|
|
Packit |
6ef888 |
dummy_bh.b_data = j_bh->b_data;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
int error = fsck_readi(j_inode, (void *)jbuf,
|
|
Packit |
6ef888 |
((jb + wrappt) % j_size),
|
|
Packit |
6ef888 |
sbd.bsize, &abs_block);
|
|
Packit |
6ef888 |
if (!error) /* end of file */
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
dummy_bh.b_data = jbuf;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
offset_from_ld++;
|
|
Packit |
6ef888 |
block_type = get_block_type(&dummy_bh, NULL);
|
|
Packit |
6ef888 |
if (block_type == GFS2_METATYPE_LD) {
|
|
Packit |
6ef888 |
ld_blocks = process_ld(abs_block, wrappt, j_size, jb,
|
|
Packit |
6ef888 |
dummy_bh.b_data, tblk, &tblk_off,
|
|
Packit |
6ef888 |
bitblk, rgd, &is_pertinent,
|
|
Packit |
6ef888 |
&bblk_off);
|
|
Packit |
6ef888 |
offset_from_ld = 0;
|
|
Packit |
6ef888 |
abs_ld = abs_block;
|
|
Packit |
6ef888 |
} else if (!tblk && block_type == GFS2_METATYPE_LH) {
|
|
Packit |
6ef888 |
struct gfs2_log_header lh;
|
|
Packit |
6ef888 |
struct gfs_log_header lh1;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sbd.gfs1) {
|
|
Packit |
6ef888 |
gfs_log_header_in(&lh1, &dummy_bh);
|
|
Packit |
6ef888 |
check_journal_wrap(lh1.lh_sequence,
|
|
Packit |
6ef888 |
&highest_seq);
|
|
Packit |
6ef888 |
print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log header: "
|
|
Packit |
6ef888 |
"Flags:%x, Seq: 0x%llx, 1st: 0x%llx, "
|
|
Packit |
6ef888 |
"tail: 0x%llx, last: 0x%llx",
|
|
Packit |
6ef888 |
abs_block, jb + wrappt,
|
|
Packit |
6ef888 |
lh1.lh_flags, lh1.lh_sequence,
|
|
Packit |
6ef888 |
lh1.lh_first, lh1.lh_tail,
|
|
Packit |
6ef888 |
lh1.lh_last_dump);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
gfs2_log_header_in(&lh, dummy_bh.b_data);
|
|
Packit |
6ef888 |
check_journal_wrap(lh.lh_sequence,
|
|
Packit |
6ef888 |
&highest_seq);
|
|
Packit |
6ef888 |
print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log header: Seq"
|
|
Packit |
6ef888 |
": 0x%llx, tail: 0x%x, blk: 0x%x%s",
|
|
Packit |
6ef888 |
abs_block, ((jb + wrappt) % j_size)
|
|
Packit |
6ef888 |
/ sbd.bsize, lh.lh_sequence,
|
|
Packit |
6ef888 |
lh.lh_tail, lh.lh_blkno,
|
|
Packit |
6ef888 |
lh.lh_flags ==
|
|
Packit |
6ef888 |
GFS2_LOG_HEAD_UNMOUNT ?
|
|
Packit |
6ef888 |
" [UNMOUNTED]" : "");
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
} else if ((ld_blocks > 0) &&
|
|
Packit |
6ef888 |
(sbd.gfs1 || block_type == GFS2_METATYPE_LB)) {
|
|
Packit |
6ef888 |
print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log descriptor"
|
|
Packit |
6ef888 |
" continuation block", abs_block,
|
|
Packit |
6ef888 |
((jb + wrappt) % j_size) / sbd.bsize);
|
|
Packit |
6ef888 |
eol(0);
|
|
Packit |
6ef888 |
print_gfs2(" ");
|
|
Packit |
6ef888 |
ld_blocks -= print_ld_blks((uint64_t *)dummy_bh.b_data +
|
|
Packit |
6ef888 |
(sbd.gfs1 ? 0 :
|
|
Packit |
6ef888 |
sizeof(struct gfs2_meta_header)),
|
|
Packit |
6ef888 |
(dummy_bh.b_data +
|
|
Packit |
6ef888 |
sbd.bsize), start_line,
|
|
Packit |
6ef888 |
tblk, &tblk_off, 0, rgd,
|
|
Packit |
6ef888 |
0, 1, NULL, 0);
|
|
Packit |
6ef888 |
} else if (block_type == 0) {
|
|
Packit |
6ef888 |
continue;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
/* Check if this metadata block references the block we're
|
|
Packit |
6ef888 |
trying to trace. */
|
|
Packit |
6ef888 |
if (details || (tblk && ((is_pertinent &&
|
|
Packit |
6ef888 |
((tblk_off && offset_from_ld == tblk_off) ||
|
|
Packit |
6ef888 |
(bblk_off && offset_from_ld == bblk_off))) ||
|
|
Packit |
6ef888 |
meta_has_ref(abs_block, tblk)))) {
|
|
Packit |
6ef888 |
uint64_t ref_blk = 0;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
saveblk = block;
|
|
Packit |
6ef888 |
block = abs_block;
|
|
Packit |
6ef888 |
if (tblk && !details) {
|
|
Packit |
6ef888 |
ref_blk = get_ldref(abs_ld, offset_from_ld);
|
|
Packit |
6ef888 |
display(0, 1, tblk, ref_blk);
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
display(0, 0, 0, 0);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
block = saveblk;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (j_inode != NULL)
|
|
Packit |
6ef888 |
inode_put(&j_inode);
|
|
Packit |
6ef888 |
brelse(j_bh);
|
|
Packit |
6ef888 |
blockhist = -1; /* So we don't print anything else */
|
|
Packit |
6ef888 |
free(jbuf);
|
|
Packit |
6ef888 |
if (!termlines)
|
|
Packit |
6ef888 |
fflush(stdout);
|
|
Packit |
6ef888 |
}
|