[BACK]Return to log_print_all.c CVS log [TXT][DIR] Up to [Development] / xfs-cmds / xfsprogs / logprint

File: [Development] / xfs-cmds / xfsprogs / logprint / log_print_all.c (download)

Revision 1.10, Wed Aug 6 21:17:06 2003 UTC (14 years, 2 months ago) by lord
Branch: MAIN
Changes since 1.9: +1 -0 lines

Add versioning to the on disk inode which we increment on each
flush call. This is used during recovery to avoid replaying an
older copy of the inode from the log. We can do this without
versioning the filesystem as the pad space we borrowed was
always zero and will be ignored by old kernels.
print new di_flushiter field

/*
 * Copyright (c) 2000-2003 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"


/*
 * Start is defined to be the block pointing to the oldest valid log record.
 */
int
xlog_print_find_oldest(
	struct log	*log,
	xfs_daddr_t	*last_blk)
{
	xfs_buf_t	*bp;
	xfs_daddr_t	first_blk;
	uint		first_half_cycle, last_half_cycle;
	int		error;

	if (xlog_find_zeroed(log, &first_blk))
		return 0;

	first_blk = 0;		/* read first block */
	bp = xlog_get_bp(log, 1);
	xlog_bread(log, 0, 1, bp);
	first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
	*last_blk = log->l_logBBsize-1;	/* read last block */
	xlog_bread(log, *last_blk, 1, bp);
	last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
	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);
		if (error)
			return error;
	}

	xlog_put_bp(bp);
	return 0;
}

