File: [Development] / xfs-cmds / xfsprogs / logprint / log_misc.c (download)
Revision 1.9, Tue Jun 4 22:53:09 2002 UTC (15 years, 4 months ago) by sandeen
Branch: MAIN
Changes since 1.8: +1 -1
lines
Undoes mod: xfs-cmds:slinx:120772a
Undo xfs-cmds:slinx:120772a, inadvertently whacked a previous mod.
|
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 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.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#include "logprint.h"
#define ZEROED_LOG (-4)
#define FULL_READ (-3)
#define PARTIAL_READ (-2)
#define BAD_HEADER (-1)
#define NO_ERROR (0)
static int logBBsize;
char *trans_type[] = {
"",
"SETATTR",
"SETATTR_SIZE",
"INACTIVE",
"CREATE",
"CREATE_TRUNC",
"TRUNCATE_FILE",
"REMOVE",
"LINK",
"RENAME",
"MKDIR",
"RMDIR",
"SYMLINK",
"SET_DMATTRS",
"GROWFS",
"STRAT_WRITE",
"DIOSTRAT",
"WRITE_SYNC",
"WRITEID",
"ADDAFORK",
"ATTRINVAL",
"ATRUNCATE",
"ATTR_SET",
"ATTR_RM",
"ATTR_FLAG",
"CLEAR_AGI_BUCKET",
"QM_SBCHANGE",
"DUMMY1",
"DUMMY2",
"QM_QUOTAOFF",
"QM_DQALLOC",
"QM_SETQLIM",
"QM_DQCLUSTER",
"QM_QINOCREATE",
"QM_QUOTAOFF_END",
"SB_UNIT",
"FSYNC_TS",
"GROWFSRT_ALLOC",
"GROWFSRT_ZERO",
"GROWFSRT_FREE",
"SWAPEXT",
};
typedef struct xlog_split_item {
struct xlog_split_item *si_next;
struct xlog_split_item *si_prev;
xlog_tid_t si_tid;
int si_skip;
} xlog_split_item_t;
xlog_split_item_t *split_list = 0;
void
print_xlog_op_line(void)
{
printf("--------------------------------------"
"--------------------------------------\n");
} /* print_xlog_op_line */
void
print_xlog_record_line(void)
{
printf("======================================"
"======================================\n");
} /* print_xlog_record_line */
void
print_stars(void)
{
printf("***********************************"
"***********************************\n");
} /* print_xlog_record_line */
/*
* Given a pointer to a data segment, print out the data as if it were
* a log operation header.
*/
void
xlog_print_op_header(xlog_op_header_t *op_head,
int i,
xfs_caddr_t *ptr)
{
xlog_op_header_t hbuf;
/*
* bcopy because on 64/n32, partial reads can cause the op_head
* pointer to come in pointing to an odd-numbered byte
*/
bcopy(op_head, &hbuf, sizeof(xlog_op_header_t));
op_head = &hbuf;
*ptr += sizeof(xlog_op_header_t);
printf("Oper (%d): tid: %x len: %d clientid: %s ", i,
INT_GET(op_head->oh_tid, ARCH_CONVERT),
INT_GET(op_head->oh_len, ARCH_CONVERT),
(op_head->oh_clientid == XFS_TRANSACTION ? "TRANS" :
(op_head->oh_clientid == XFS_LOG ? "LOG" : "ERROR")));
printf("flags: ");
if (op_head->oh_flags) {
if (op_head->oh_flags & XLOG_START_TRANS)
printf("START ");
if (op_head->oh_flags & XLOG_COMMIT_TRANS)
printf("COMMIT ");
if (op_head->oh_flags & XLOG_WAS_CONT_TRANS)
printf("WAS_CONT ");
if (op_head->oh_flags & XLOG_UNMOUNT_TRANS)
printf("UNMOUNT ");
if (op_head->oh_flags & XLOG_CONTINUE_TRANS)
printf("CONTINUE ");
if (op_head->oh_flags & XLOG_END_TRANS)
printf("END ");
} else {
printf("none");
}
printf("\n");
} /* xlog_print_op_header */
void
xlog_print_add_to_trans(xlog_tid_t tid,
int skip)
{
xlog_split_item_t *item;
item = (xlog_split_item_t *)calloc(sizeof(xlog_split_item_t), 1);
item->si_tid = tid;
item->si_skip = skip;
item->si_next = split_list;
item->si_prev = 0;
if (split_list)
split_list->si_prev = item;
split_list = item;
} /* xlog_print_add_to_trans */
int
xlog_print_find_tid(xlog_tid_t tid, uint was_cont)
{
xlog_split_item_t *listp = split_list;
if (!split_list) {
if (was_cont != 0) /* Not first time we have used this tid */
return 1;
else
return 0;
}
while (listp) {
if (listp->si_tid == tid)
break;
listp = listp->si_next;
}
if (!listp) {
return 0;
}
if (--listp->si_skip == 0) {
if (listp == split_list) { /* delete at head */
split_list = listp->si_next;
if (split_list)
split_list->si_prev = NULL;
} else {
if (listp->si_next)
listp->si_next->si_prev = listp->si_prev;
listp->si_prev->si_next = listp->si_next;
}
free(listp);
}
return 1;
} /* xlog_print_find_tid */
int
xlog_print_trans_header(xfs_caddr_t *ptr, int len)
{
xfs_trans_header_t *h;
xfs_caddr_t cptr = *ptr;
__uint32_t magic;
char *magic_c = (char *)&magic;
*ptr += len;
magic=*(__uint32_t*)cptr; /* XXX INT_GET soon */
if (len >= 4) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
printf("%c%c%c%c:",
magic_c[3], magic_c[2], magic_c[1], magic_c[0]);
#else
printf("%c%c%c%c:",
magic_c[0], magic_c[1], magic_c[2], magic_c[3]);
#endif
}
if (len != sizeof(xfs_trans_header_t)) {
printf(" Not enough data to decode further\n");
return 1;
}
h = (xfs_trans_header_t *)cptr;
printf(" type: %s tid: %x num_items: %d\n",
trans_type[h->th_type], h->th_tid, h->th_num_items);
return 0;
} /* xlog_print_trans_header */
int
xlog_print_trans_buffer(xfs_caddr_t *ptr, int len, int *i, int num_ops)
{
xfs_buf_log_format_t *f;
xfs_buf_log_format_v1_t *old_f;
xfs_agi_t *agi;
xfs_agf_t *agf;
xfs_disk_dquot_t *dq;
xlog_op_header_t *head = 0;
int num, skip;
int super_block = 0;
int bucket, col, buckets;
__int64_t blkno;
xfs_buf_log_format_t lbuf;
int size, blen, map_size, struct_size;
long long x, y;
/*
* bcopy to ensure 8-byte alignment for the long longs in
* buf_log_format_t structure
*/
bcopy(*ptr, &lbuf, MIN(sizeof(xfs_buf_log_format_t), len));
f = &lbuf;
*ptr += len;
if (f->blf_type == XFS_LI_BUF) {
blkno = f->blf_blkno;
size = f->blf_size;
blen = f->blf_len;
map_size = f->blf_map_size;
struct_size = sizeof(xfs_buf_log_format_t);
} else {
old_f = (xfs_buf_log_format_v1_t*)f;
blkno = old_f->blf_blkno;
size = old_f->blf_size;
blen = old_f->blf_len;
map_size = old_f->blf_map_size;
struct_size = sizeof(xfs_buf_log_format_v1_t);
}
switch (f->blf_type) {
case XFS_LI_BUF:
printf("BUF: ");
break;
case XFS_LI_6_1_BUF:
printf("6.1 BUF: ");
break;
case XFS_LI_5_3_BUF:
printf("5.3 BUF: ");
break;
default:
printf("UNKNOWN BUF: ");
break;
}
if (len >= struct_size) {
ASSERT((len - sizeof(struct_size)) % sizeof(int) == 0);
printf("#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d\n",
size, (long long)blkno, (unsigned long long)blkno, blen, map_size);
if (blkno == 0)
super_block = 1;
} else {
ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */
printf("#regs: %d Not printing rest of data\n", f->blf_size);
return size;
}
num = size-1;
/* Check if all regions in this log item were in the given LR ptr */
if (*i+num > num_ops-1) {
skip = num - (num_ops-1-*i);
num = num_ops-1-*i;
} else {
skip = 0;
}
while (num-- > 0) {
(*i)++;
head = (xlog_op_header_t *)*ptr;
xlog_print_op_header(head, *i, ptr);
if (super_block) {
printf("SUPER BLOCK Buffer: ");
if (INT_GET(head->oh_len, ARCH_CONVERT) < 4*8) {
printf("Out of space\n");
} else {
printf("\n");
/*
* bcopy because *ptr may not be 8-byte aligned
*/
bcopy(*ptr, &x, sizeof(long long));
bcopy(*ptr+8, &y, sizeof(long long));
printf("icount: %lld ifree: %lld ",
INT_GET(x, ARCH_CONVERT),
INT_GET(y, ARCH_CONVERT));
bcopy(*ptr+16, &x, sizeof(long long));
bcopy(*ptr+24, &y, sizeof(long long));
printf("fdblks: %lld frext: %lld\n",
INT_GET(x, ARCH_CONVERT),
INT_GET(y, ARCH_CONVERT));
}
super_block = 0;
} else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGI_MAGIC) {
agi = (xfs_agi_t *)(*ptr);
printf("AGI Buffer: XAGI ");
if (INT_GET(head->oh_len, ARCH_CONVERT) <
sizeof(xfs_agi_t) -
XFS_AGI_UNLINKED_BUCKETS*sizeof(xfs_agino_t)) {
printf("out of space\n");
} else {
printf("\n");
printf("ver: %d ",
INT_GET(agi->agi_versionnum, ARCH_CONVERT));
printf("seq#: %d len: %d cnt: %d root: %d\n",
INT_GET(agi->agi_seqno, ARCH_CONVERT),
INT_GET(agi->agi_length, ARCH_CONVERT),
INT_GET(agi->agi_count, ARCH_CONVERT),
INT_GET(agi->agi_root, ARCH_CONVERT));
printf("level: %d free#: 0x%x newino: 0x%x\n",
INT_GET(agi->agi_level, ARCH_CONVERT),
INT_GET(agi->agi_freecount, ARCH_CONVERT),
INT_GET(agi->agi_newino, ARCH_CONVERT));
if (INT_GET(head->oh_len, ARCH_CONVERT) == 128) {
buckets = 17;
} else if (INT_GET(head->oh_len, ARCH_CONVERT) == 256) {
buckets = 32 + 17;
} else {
if (head->oh_flags & XLOG_CONTINUE_TRANS) {
printf("AGI unlinked data skipped ");
printf("(CONTINUE set, no space)\n");
continue;
}
buckets = XFS_AGI_UNLINKED_BUCKETS;
}
for (bucket = 0; bucket < buckets;) {
printf("bucket[%d - %d]: ", bucket, bucket+3);
for (col = 0; col < 4; col++, bucket++) {
if (bucket < buckets) {
printf("0x%x ",
INT_GET(agi->agi_unlinked[bucket], ARCH_CONVERT));
}
}
printf("\n");
}
}
} else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGF_MAGIC) {
agf = (xfs_agf_t *)(*ptr);
printf("AGF Buffer: XAGF ");
if (INT_GET(head->oh_len, ARCH_CONVERT) < sizeof(xfs_agf_t)) {
printf("Out of space\n");
} else {
printf("\n");
printf("ver: %d seq#: %d len: %d \n",
INT_GET(agf->agf_versionnum, ARCH_CONVERT),
INT_GET(agf->agf_seqno, ARCH_CONVERT),
INT_GET(agf->agf_length, ARCH_CONVERT));
printf("root BNO: %d CNT: %d\n",
INT_GET(agf->agf_roots[XFS_BTNUM_BNOi],
ARCH_CONVERT),
INT_GET(agf->agf_roots[XFS_BTNUM_CNTi],
ARCH_CONVERT));
printf("level BNO: %d CNT: %d\n",
INT_GET(agf->agf_levels[XFS_BTNUM_BNOi],
ARCH_CONVERT),
INT_GET(agf->agf_levels[XFS_BTNUM_CNTi],
ARCH_CONVERT));
printf("1st: %d last: %d cnt: %d "
"freeblks: %d longest: %d\n",
INT_GET(agf->agf_flfirst, ARCH_CONVERT),
INT_GET(agf->agf_fllast, ARCH_CONVERT),
INT_GET(agf->agf_flcount, ARCH_CONVERT),
INT_GET(agf->agf_freeblks, ARCH_CONVERT),
INT_GET(agf->agf_longest, ARCH_CONVERT));
}
} else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_DQUOT_MAGIC) {
dq = (xfs_disk_dquot_t *)(*ptr);
printf("DQUOT Buffer: DQ ");
if (INT_GET(head->oh_len, ARCH_CONVERT) <
sizeof(xfs_disk_dquot_t)) {
printf("Out of space\n");
}
else {
printf("\n");
printf("ver: %d flags: 0x%x id: %d \n",
INT_GET(dq->d_version, ARCH_CONVERT),
INT_GET(dq->d_flags, ARCH_CONVERT),
INT_GET(dq->d_id, ARCH_CONVERT));
printf("blk limits hard: %llu soft: %llu\n",
(unsigned long long)
INT_GET(dq->d_blk_hardlimit, ARCH_CONVERT),
(unsigned long long)
INT_GET(dq->d_blk_softlimit, ARCH_CONVERT));
printf("blk count: %llu warns: %d timer: %d\n",
(unsigned long long)
INT_GET(dq->d_bcount, ARCH_CONVERT),
INT_GET(dq->d_bwarns, ARCH_CONVERT),
INT_GET(dq->d_btimer, ARCH_CONVERT));
printf("ino limits hard: %llu soft: %llu\n",
(unsigned long long)
INT_GET(dq->d_ino_hardlimit, ARCH_CONVERT),
(unsigned long long)
INT_GET(dq->d_ino_softlimit, ARCH_CONVERT));
printf("ino count: %llu warns: %d timer: %d\n",
(unsigned long long)
INT_GET(dq->d_icount, ARCH_CONVERT),
INT_GET(dq->d_iwarns, ARCH_CONVERT),
INT_GET(dq->d_itimer, ARCH_CONVERT));
}
} else {
printf("BUF DATA\n");
if (print_data) {
uint *dp = (uint *)*ptr;
int nums = INT_GET(head->oh_len, ARCH_CONVERT) >> 2;
int i = 0;
while (i < nums) {
if ((i % 8) == 0)
printf("%2x ", i);
printf("%8x ", *dp);
dp++;
i++;
if ((i % 8) == 0)
printf("\n");
}
printf("\n");
}
}
*ptr += INT_GET(head->oh_len, ARCH_CONVERT);
}
if (head && head->oh_flags & XLOG_CONTINUE_TRANS)
skip++;
return skip;
} /* xlog_print_trans_buffer */
int
xlog_print_trans_efd(xfs_caddr_t *ptr, uint len)
{
xfs_efd_log_format_t *f;
xfs_extent_t *ex;
int i;
xfs_efd_log_format_t lbuf;
/*
* bcopy to ensure 8-byte alignment for the long longs in
* xfs_efd_log_format_t structure
*/
bcopy(*ptr, &lbuf, sizeof(xfs_efd_log_format_t));
f = &lbuf;
*ptr += len;
if (len >= sizeof(xfs_efd_log_format_t)) {
printf("EFD: #regs: %d num_extents: %d id: 0x%llx\n",
f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id);
ex = f->efd_extents;
for (i=0; i< f->efd_size; i++) {
printf("(s: 0x%llx, l: %d) ",
(unsigned long long)ex->ext_start, ex->ext_len);
if (i % 4 == 3) printf("\n");
ex++;
}
if (i % 4 != 0) printf("\n");
return 0;
} else {
printf("EFD: Not enough data to decode further\n");
return 1;
}
} /* xlog_print_trans_efd */
int
xlog_print_trans_efi(xfs_caddr_t *ptr, uint len)
{
xfs_efi_log_format_t *f;
xfs_extent_t *ex;
int i;
xfs_efi_log_format_t lbuf;
/*
* bcopy to ensure 8-byte alignment for the long longs in
* xfs_efi_log_format_t structure
*/
bcopy(*ptr, &lbuf, sizeof(xfs_efi_log_format_t));
f = &lbuf;
*ptr += len;
if (len >= sizeof(xfs_efi_log_format_t)) {
printf("EFI: #regs: %d num_extents: %d id: 0x%llx\n",
f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
ex = f->efi_extents;
for (i=0; i< f->efi_size; i++) {
printf("(s: 0x%llx, l: %d) ",
(unsigned long long)ex->ext_start, ex->ext_len);
if (i % 4 == 3) printf("\n");
ex++;
}
if (i % 4 != 0) printf("\n");
return 0;
} else {
printf("EFI: Not enough data to decode further\n");
return 1;
}
} /* xlog_print_trans_efi */
int
xlog_print_trans_qoff(xfs_caddr_t *ptr, uint len)
{
xfs_qoff_logformat_t *f;
xfs_qoff_logformat_t lbuf;
bcopy(*ptr, &lbuf, sizeof(xfs_qoff_logformat_t));
f = &lbuf;
*ptr += len;
if (len >= sizeof(xfs_qoff_logformat_t)) {
printf("QOFF: #regs: %d flags: 0x%x\n", f->qf_size, f->qf_flags);
return 0;
} else {
printf("QOFF: Not enough data to decode further\n");
return 1;
}
} /* xlog_print_trans_qoff */
void
xlog_print_trans_inode_core(xfs_dinode_core_t *ip)
{
printf("INODE CORE\n");
printf("magic 0x%hx mode 0%ho version %d format %d\n",
ip->di_magic, ip->di_mode, (int)ip->di_version,
(int)ip->di_format);
printf("nlink %hd uid %d gid %d\n",
ip->di_nlink, ip->di_uid, ip->di_gid);
printf("atime 0x%x mtime 0x%x ctime 0x%x\n",
ip->di_atime.t_sec, ip->di_mtime.t_sec, ip->di_ctime.t_sec);
printf("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n",
(unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks,
ip->di_extsize, ip->di_nextents);
printf("naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n",
ip->di_anextents, (int)ip->di_forkoff, ip->di_dmevmask,
ip->di_dmstate);
printf("flags 0x%x gen 0x%x\n",
ip->di_flags, ip->di_gen);
}
void
xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size)
{
xfs_ino_t ino;
int count;
int i;
char namebuf[257];
xfs_dir_sf_entry_t *sfep;
/* XXX need to determine whether this is v1 or v2, then
print appropriate structure */
printf("SHORTFORM DIRECTORY size %d\n",
size);
/* bail out for now */
return;
printf("SHORTFORM DIRECTORY size %d count %d\n",
size, sfp->hdr.count);
bcopy(&(sfp->hdr.parent), &ino, sizeof(ino));
printf(".. ino 0x%llx\n", (unsigned long long)INT_GET(ino, ARCH_CONVERT));
count = (uint)(sfp->hdr.count);
sfep = &(sfp->list[0]);
for (i = 0; i < count; i++) {
bcopy(&(sfep->inumber), &ino, sizeof(ino));
bcopy((sfep->name), namebuf, sfep->namelen);
namebuf[sfep->namelen] = '\0';
printf("%s ino 0x%llx namelen %d\n",
namebuf, (unsigned long long)ino, sfep->namelen);
sfep = XFS_DIR_SF_NEXTENTRY(sfep);
}
}
int
xlog_print_trans_inode(xfs_caddr_t *ptr, int len, int *i, int num_ops)
{
xfs_inode_log_format_t *f;
xfs_inode_log_format_t_v1 *old_f;
xfs_dinode_core_t dino;
xlog_op_header_t *op_head;
int version;
xfs_inode_log_format_t lbuf = {0};
int mode;
int size;
/*
* print inode type header region
*
* bcopy to ensure 8-byte alignment for the long longs in
* xfs_inode_log_format_t structure
*
* len can be smaller than xfs_inode_log_format_t sometimes... (?)
*/
bcopy(*ptr, &lbuf, MIN(sizeof(xfs_inode_log_format_t), len));
version = lbuf.ilf_type;
f = &lbuf;
(*i)++; /* bump index */
*ptr += len;
if (version == XFS_LI_5_3_INODE) {
old_f = (xfs_inode_log_format_t_v1 *)f;
if (len == sizeof(xfs_inode_log_format_t_v1)) {
printf("5.3 INODE: #regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n",
old_f->ilf_size, (unsigned long long)old_f->ilf_ino,
old_f->ilf_fields, old_f->ilf_dsize);
} else {
ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */
printf("5.3 INODE: #regs: %d Not printing rest of data\n",
old_f->ilf_size);
return old_f->ilf_size;
}
} else {
if (len == sizeof(xfs_inode_log_format_t)) {
if (version == XFS_LI_6_1_INODE)
printf("6.1 INODE: ");
else printf("INODE: ");
printf("#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);
printf(" blkno: %lld len: %d boff: %d\n",
(long long)f->ilf_blkno, f->ilf_len, f->ilf_boffset);
} else {
ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */
printf("INODE: #regs: %d Not printing rest of data\n",
f->ilf_size);
return f->ilf_size;
}
}
if (*i >= num_ops) /* end of LR */
return f->ilf_size-1;
/* core inode comes 2nd */
op_head = (xlog_op_header_t *)*ptr;
xlog_print_op_header(op_head, *i, ptr);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return f->ilf_size-1;
}
bcopy(*ptr, &dino, sizeof(dino));
mode = dino.di_mode & IFMT;
size = (int)dino.di_size;
xlog_print_trans_inode_core(&dino);
*ptr += sizeof(xfs_dinode_core_t);
if (*i == num_ops-1 && f->ilf_size == 3) {
return 1;
}
/* does anything come next */
op_head = (xlog_op_header_t *)*ptr;
switch (f->ilf_fields & XFS_ILOG_NONCORE) {
case XFS_ILOG_DEXT: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("EXTENTS inode data\n");
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_DBROOT: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("BTREE inode data\n");
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_DDATA: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("LOCAL inode data\n");
if (mode == IFDIR) {
xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size);
}
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_AEXT: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("EXTENTS inode attr\n");
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_ABROOT: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("BTREE inode attr\n");
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_ADATA: {
ASSERT(f->ilf_size == 3);
(*i)++;
xlog_print_op_header(op_head, *i, ptr);
printf("LOCAL inode attr\n");
if (mode == IFDIR) {
xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size);
}
*ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) {
return 1;
}
break;
}
case XFS_ILOG_DEV: {
ASSERT(f->ilf_size == 2);
printf("DEV inode: no extra region\n");
break;
}
case XFS_ILOG_UUID: {
ASSERT(f->ilf_size == 2);
printf("UUID inode: no extra region\n");
break;
}
case 0: {
ASSERT(f->ilf_size == 2);
break;
}
default: {
xlog_panic("xlog_print_trans_inode: illegal inode type");
}
}
return 0;
} /* xlog_print_trans_inode */
int
xlog_print_trans_dquot(xfs_caddr_t *ptr, int len, int *i, int num_ops)
{
xfs_dq_logformat_t *f;
xfs_dq_logformat_t lbuf = {0};
xfs_disk_dquot_t ddq;
xlog_op_header_t *head = NULL;
int num, skip;
/*
* print dquot header region
*
* bcopy to ensure 8-byte alignment for the long longs in
* xfs_dq_logformat_t structure
*/
bcopy(*ptr, &lbuf, MIN(sizeof(xfs_dq_logformat_t), len));
f = &lbuf;
(*i)++; /* bump index */
*ptr += len;
if (len == sizeof(xfs_dq_logformat_t)) {
printf("#regs: %d id: 0x%x", f->qlf_size, f->qlf_id);
printf(" blkno: %lld len: %d boff: %d\n",
(long long)f->qlf_blkno, f->qlf_len, f->qlf_boffset);
} else {
ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */
printf("DQUOT: #regs: %d Not printing rest of data\n",
f->qlf_size);
return f->qlf_size;
}
num = f->qlf_size-1;
/* Check if all regions in this log item were in the given LR ptr */
if (*i+num > num_ops-1) {
skip = num - (num_ops-1-*i);
num = num_ops-1-*i;
} else {
skip = 0;
}
while (num-- > 0) {
head = (xlog_op_header_t *)*ptr;
xlog_print_op_header(head, *i, ptr);
ASSERT(INT_GET(head->oh_len, ARCH_CONVERT) == sizeof(xfs_disk_dquot_t));
bcopy(*ptr, &ddq, sizeof(xfs_disk_dquot_t));
printf("DQUOT: magic 0x%hx flags 0%ho\n",
INT_GET(ddq.d_magic, ARCH_CONVERT),
INT_GET(ddq.d_flags, ARCH_CONVERT));
*ptr += INT_GET(head->oh_len, ARCH_CONVERT);
}
if (head && head->oh_flags & XLOG_CONTINUE_TRANS)
skip++;
return skip;
} /* xlog_print_trans_dquot */
/******************************************************************************
*
* Log print routines
*
******************************************************************************
*/
void
xlog_print_lseek(xlog_t *log, int fd, xfs_daddr_t blkno, int whence)
{
#define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT)
xfs_off_t offset;
if (whence == SEEK_SET)
offset = BBTOOFF64(blkno+log->l_logBBstart);
else
offset = BBTOOFF64(blkno);
if (lseek64(fd, offset, whence) < 0) {
fprintf(stderr, "%s: lseek64 to %llu failed: %s\n",
progname, (unsigned long long)offset, strerror(errno));
exit(1);
}
} /* xlog_print_lseek */
void
print_lsn(xfs_caddr_t string,
xfs_lsn_t *lsn,
xfs_arch_t arch)
{
printf("%s: %u,%u", string,
CYCLE_LSN(*lsn, arch), BLOCK_LSN(*lsn, arch));
}
int
xlog_print_record(int fd,
int num_ops,
int len,
int *read_type,
xfs_caddr_t *partial_buf,
xlog_rec_header_t *rhead)
{
xlog_op_header_t *op_head;
xlog_rec_header_t *rechead;
xfs_caddr_t buf, ptr;
int read_len, skip;
int ret, n, i;
if (print_no_print)
return NO_ERROR;
if (!len) {
printf("\n");
return NO_ERROR;
}
/* read_len must read up to some block boundary */
read_len = (int) BBTOB(BTOBB(len));
/* read_type => don't malloc() new buffer, use old one */
if (*read_type == FULL_READ) {
if ((ptr = buf = (xfs_caddr_t)malloc(read_len)) == NULL) {
fprintf(stderr, "xlog_print_record: malloc failed\n");
exit(1);
}
} else {
read_len -= *read_type;
buf = (xfs_caddr_t)((__psint_t)(*partial_buf) + (__psint_t)(*read_type));
ptr = *partial_buf;
}
if ((ret = (int) read(fd, buf, read_len)) == -1) {
fprintf(stderr, "xlog_print_record: read error\n");
exit(1);
}
/* Did we overflow the end? */
if (*read_type == FULL_READ &&
BLOCK_LSN(rhead->h_lsn, ARCH_CONVERT)+BTOBB(read_len) >= logBBsize) {
*read_type = BBTOB(logBBsize-BLOCK_LSN(rhead->h_lsn, ARCH_CONVERT)-1);
*partial_buf = buf;
return PARTIAL_READ;
}
/* Did we read everything? */
if ((ret == 0 && read_len != 0) || ret != read_len) {
*read_type = ret;
*partial_buf = buf;
return PARTIAL_READ;
}
if (*read_type != FULL_READ)
read_len += *read_type;
/* Everything read in. Start from beginning of buffer */
buf = ptr;
for (i = 0; ptr < buf + read_len; ptr += BBSIZE, i++) {
rechead = (xlog_rec_header_t *)ptr;
if (INT_GET(rechead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) {
xlog_print_lseek(0, fd, -read_len+i*BBSIZE, SEEK_CUR);
free(buf);
return -1;
} else {
if (INT_GET(rhead->h_cycle, ARCH_CONVERT) !=
INT_GET(*(uint *)ptr, ARCH_CONVERT)) {
if (*read_type == FULL_READ)
return -1;
else if (INT_GET(rhead->h_cycle, ARCH_CONVERT) + 1 !=
INT_GET(*(uint *)ptr, ARCH_CONVERT))
return -1;
}
}
INT_SET(*(uint *)ptr, ARCH_CONVERT,
INT_GET(rhead->h_cycle_data[i], ARCH_CONVERT));
}
ptr = buf;
for (i=0; i<num_ops; i++) {
print_xlog_op_line();
op_head = (xlog_op_header_t *)ptr;
xlog_print_op_header(op_head, i, &ptr);
/* print transaction data */
if (print_no_data ||
((XLOG_SET(op_head->oh_flags, XLOG_WAS_CONT_TRANS) ||
XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) &&
INT_GET(op_head->oh_len, ARCH_CONVERT) == 0)) {
for (n = 0; n < INT_GET(op_head->oh_len, ARCH_CONVERT); n++) {
printf("%c", *ptr);
ptr++;
}
printf("\n");
continue;
}
if (xlog_print_find_tid(INT_GET(op_head->oh_tid, ARCH_CONVERT),
op_head->oh_flags & XLOG_WAS_CONT_TRANS)) {
printf("Left over region from split log item\n");
ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
continue;
}
if (INT_GET(op_head->oh_len, ARCH_CONVERT) != 0) {
if (*(uint *)ptr == XFS_TRANS_HEADER_MAGIC) {
skip = xlog_print_trans_header(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT));
} else {
switch (*(unsigned short *)ptr) {
case XFS_LI_5_3_BUF:
case XFS_LI_6_1_BUF:
case XFS_LI_BUF: {
skip = xlog_print_trans_buffer(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT),
&i, num_ops);
break;
}
case XFS_LI_5_3_INODE:
case XFS_LI_6_1_INODE:
case XFS_LI_INODE: {
skip = xlog_print_trans_inode(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT),
&i, num_ops);
break;
}
case XFS_LI_DQUOT: {
skip = xlog_print_trans_dquot(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT),
&i, num_ops);
break;
}
case XFS_LI_EFI: {
skip = xlog_print_trans_efi(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT));
break;
}
case XFS_LI_EFD: {
skip = xlog_print_trans_efd(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT));
break;
}
case XFS_LI_QUOTAOFF: {
skip = xlog_print_trans_qoff(&ptr,
INT_GET(op_head->oh_len, ARCH_CONVERT));
break;
}
case XLOG_UNMOUNT_TYPE: {
printf("Unmount filesystem\n");
skip = 0;
break;
}
default: {
fprintf(stderr, "%s: unknown log operation type (%x)\n",
progname, *(unsigned short *)ptr);
skip = 0;
ptr += INT_GET(op_head->oh_len, ARCH_CONVERT);
}
} /* switch */
} /* else */
if (skip != 0)
xlog_print_add_to_trans(INT_GET(op_head->oh_tid, ARCH_CONVERT), skip);
}
}
printf("\n");
free(buf);
return NO_ERROR;
} /* xlog_print_record */
int
xlog_print_rec_head(xlog_rec_header_t *head, int *len)
{
int i;
char uub[64];
int datalen,bbs;
if (print_no_print)
return INT_GET(head->h_num_logops, ARCH_CONVERT);
if (INT_ISZERO(head->h_magicno, ARCH_CONVERT))
return ZEROED_LOG;
if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) {
printf("Header 0x%x wanted 0x%x\n",
INT_GET(head->h_magicno, ARCH_CONVERT),
XLOG_HEADER_MAGIC_NUM);
return BAD_HEADER;
}
datalen=INT_GET(head->h_len, ARCH_CONVERT);
bbs=(datalen/BBSIZE)+(datalen%BBSIZE)?1:0;
printf("cycle: %d version: %d ",
INT_GET(head->h_cycle, ARCH_CONVERT),
INT_GET(head->h_version, ARCH_CONVERT));
print_lsn(" lsn", &head->h_lsn, ARCH_CONVERT);
print_lsn(" tail_lsn", &head->h_tail_lsn, ARCH_CONVERT);
printf("\n");
printf("length of Log Record: %d prev offset: %d num ops: %d\n",
datalen,
INT_GET(head->h_prev_block, ARCH_CONVERT),
INT_GET(head->h_num_logops, ARCH_CONVERT));
if (print_overwrite) {
printf("cycle num overwrites: ");
for (i=0; i< bbs; i++)
printf("%d - 0x%x ",
i,
INT_GET(head->h_cycle_data[i], ARCH_CONVERT));
printf("\n");
}
uuid_unparse(head->h_fs_uuid, uub);
printf("uuid: %s format: ", uub);
switch (INT_GET(head->h_fmt, ARCH_CONVERT)) {
case XLOG_FMT_UNKNOWN:
printf("unknown\n");
break;
case XLOG_FMT_LINUX_LE:
printf("little endian linux\n");
break;
case XLOG_FMT_LINUX_BE:
printf("big endian linux\n");
break;
case XLOG_FMT_IRIX_BE:
printf("big endian irix\n");
break;
default:
printf("? (%d)\n", INT_GET(head->h_fmt, ARCH_CONVERT));
break;
}
*len = INT_GET(head->h_len, ARCH_CONVERT);
return(INT_GET(head->h_num_logops, ARCH_CONVERT));
} /* xlog_print_rec_head */
static void
print_xlog_bad_zeroed(xfs_daddr_t blkno)
{
print_stars();
printf("* ERROR: found data after zeroed blocks block=%-21lld *\n",
(long long)blkno);
print_stars();
if (print_exit)
xlog_exit("Bad log - data after zeroed blocks");
} /* print_xlog_bad_zeroed */
static void
print_xlog_bad_header(xfs_daddr_t blkno, xfs_caddr_t buf)
{
print_stars();
printf("* ERROR: header cycle=%-11d block=%-21lld *\n",
GET_CYCLE(buf, ARCH_CONVERT), (long long)blkno);
print_stars();
if (print_exit)
xlog_exit("Bad log record header");
} /* print_xlog_bad_header */
void
print_xlog_bad_data(xfs_daddr_t blkno)
{
print_stars();
printf("* ERROR: data block=%-21lld *\n",
(long long)blkno);
print_stars();
if (print_exit)
xlog_exit("Bad data in log");
} /* print_xlog_bad_data */
/*
* This code is gross and needs to be rewritten.
*/
void xfs_log_print(xlog_t *log,
int fd,
int print_block_start)
{
char hbuf[XLOG_HEADER_SIZE];
int num_ops, len;
xfs_daddr_t block_end = 0, block_start, blkno, error;
int read_type = FULL_READ;
xfs_caddr_t partial_buf;
int zeroed = 0;
logBBsize = log->l_logBBsize;
/*
* Normally, block_start and block_end are the same value since we
* are printing the entire log. However, if the start block is given,
* we still end at the end of the logical log.
*/
if ((error = xlog_print_find_oldest(log, &block_end))) {
fprintf(stderr, "%s: problem finding oldest LR\n", progname);
return;
}
if (print_block_start == -1)
block_start = block_end;
else
block_start = print_block_start;
xlog_print_lseek(log, fd, block_start, SEEK_SET);
blkno = block_start;
for (;;) {
if (read(fd, hbuf, 512) == 0) {
printf("%s: physical end of log\n", progname);
print_xlog_record_line();
break;
}
if (print_only_data) {
printf("BLKNO: %lld\n", (long long)blkno);
xlog_recover_print_data(hbuf, 512);
blkno++;
goto loop;
}
num_ops = xlog_print_rec_head((xlog_rec_header_t *)hbuf, &len);
blkno++;
if (zeroed && num_ops != ZEROED_LOG) {
printf("%s: after %d zeroed blocks\n", progname, zeroed);
/* once we find zeroed blocks - that's all we expect */
print_xlog_bad_zeroed(blkno-1);
/* reset count since we're assuming previous zeroed blocks
* were bad
*/
zeroed = 0;
}
if (num_ops == ZEROED_LOG || num_ops == BAD_HEADER) {
if (num_ops == ZEROED_LOG) {
zeroed++;
} else {
print_xlog_bad_header(blkno-1, hbuf);
}
goto loop;
}
error = xlog_print_record(fd, num_ops, len, &read_type, &partial_buf,
(xlog_rec_header_t *)hbuf);
switch (error) {
case 0: {
blkno += BTOBB(len);
if (print_block_start != -1 &&
blkno >= block_end) /* If start specified, we */
goto end; /* end early */
break;
}
case -1: {
print_xlog_bad_data(blkno-1);
if (print_block_start != -1 &&
blkno >= block_end) /* If start specified, */
goto end; /* we end early */
xlog_print_lseek(log, fd, blkno, SEEK_SET);
goto loop;
}
case PARTIAL_READ: {
print_xlog_record_line();
printf("%s: physical end of log\n", progname);
print_xlog_record_line();
blkno = 0;
xlog_print_lseek(log, fd, 0, SEEK_SET);
/*
* We may have hit the end of the log when we started at 0.
* In this case, just end.
*/
if (block_start == 0)
goto end;
goto partial_log_read;
}
default: xlog_panic("illegal value");
}
print_xlog_record_line();
loop:
if (blkno >= logBBsize) {
if (zeroed) {
printf("%s: skipped %d zeroed blocks\n", progname, zeroed);
if (zeroed == logBBsize)
printf("%s: totally zeroed log\n", progname);
zeroed=0;
}
printf("%s: physical end of log\n", progname);
print_xlog_record_line();
break;
}
}
/* Do we need to print the first part of physical log? */
if (block_start != 0) {
blkno = 0;
xlog_print_lseek(log, fd, 0, SEEK_SET);
for (;;) {
if (read(fd, hbuf, 512) == 0) {
xlog_panic("xlog_find_head: bad read");
}
if (print_only_data) {
printf("BLKNO: %lld\n", (long long)blkno);
xlog_recover_print_data(hbuf, 512);
blkno++;
goto loop2;
}
num_ops = xlog_print_rec_head((xlog_rec_header_t *)hbuf, &len);
blkno++;
if (num_ops == ZEROED_LOG || num_ops == BAD_HEADER) {
/* we only expect zeroed log entries at the end
* of the _physical_ log, so treat them the same
* as bad blocks here
*/
print_xlog_bad_header(blkno-1, hbuf);
if (blkno >= block_end)
break;
continue;
}
partial_log_read:
error= xlog_print_record(fd, num_ops, len, &read_type,
&partial_buf, (xlog_rec_header_t *)hbuf);
if (read_type != FULL_READ)
len -= read_type;
read_type = FULL_READ;
if (!error)
blkno += BTOBB(len);
else {
print_xlog_bad_data(blkno-1);
xlog_print_lseek(log, fd, blkno, SEEK_SET);
goto loop2;
}
print_xlog_record_line();
loop2:
if (blkno >= block_end)
break;
}
}
end:
printf("%s: logical end of log\n", progname);
print_xlog_record_line();
}