blob: cdaf77bf976c185cbbd5c47ae685088fcdb85645 [file] [log] [blame]
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libxfs.h"
#include "libxlog.h"
#include "logprint.h"
/*
* Start is defined to be the block pointing to the oldest valid log record.
*/
int
xlog_print_find_oldest(
struct xlog *log,
xfs_daddr_t *last_blk)
{
xfs_buf_t *bp;
xfs_daddr_t first_blk;
uint first_half_cycle, last_half_cycle;
int error = 0;
if (xlog_find_zeroed(log, &first_blk))
return 0;
first_blk = 0; /* read first block */
bp = xlog_get_bp(log, 1);
xlog_bread_noalign(log, 0, 1, bp);
first_half_cycle = xlog_get_cycle(XFS_BUF_PTR(bp));
*last_blk = log->l_logBBsize-1; /* read last block */
xlog_bread_noalign(log, *last_blk, 1, bp);
last_half_cycle = xlog_get_cycle(XFS_BUF_PTR(bp));
ASSERT(last_half_cycle != 0);
if (first_half_cycle == last_half_cycle) /* all cycle nos are same */
*last_blk = 0;
else /* have 1st and last; look for middle cycle */
error = xlog_find_cycle_start(log, bp, first_blk,
last_blk, last_half_cycle);
xlog_put_bp(bp);
return error;
}
void
xlog_recover_print_data(
char *p,
int len)
{
if (print_data) {
uint *dp = (uint *)p;
int nums = len >> 2;
int j = 0;
while (j < nums) {
if ((j % 8) == 0)
printf("%2x ", j);
printf("%8x ", *dp);
dp++;
j++;
if ((j % 8) == 0)
printf("\n");
}
printf("\n");
}
}
STATIC void
xlog_recover_print_buffer(
xlog_recover_item_t *item)
{
xfs_agi_t *agi;
xfs_agf_t *agf;
xfs_buf_log_format_t *f;
char *p;
int len, num, i;
xfs_daddr_t blkno;
xfs_disk_dquot_t *ddq;
f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
printf(" ");
ASSERT(f->blf_type == XFS_LI_BUF);
printf(_("BUF: #regs:%d start blkno:0x%llx len:%d bmap size:%d flags:0x%x\n"),
f->blf_size, (long long)f->blf_blkno, f->blf_len, f->blf_map_size, f->blf_flags);
blkno = (xfs_daddr_t)f->blf_blkno;
num = f->blf_size-1;
i = 1;
while (num-- > 0) {
p = item->ri_buf[i].i_addr;
len = item->ri_buf[i].i_len;
i++;
if (blkno == 0) { /* super block */
printf(_(" SUPER Block Buffer:\n"));
if (!print_buffer)
continue;
printf(_(" icount:%llu ifree:%llu "),
(unsigned long long)
be64_to_cpu(*(__be64 *)(p)),
(unsigned long long)
be64_to_cpu(*(__be64 *)(p+8)));
printf(_("fdblks:%llu frext:%llu\n"),
(unsigned long long)
be64_to_cpu(*(__be64 *)(p+16)),
(unsigned long long)
be64_to_cpu(*(__be64 *)(p+24)));
printf(_(" sunit:%u swidth:%u\n"),
be32_to_cpu(*(__be32 *)(p+56)),
be32_to_cpu(*(__be32 *)(p+60)));
} else if (be32_to_cpu(*(__be32 *)p) == XFS_AGI_MAGIC) {
int bucket, buckets;
agi = (xfs_agi_t *)p;
printf(_(" AGI Buffer: (XAGI)\n"));
if (!print_buffer)
continue;
printf(_(" ver:%d "),
be32_to_cpu(agi->agi_versionnum));
printf(_("seq#:%d len:%d cnt:%d root:%d\n"),
be32_to_cpu(agi->agi_seqno),
be32_to_cpu(agi->agi_length),
be32_to_cpu(agi->agi_count),
be32_to_cpu(agi->agi_root));
printf(_(" level:%d free#:0x%x newino:0x%x\n"),
be32_to_cpu(agi->agi_level),
be32_to_cpu(agi->agi_freecount),
be32_to_cpu(agi->agi_newino));
if (len == 128) {
buckets = 17;
} else if (len == 256) {
buckets = 32 + 17;
} else {
buckets = XFS_AGI_UNLINKED_BUCKETS;
}
for (bucket = 0; bucket < buckets;) {
int col;
printf(_("bucket[%d - %d]: "), bucket, bucket+3);
for (col = 0; col < 4; col++, bucket++) {
if (bucket < buckets) {
printf("0x%x ",
be32_to_cpu(agi->agi_unlinked[bucket]));
}
}
printf("\n");
}
} else if (be32_to_cpu(*(__be32 *)p) == XFS_AGF_MAGIC) {
agf = (xfs_agf_t *)p;
printf(_(" AGF Buffer: (XAGF)\n"));
if (!print_buffer)
continue;
printf(_(" ver:%d seq#:%d len:%d \n"),
be32_to_cpu(agf->agf_versionnum),
be32_to_cpu(agf->agf_seqno),
be32_to_cpu(agf->agf_length));
printf(_(" root BNO:%d CNT:%d\n"),
be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]),
be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi]));
printf(_(" level BNO:%d CNT:%d\n"),
be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]),
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]));
printf(_(" 1st:%d last:%d cnt:%d "
"freeblks:%d longest:%d\n"),
be32_to_cpu(agf->agf_flfirst),
be32_to_cpu(agf->agf_fllast),
be32_to_cpu(agf->agf_flcount),
be32_to_cpu(agf->agf_freeblks),
be32_to_cpu(agf->agf_longest));
} else if (*(uint *)p == XFS_DQUOT_MAGIC) {
ddq = (xfs_disk_dquot_t *)p;
printf(_(" DQUOT Buffer:\n"));
if (!print_buffer)
continue;
printf(_(" UIDs 0x%lx-0x%lx\n"),
(unsigned long)be32_to_cpu(ddq->d_id),
(unsigned long)be32_to_cpu(ddq->d_id) +
(BBTOB(f->blf_len) / sizeof(xfs_dqblk_t)) - 1);
} else {
printf(_(" BUF DATA\n"));
if (!print_buffer) continue;
xlog_recover_print_data(p, len);
}
}
}
STATIC void
xlog_recover_print_quotaoff(
xlog_recover_item_t *item)
{
xfs_qoff_logformat_t *qoff_f;
char str[32] = { 0 };
qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr;
ASSERT(qoff_f);
if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
strcat(str, "USER QUOTA");
if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
strcat(str, "GROUP QUOTA");
if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
strcat(str, "PROJECT QUOTA");
printf(_("\tQUOTAOFF: #regs:%d type:%s\n"),
qoff_f->qf_size, str);
}
STATIC void
xlog_recover_print_dquot(
xlog_recover_item_t *item)
{
xfs_dq_logformat_t *f;
xfs_disk_dquot_t *d;
f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr;
ASSERT(f);
ASSERT(f->qlf_len == 1);
d = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr;
printf(_("\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n"),
f->qlf_size, (long long)f->qlf_blkno, f->qlf_boffset, f->qlf_id);
if (!print_quota)
return;
printf(_("\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n"),
be16_to_cpu(d->d_magic),
d->d_version,
be32_to_cpu(d->d_id),
be32_to_cpu(d->d_id));
printf(_("\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x"
"\tino_soft 0x%x\n"),
(int)be64_to_cpu(d->d_blk_hardlimit),
(int)be64_to_cpu(d->d_blk_softlimit),
(int)be64_to_cpu(d->d_ino_hardlimit),
(int)be64_to_cpu(d->d_ino_softlimit));
printf(_("\t\tbcount 0x%x (%d) icount 0x%x (%d)\n"),
(int)be64_to_cpu(d->d_bcount),
(int)be64_to_cpu(d->d_bcount),
(int)be64_to_cpu(d->d_icount),
(int)be64_to_cpu(d->d_icount));
printf(_("\t\tbtimer 0x%x itimer 0x%x \n"),
(int)be32_to_cpu(d->d_btimer),
(int)be32_to_cpu(d->d_itimer));
}
STATIC void
xlog_recover_print_inode_core(
struct xfs_log_dinode *di)
{
printf(_(" CORE inode:\n"));
if (!print_inode)
return;
printf(_(" magic:%c%c mode:0x%x ver:%d format:%d\n"),
(di->di_magic>>8) & 0xff, di->di_magic & 0xff,
di->di_mode, di->di_version, di->di_format);
printf(_(" uid:%d gid:%d nlink:%d projid:0x%04x%04x\n"),
di->di_uid, di->di_gid, di->di_nlink,
di->di_projid_hi, di->di_projid_lo);
printf(_(" atime:%d mtime:%d ctime:%d\n"),
di->di_atime.t_sec, di->di_mtime.t_sec, di->di_ctime.t_sec);
printf(_(" flushiter:%d\n"), di->di_flushiter);
printf(_(" size:0x%llx nblks:0x%llx exsize:%d "
"nextents:%d anextents:%d\n"), (unsigned long long)
di->di_size, (unsigned long long)di->di_nblocks,
di->di_extsize, di->di_nextents, (int)di->di_anextents);
printf(_(" forkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x "
"gen:%u\n"),
(int)di->di_forkoff, di->di_dmevmask, (int)di->di_dmstate,
(int)di->di_flags, di->di_gen);
if (di->di_version == 3) {
printf(_(" flags2 0x%llx cowextsize 0x%x\n"),
(unsigned long long)di->di_flags2, di->di_cowextsize);
}
}
STATIC void
xlog_recover_print_inode(
xlog_recover_item_t *item)
{
struct xfs_inode_log_format f_buf;
struct xfs_inode_log_format *f;
int attr_index;
int hasdata;
int hasattr;
ASSERT(item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format_32) ||
item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format));
f = xfs_inode_item_format_convert(item->ri_buf[0].i_addr, item->ri_buf[0].i_len, &f_buf);
printf(_(" INODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n"),
f->ilf_size, (unsigned long long)f->ilf_ino, f->ilf_fields,
f->ilf_dsize);
/* core inode comes 2nd */
ASSERT(item->ri_buf[1].i_len == xfs_log_dinode_size(2) ||
item->ri_buf[1].i_len == xfs_log_dinode_size(3));
xlog_recover_print_inode_core((struct xfs_log_dinode *)
item->ri_buf[1].i_addr);
hasdata = (f->ilf_fields & XFS_ILOG_DFORK) != 0;
hasattr = (f->ilf_fields & XFS_ILOG_AFORK) != 0;
/* does anything come next */
switch (f->ilf_fields & (XFS_ILOG_DFORK|XFS_ILOG_DEV|XFS_ILOG_UUID)) {
case XFS_ILOG_DEXT:
ASSERT(f->ilf_size == 3 + hasattr);
printf(_(" DATA FORK EXTENTS inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(item->ri_buf[2].i_addr,
item->ri_buf[2].i_len);
break;
case XFS_ILOG_DBROOT:
ASSERT(f->ilf_size == 3 + hasattr);
printf(_(" DATA FORK BTREE inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(item->ri_buf[2].i_addr,
item->ri_buf[2].i_len);
break;
case XFS_ILOG_DDATA:
ASSERT(f->ilf_size == 3 + hasattr);
printf(_(" DATA FORK LOCAL inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(item->ri_buf[2].i_addr,
item->ri_buf[2].i_len);
break;
case XFS_ILOG_DEV:
ASSERT(f->ilf_size == 2 + hasattr);
printf(_(" DEV inode: no extra region\n"));
break;
case XFS_ILOG_UUID:
ASSERT(f->ilf_size == 2 + hasattr);
printf(_(" UUID inode: no extra region\n"));
break;
case 0:
ASSERT(f->ilf_size == 2 + hasattr);
break;
default:
xlog_panic("xlog_print_trans_inode: illegal inode type");
}
if (hasattr) {
attr_index = 2 + hasdata;
switch (f->ilf_fields & XFS_ILOG_AFORK) {
case XFS_ILOG_AEXT:
ASSERT(f->ilf_size == 3 + hasdata);
printf(_(" ATTR FORK EXTENTS inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(
item->ri_buf[attr_index].i_addr,
item->ri_buf[attr_index].i_len);
break;
case XFS_ILOG_ABROOT:
ASSERT(f->ilf_size == 3 + hasdata);
printf(_(" ATTR FORK BTREE inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(
item->ri_buf[attr_index].i_addr,
item->ri_buf[attr_index].i_len);
break;
case XFS_ILOG_ADATA:
ASSERT(f->ilf_size == 3 + hasdata);
printf(_(" ATTR FORK LOCAL inode data:\n"));
if (print_inode && print_data)
xlog_recover_print_data(
item->ri_buf[attr_index].i_addr,
item->ri_buf[attr_index].i_len);
break;
default:
xlog_panic("%s: illegal inode log flag", __FUNCTION__);
}
}
}
STATIC void
xlog_recover_print_icreate(
struct xlog_recover_item *item)
{
struct xfs_icreate_log *icl;
icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr;
printf(_(" ICR: #ag: %d agbno: 0x%x len: %d\n"
" cnt: %d isize: %d gen: 0x%x\n"),
be32_to_cpu(icl->icl_ag), be32_to_cpu(icl->icl_agbno),
be32_to_cpu(icl->icl_length), be32_to_cpu(icl->icl_count),
be32_to_cpu(icl->icl_isize), be32_to_cpu(icl->icl_gen));
}
void
xlog_recover_print_logitem(
xlog_recover_item_t *item)
{
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF:
xlog_recover_print_buffer(item);
break;
case XFS_LI_ICREATE:
xlog_recover_print_icreate(item);
break;
case XFS_LI_INODE:
xlog_recover_print_inode(item);
break;
case XFS_LI_EFD:
xlog_recover_print_efd(item);
break;
case XFS_LI_EFI:
xlog_recover_print_efi(item);
break;
case XFS_LI_RUD:
xlog_recover_print_rud(item);
break;
case XFS_LI_RUI:
xlog_recover_print_rui(item);
break;
case XFS_LI_CUD:
xlog_recover_print_cud(item);
break;
case XFS_LI_CUI:
xlog_recover_print_cui(item);
break;
case XFS_LI_BUD:
xlog_recover_print_bud(item);
break;
case XFS_LI_BUI:
xlog_recover_print_bui(item);
break;
case XFS_LI_DQUOT:
xlog_recover_print_dquot(item);
break;
case XFS_LI_QUOTAOFF:
xlog_recover_print_quotaoff(item);
break;
default:
printf(_("xlog_recover_print_logitem: illegal type\n"));
break;
}
}
void
xlog_recover_print_item(
xlog_recover_item_t *item)
{
int i;
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF:
printf("BUF");
break;
case XFS_LI_ICREATE:
printf("ICR");
break;
case XFS_LI_INODE:
printf("INO");
break;
case XFS_LI_EFD:
printf("EFD");
break;
case XFS_LI_EFI:
printf("EFI");
break;
case XFS_LI_RUD:
printf("RUD");
break;
case XFS_LI_RUI:
printf("RUI");
break;
case XFS_LI_CUD:
printf("CUD");
break;
case XFS_LI_CUI:
printf("CUI");
break;
case XFS_LI_BUD:
printf("BUD");
break;
case XFS_LI_BUI:
printf("BUI");
break;
case XFS_LI_DQUOT:
printf("DQ ");
break;
case XFS_LI_QUOTAOFF:
printf("QOFF");
break;
default:
cmn_err(CE_PANIC, _("%s: illegal type"), __FUNCTION__);
break;
}
/* type isn't filled in yet
printf(_("ITEM: type: %d cnt: %d total: %d "),
item->ri_type, item->ri_cnt, item->ri_total);
*/
printf(_(": cnt:%d total:%d "), item->ri_cnt, item->ri_total);
for (i=0; i<item->ri_cnt; i++) {
printf(_("a:0x%lx len:%d "),
(long)item->ri_buf[i].i_addr, item->ri_buf[i].i_len);
}
printf("\n");
xlog_recover_print_logitem(item);
}
void
xlog_recover_print_trans(
xlog_recover_t *trans,
struct list_head *itemq,
int print)
{
xlog_recover_item_t *item;
if (print < 3)
return;
print_xlog_record_line();
xlog_recover_print_trans_head(trans);
list_for_each_entry(item, itemq, ri_list)
xlog_recover_print_item(item);
}