void
xlog_recover_print_data(
	xfs_caddr_t	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_v1_t	*old_f;
	xfs_buf_log_format_t	*f;
	xfs_caddr_t		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;
	old_f = (xfs_buf_log_format_v1_t *)f;
	len = item->ri_buf[0].i_len;
	printf("	");
	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;
	}
	if (f->blf_type == XFS_LI_BUF) {
		printf("#regs:%d   start blkno:0x%llx   len:%d   bmap size:%d\n",
		       f->blf_size, (long long)f->blf_blkno, f->blf_len, f->blf_map_size);
		blkno = (xfs_daddr_t)f->blf_blkno;
	} else {
		printf("#regs:%d   start blkno:0x%x   len:%d   bmap size:%d\n",
		       old_f->blf_size, old_f->blf_blkno, old_f->blf_len,
		       old_f->blf_map_size);
		blkno = (xfs_daddr_t)old_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:%Ld  ifree:%Ld  ",
			       INT_GET(*(long long *)(p), ARCH_CONVERT),
			       INT_GET(*(long long *)(p+8), ARCH_CONVERT));
			printf("fdblks:%Ld  frext:%Ld\n",
			       INT_GET(*(long long *)(p+16), ARCH_CONVERT),
			       INT_GET(*(long long *)(p+24), ARCH_CONVERT));
			printf("		sunit:%u  swidth:%u\n",
			       INT_GET(*(uint *)(p+56), ARCH_CONVERT),
			       INT_GET(*(uint *)(p+60), ARCH_CONVERT));
		} else if (INT_GET(*(uint *)p, ARCH_CONVERT) == XFS_AGI_MAGIC) {
			agi = (xfs_agi_t *)p;
			printf("	AGI Buffer: (XAGI)\n");
			if (!print_buffer) continue;
			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));
		} else if (INT_GET(*(uint *)p, ARCH_CONVERT) == 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",
				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 (*(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)INT_GET(ddq->d_id, ARCH_CONVERT),
			       (unsigned long)INT_GET(ddq->d_id, ARCH_CONVERT) +
			       (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[20];

	qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr;
	ASSERT(qoff_f);
	if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
		strcpy(str, "USER QUOTA");
	if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
		strcat(str, "GROUP 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",
	       INT_GET(d->d_magic, ARCH_CONVERT),
	       INT_GET(d->d_version, ARCH_CONVERT),
	       INT_GET(d->d_id, ARCH_CONVERT),
	       INT_GET(d->d_id, ARCH_CONVERT));
	printf("\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x"
	       "\tino_soft 0x%x\n",
	       (int)INT_GET(d->d_blk_hardlimit, ARCH_CONVERT),
	       (int)INT_GET(d->d_blk_softlimit, ARCH_CONVERT),
	       (int)INT_GET(d->d_ino_hardlimit, ARCH_CONVERT),
	       (int)INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
	printf("\t\tbcount 0x%x (%d) icount 0x%x (%d)\n",
	       (int)INT_GET(d->d_bcount, ARCH_CONVERT),
	       (int)INT_GET(d->d_bcount, ARCH_CONVERT),
	       (int)INT_GET(d->d_icount, ARCH_CONVERT),
	       (int)INT_GET(d->d_icount, ARCH_CONVERT));
	printf("\t\tbtimer 0x%x itimer 0x%x \n",
	       (int)INT_GET(d->d_btimer, ARCH_CONVERT),
	       (int)INT_GET(d->d_itimer, ARCH_CONVERT));
}

STATIC void
xlog_recover_print_inode_core(
	xfs_dinode_core_t	*di)
{
	printf("	CORE inode:\n");
	if (!print_inode)
		return;
	printf("		magic:%c%c  mode:0x%x  ver:%d  format:%d  "
	     "onlink:%d\n",
	       (di->di_magic>>8) & 0xff, di->di_magic & 0xff,
	       di->di_mode, di->di_version, di->di_format, di->di_onlink);
	printf("		uid:%d  gid:%d  nlink:%d projid:%d\n",
	       di->di_uid, di->di_gid, di->di_nlink, (uint)di->di_projid);
	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:%d\n",
	       (int)di->di_forkoff, di->di_dmevmask, (int)di->di_dmstate,
	       (int)di->di_flags, di->di_gen);
}

STATIC void
xlog_recover_print_inode(
	xlog_recover_item_t	*item)
{
	xfs_inode_log_format_t	*f;
	int			attr_index;
	int			hasdata;
	int			hasattr;

	f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
	ASSERT(item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t));
	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 == sizeof(xfs_dinode_core_t));
	xlog_recover_print_inode_core((xfs_dinode_core_t *)
				      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_efd(
	xlog_recover_item_t	*item)
{
	xfs_efd_log_format_t	*f;
	xfs_extent_t		*ex;
	int			i;

	f = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
	/*
	 * An xfs_efd_log_format structure contains a variable length array
	 * as the last field.  Each element is of size xfs_extent_t.
	 */
	ASSERT(item->ri_buf[0].i_len ==
	       sizeof(xfs_efd_log_format_t) + sizeof(xfs_extent_t) *
	       (f->efd_nextents-1));
	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;
	printf("	");
	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");
}


STATIC void
xlog_recover_print_efi(
	xlog_recover_item_t	*item)
{
	xfs_efi_log_format_t	*f;
	xfs_extent_t		*ex;
	int			i;

	f = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
	/*
	 * An xfs_efi_log_format structure contains a variable length array
	 * as the last field.  Each element is of size xfs_extent_t.
	 */
	ASSERT(item->ri_buf[0].i_len ==
	       sizeof(xfs_efi_log_format_t) + sizeof(xfs_extent_t) *
	       (f->efi_nextents-1));

	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;
	printf("	");
	for (i=0; i< f->efi_nextents; 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");
}

void
xlog_recover_print_logitem(
	xlog_recover_item_t	*item)
{
	switch (ITEM_TYPE(item)) {
	case XFS_LI_BUF:
	case XFS_LI_6_1_BUF:
	case XFS_LI_5_3_BUF:
		xlog_recover_print_buffer(item);
		break;
	case XFS_LI_INODE:
	case XFS_LI_6_1_INODE:
	case XFS_LI_5_3_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_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_INODE:
		printf("INO");
		break;
	case XFS_LI_EFD:
		printf("EFD");
		break;
	case XFS_LI_EFI:
		printf("EFI");
		break;
	case XFS_LI_6_1_BUF:
		printf("6.1 BUF");
		break;
	case XFS_LI_5_3_BUF:
		printf("5.3 BUF");
		break;
	case XFS_LI_6_1_INODE:
		printf("6.1 INO");
		break;
	case XFS_LI_5_3_INODE:
		printf("5.3 INO");
		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,
	xlog_recover_item_t	*itemq,
	int			print)
{
	xlog_recover_item_t	*first_item, *item;

	if (print < 3)
		return;

	print_xlog_record_line();
	xlog_recover_print_trans_head(trans);
	item = first_item = itemq;
	do {
		xlog_recover_print_item(item);
		item = item->ri_next;
	} while (first_item != item);
}