Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d192a9b authored by Tim Shimmin's avatar Tim Shimmin Committed by Nathan Scott
Browse files

[XFS] inode items and EFI/EFDs have different ondisk format for 32bit and


64bit kernels allow recovery to handle both versions and do the necessary
decoding

SGI-PV: 952214
SGI-Modid: xfs-linux-melb:xfs-kern:26011a

Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent d210a28c
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -293,6 +293,62 @@ xfs_efi_init(xfs_mount_t *mp,
	return (efip);
}

/*
 * Copy an EFI format buffer from the given buf, and into the destination
 * EFI format structure.
 * The given buffer can be in 32 bit or 64 bit form (which has different padding),
 * one of which will be the native format for this kernel.
 * It will handle the conversion of formats if necessary.
 */
int
xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
{
	xfs_efi_log_format_t *src_efi_fmt = (xfs_efi_log_format_t *)buf->i_addr;
	uint i;
	uint len = sizeof(xfs_efi_log_format_t) + 
		(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t);  
	uint len32 = sizeof(xfs_efi_log_format_32_t) + 
		(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_32_t);  
	uint len64 = sizeof(xfs_efi_log_format_64_t) + 
		(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_64_t);  

	if (buf->i_len == len) {
		memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len);
		return 0;
	} else if (buf->i_len == len32) {
		xfs_efi_log_format_32_t *src_efi_fmt_32 =
			(xfs_efi_log_format_32_t *)buf->i_addr;

		dst_efi_fmt->efi_type     = src_efi_fmt_32->efi_type;
		dst_efi_fmt->efi_size     = src_efi_fmt_32->efi_size;
		dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents;
		dst_efi_fmt->efi_id       = src_efi_fmt_32->efi_id;
		for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
			dst_efi_fmt->efi_extents[i].ext_start =
				src_efi_fmt_32->efi_extents[i].ext_start;
			dst_efi_fmt->efi_extents[i].ext_len =
				src_efi_fmt_32->efi_extents[i].ext_len;
		}
		return 0;
	} else if (buf->i_len == len64) {
		xfs_efi_log_format_64_t *src_efi_fmt_64 =
			(xfs_efi_log_format_64_t *)buf->i_addr;

		dst_efi_fmt->efi_type     = src_efi_fmt_64->efi_type;
		dst_efi_fmt->efi_size     = src_efi_fmt_64->efi_size;
		dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents;
		dst_efi_fmt->efi_id       = src_efi_fmt_64->efi_id;
		for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
			dst_efi_fmt->efi_extents[i].ext_start =
				src_efi_fmt_64->efi_extents[i].ext_start;
			dst_efi_fmt->efi_extents[i].ext_len =
				src_efi_fmt_64->efi_extents[i].ext_len;
		}
		return 0;
	}
	return EFSCORRUPTED;
}

/*
 * This is called by the efd item code below to release references to
 * the given efi item.  Each efd calls this with the number of
+52 −1
Original line number Diff line number Diff line
@@ -26,6 +26,24 @@ typedef struct xfs_extent {
	xfs_extlen_t	ext_len;
} xfs_extent_t;

/*
 * Since an xfs_extent_t has types (start:64, len: 32)
 * there are different alignments on 32 bit and 64 bit kernels.
 * So we provide the different variants for use by a
 * conversion routine.
 */

typedef struct xfs_extent_32 {
	xfs_dfsbno_t	ext_start;
	xfs_extlen_t	ext_len;
} __attribute__((packed)) xfs_extent_32_t;

typedef struct xfs_extent_64 {
	xfs_dfsbno_t	ext_start;
	xfs_extlen_t	ext_len;
	__uint32_t	ext_pad;
} xfs_extent_64_t;

/*
 * This is the structure used to lay out an efi log item in the
 * log.  The efi_extents field is a variable size array whose
@@ -39,6 +57,22 @@ typedef struct xfs_efi_log_format {
	xfs_extent_t		efi_extents[1];	/* array of extents to free */
} xfs_efi_log_format_t;

typedef struct xfs_efi_log_format_32 {
	unsigned short		efi_type;	/* efi log item type */
	unsigned short		efi_size;	/* size of this item */
	uint			efi_nextents;	/* # extents to free */
	__uint64_t		efi_id;		/* efi identifier */
	xfs_extent_32_t		efi_extents[1];	/* array of extents to free */
} __attribute__((packed)) xfs_efi_log_format_32_t;

typedef struct xfs_efi_log_format_64 {
	unsigned short		efi_type;	/* efi log item type */
	unsigned short		efi_size;	/* size of this item */
	uint			efi_nextents;	/* # extents to free */
	__uint64_t		efi_id;		/* efi identifier */
	xfs_extent_64_t		efi_extents[1];	/* array of extents to free */
} xfs_efi_log_format_64_t;

/*
 * This is the structure used to lay out an efd log item in the
 * log.  The efd_extents array is a variable size array whose
@@ -52,6 +86,22 @@ typedef struct xfs_efd_log_format {
	xfs_extent_t		efd_extents[1];	/* array of extents freed */
} xfs_efd_log_format_t;

typedef struct xfs_efd_log_format_32 {
	unsigned short		efd_type;	/* efd log item type */
	unsigned short		efd_size;	/* size of this item */
	uint			efd_nextents;	/* # of extents freed */
	__uint64_t		efd_efi_id;	/* id of corresponding efi */
	xfs_extent_32_t		efd_extents[1];	/* array of extents freed */
} __attribute__((packed)) xfs_efd_log_format_32_t;

typedef struct xfs_efd_log_format_64 {
	unsigned short		efd_type;	/* efd log item type */
	unsigned short		efd_size;	/* size of this item */
	uint			efd_nextents;	/* # of extents freed */
	__uint64_t		efd_efi_id;	/* id of corresponding efi */
	xfs_extent_64_t		efd_extents[1];	/* array of extents freed */
} xfs_efd_log_format_64_t;


#ifdef __KERNEL__

@@ -103,7 +153,8 @@ extern struct kmem_zone *xfs_efd_zone;
xfs_efi_log_item_t	*xfs_efi_init(struct xfs_mount *, uint);
xfs_efd_log_item_t	*xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *,
				      uint);

int			xfs_efi_copy_format(xfs_log_iovec_t *buf,
					    xfs_efi_log_format_t *dst_efi_fmt);
void			xfs_efi_item_free(xfs_efi_log_item_t *);

#endif	/* __KERNEL__ */
+49 −0
Original line number Diff line number Diff line
@@ -1084,3 +1084,52 @@ xfs_istale_done(
{
	xfs_iflush_abort(iip->ili_inode);
}

/*
 * convert an xfs_inode_log_format struct from either 32 or 64 bit versions
 * (which can have different field alignments) to the native version
 */
int
xfs_inode_item_format_convert(
	xfs_log_iovec_t		*buf,
	xfs_inode_log_format_t	*in_f)
{
	if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) {
		xfs_inode_log_format_32_t *in_f32;

		in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr;
		in_f->ilf_type = in_f32->ilf_type;
		in_f->ilf_size = in_f32->ilf_size;
		in_f->ilf_fields = in_f32->ilf_fields;
		in_f->ilf_asize = in_f32->ilf_asize;
		in_f->ilf_dsize = in_f32->ilf_dsize;
		in_f->ilf_ino = in_f32->ilf_ino;
		/* copy biggest field of ilf_u */
		memcpy(in_f->ilf_u.ilfu_uuid.__u_bits,
		       in_f32->ilf_u.ilfu_uuid.__u_bits,
		       sizeof(uuid_t));
		in_f->ilf_blkno = in_f32->ilf_blkno;
		in_f->ilf_len = in_f32->ilf_len;
		in_f->ilf_boffset = in_f32->ilf_boffset;
		return 0;
	} else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){
		xfs_inode_log_format_64_t *in_f64;

		in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr;
		in_f->ilf_type = in_f64->ilf_type;
		in_f->ilf_size = in_f64->ilf_size;
		in_f->ilf_fields = in_f64->ilf_fields;
		in_f->ilf_asize = in_f64->ilf_asize;
		in_f->ilf_dsize = in_f64->ilf_dsize;
		in_f->ilf_ino = in_f64->ilf_ino;
		/* copy biggest field of ilf_u */
		memcpy(in_f->ilf_u.ilfu_uuid.__u_bits,
		       in_f64->ilf_u.ilfu_uuid.__u_bits,
		       sizeof(uuid_t));
		in_f->ilf_blkno = in_f64->ilf_blkno;
		in_f->ilf_len = in_f64->ilf_len;
		in_f->ilf_boffset = in_f64->ilf_boffset;
		return 0;
	}
	return EFSCORRUPTED;
}
+32 −29
Original line number Diff line number Diff line
@@ -23,25 +23,6 @@
 * log.  The size of the inline data/extents/b-tree root to be logged
 * (if any) is indicated in the ilf_dsize field.  Changes to this structure
 * must be added on to the end.
 *
 * Convention for naming inode log item versions :  The current version
 * is always named XFS_LI_INODE.  When an inode log item gets superseded,
 * add the latest version of IRIX that will generate logs with that item
 * to the version name.
 *
 * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first
 *	union (ilf_u) field.  This was released with IRIX 5.3-XFS.
 * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire
 *	structure.  This was released with IRIX 6.0.1-XFS and IRIX 6.1.
 * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2
 *	so a new structure definition wasn't necessary.  However, we had
 *	to add a new type because the inode cluster size changed from 4K
 *	to 8K and the version number had to be rev'ved to keep older kernels
 *	from trying to recover logs with the 8K buffers in them.  The logging
 *	code can handle recovery on different-sized clusters now so hopefully
 *	this'll be the last time we need to change the inode log item just
 *	for a change in the inode cluster size.  This new version was
 *	released with IRIX 6.2.
 */
typedef struct xfs_inode_log_format {
	unsigned short		ilf_type;	/* inode log item type */
@@ -59,18 +40,38 @@ typedef struct xfs_inode_log_format {
	int			ilf_boffset;	/* off of inode in buffer */
} xfs_inode_log_format_t;

/* Initial version shipped with IRIX 5.3-XFS */
typedef struct xfs_inode_log_format_v1 {
	unsigned short		ilf_type;	/* inode log item type */
	unsigned short		ilf_size;	/* size of this item */
	uint			ilf_fields;	/* flags for fields logged */
	uint			ilf_dsize;	/* size of data/ext/root */
	xfs_ino_t		ilf_ino;	/* inode number */
typedef struct xfs_inode_log_format_32 {
	unsigned short		ilf_type;	/* 16: inode log item type */
	unsigned short		ilf_size;	/* 16: size of this item */
	uint			ilf_fields;	/* 32: flags for fields logged */
	ushort			ilf_asize;	/* 32: size of attr d/ext/root */
	ushort			ilf_dsize;	/* 32: size of data/ext/root */
	xfs_ino_t		ilf_ino;	/* 64: inode number */
	union {
		xfs_dev_t	ilfu_rdev;	/* rdev value for dev inode*/
		uuid_t		ilfu_uuid;	/* mount point value */
		xfs_dev_t	ilfu_rdev;	/* 32: rdev value for dev inode*/
		uuid_t		ilfu_uuid;	/* 128: mount point value */
	} ilf_u;
	__int64_t		ilf_blkno;	/* 64: blkno of inode buffer */
	int			ilf_len;	/* 32: len of inode buffer */
	int			ilf_boffset;	/* 32: off of inode in buffer */
} __attribute__((packed)) xfs_inode_log_format_32_t;

typedef struct xfs_inode_log_format_64 {
	unsigned short		ilf_type;	/* 16: inode log item type */
	unsigned short		ilf_size;	/* 16: size of this item */
	uint			ilf_fields;	/* 32: flags for fields logged */
	ushort			ilf_asize;	/* 32: size of attr d/ext/root */
	ushort			ilf_dsize;	/* 32: size of data/ext/root */
	__uint32_t		ilf_pad;	/* 32: pad for 64 bit boundary */
	xfs_ino_t		ilf_ino;	/* 64: inode number */
	union {
		xfs_dev_t	ilfu_rdev;	/* 32: rdev value for dev inode*/
		uuid_t		ilfu_uuid;	/* 128: mount point value */
	} ilf_u;
} xfs_inode_log_format_t_v1;
	__int64_t		ilf_blkno;	/* 64: blkno of inode buffer */
	int			ilf_len;	/* 32: len of inode buffer */
	int			ilf_boffset;	/* 32: off of inode in buffer */
} xfs_inode_log_format_64_t;

/*
 * Flags for xfs_trans_log_inode flags field.
@@ -172,6 +173,8 @@ extern void xfs_inode_item_destroy(struct xfs_inode *);
extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);
extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *);
extern void xfs_iflush_abort(struct xfs_inode *);
extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
					 xfs_inode_log_format_t *);

#endif	/* __KERNEL__ */

+56 −31
Original line number Diff line number Diff line
@@ -2292,12 +2292,22 @@ xlog_recover_do_inode_trans(
	int			attr_index;
	uint			fields;
	xfs_dinode_core_t	*dicp;
	int			need_free = 0;

	if (pass == XLOG_RECOVER_PASS1) {
		return 0;
	}

	if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) {
		in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
	} else {
		in_f = (xfs_inode_log_format_t *)kmem_alloc(
			sizeof(xfs_inode_log_format_t), KM_SLEEP);
		need_free = 1;
		error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
		if (error)
			goto error;
	}
	ino = in_f->ilf_ino;
	mp = log->l_mp;
	if (ITEM_TYPE(item) == XFS_LI_INODE) {
@@ -2323,8 +2333,10 @@ xlog_recover_do_inode_trans(
	 * Inode buffers can be freed, look out for it,
	 * and do not replay the inode.
	 */
	if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0))
		return 0;
	if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) {
		error = 0;
		goto error;
	}

	bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len,
								XFS_BUF_LOCK);
@@ -2333,7 +2345,7 @@ xlog_recover_do_inode_trans(
				  bp, imap.im_blkno);
		error = XFS_BUF_GETERROR(bp);
		xfs_buf_relse(bp);
		return error;
		goto error;
	}
	error = 0;
	ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
@@ -2350,7 +2362,8 @@ xlog_recover_do_inode_trans(
			dip, bp, ino);
		XFS_ERROR_REPORT("xlog_recover_do_inode_trans(1)",
				 XFS_ERRLEVEL_LOW, mp);
		return XFS_ERROR(EFSCORRUPTED);
		error = EFSCORRUPTED;
		goto error;
	}
	dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr);
	if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
@@ -2360,7 +2373,8 @@ xlog_recover_do_inode_trans(
			item, ino);
		XFS_ERROR_REPORT("xlog_recover_do_inode_trans(2)",
				 XFS_ERRLEVEL_LOW, mp);
		return XFS_ERROR(EFSCORRUPTED);
		error = EFSCORRUPTED;
		goto error;
	}

	/* Skip replay when the on disk inode is newer than the log one */
@@ -2376,7 +2390,8 @@ xlog_recover_do_inode_trans(
			/* do nothing */
		} else {
			xfs_buf_relse(bp);
			return 0;
			error = 0;
			goto error;
		}
	}
	/* Take the opportunity to reset the flush iteration count */
@@ -2391,7 +2406,8 @@ xlog_recover_do_inode_trans(
			xfs_fs_cmn_err(CE_ALERT, mp,
				"xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
				item, dip, bp, ino);
			return XFS_ERROR(EFSCORRUPTED);
			error = EFSCORRUPTED;
			goto error;
		}
	} else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) {
		if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
@@ -2403,7 +2419,8 @@ xlog_recover_do_inode_trans(
			xfs_fs_cmn_err(CE_ALERT, mp,
				"xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
				item, dip, bp, ino);
			return XFS_ERROR(EFSCORRUPTED);
			error = EFSCORRUPTED;
			goto error;
		}
	}
	if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){
@@ -2415,7 +2432,8 @@ xlog_recover_do_inode_trans(
			item, dip, bp, ino,
			dicp->di_nextents + dicp->di_anextents,
			dicp->di_nblocks);
		return XFS_ERROR(EFSCORRUPTED);
		error = EFSCORRUPTED;
		goto error;
	}
	if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
		XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(6)",
@@ -2424,7 +2442,8 @@ xlog_recover_do_inode_trans(
		xfs_fs_cmn_err(CE_ALERT, mp,
			"xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x",
			item, dip, bp, ino, dicp->di_forkoff);
		return XFS_ERROR(EFSCORRUPTED);
		error = EFSCORRUPTED;
		goto error;
	}
	if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) {
		XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)",
@@ -2433,7 +2452,8 @@ xlog_recover_do_inode_trans(
		xfs_fs_cmn_err(CE_ALERT, mp,
			"xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p",
			item->ri_buf[1].i_len, item);
		return XFS_ERROR(EFSCORRUPTED);
		error = EFSCORRUPTED;
		goto error;
	}

	/* The core is in in-core format */
@@ -2521,7 +2541,8 @@ xlog_recover_do_inode_trans(
			xlog_warn("XFS: xlog_recover_do_inode_trans: Invalid flag");
			ASSERT(0);
			xfs_buf_relse(bp);
			return XFS_ERROR(EIO);
			error = EIO;
			goto error;
		}
	}

@@ -2537,7 +2558,10 @@ write_inode_buffer:
		error = xfs_bwrite(mp, bp);
	}

	return (error);
error:
	if (need_free)
		kmem_free(in_f, sizeof(*in_f));
	return XFS_ERROR(error);
}

/*
@@ -2674,32 +2698,32 @@ xlog_recover_do_dquot_trans(
 * structure into it, and adds the efi to the AIL with the given
 * LSN.
 */
STATIC void
STATIC int
xlog_recover_do_efi_trans(
	xlog_t			*log,
	xlog_recover_item_t	*item,
	xfs_lsn_t		lsn,
	int			pass)
{
	int			error;
	xfs_mount_t		*mp;
	xfs_efi_log_item_t	*efip;
	xfs_efi_log_format_t	*efi_formatp;
	SPLDECL(s);

	if (pass == XLOG_RECOVER_PASS1) {
		return;
		return 0;
	}

	efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
	ASSERT(item->ri_buf[0].i_len ==
	       (sizeof(xfs_efi_log_format_t) +
		((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))));

	mp = log->l_mp;
	efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
	memcpy((char *)&(efip->efi_format), (char *)efi_formatp,
	      sizeof(xfs_efi_log_format_t) +
	      ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)));
	if ((error = xfs_efi_copy_format(&(item->ri_buf[0]),
					 &(efip->efi_format)))) {
		xfs_efi_item_free(efip);
		return error;
	}
	efip->efi_next_extent = efi_formatp->efi_nextents;
	efip->efi_flags |= XFS_EFI_COMMITTED;

@@ -2708,6 +2732,7 @@ xlog_recover_do_efi_trans(
	 * xfs_trans_update_ail() drops the AIL lock.
	 */
	xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s);
	return 0;
}


@@ -2738,9 +2763,10 @@ xlog_recover_do_efd_trans(
	}

	efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
	ASSERT(item->ri_buf[0].i_len ==
	       (sizeof(xfs_efd_log_format_t) +
		((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t))));
	ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
		((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
	       (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
		((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t)))));
	efi_id = efd_formatp->efd_efi_id;

	/*
@@ -2810,15 +2836,14 @@ xlog_recover_do_trans(
			if  ((error = xlog_recover_do_buffer_trans(log, item,
								 pass)))
				break;
		} else if ((ITEM_TYPE(item) == XFS_LI_INODE) ||
			   (ITEM_TYPE(item) == XFS_LI_6_1_INODE) ||
			   (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) {
		} else if ((ITEM_TYPE(item) == XFS_LI_INODE)) {
			if ((error = xlog_recover_do_inode_trans(log, item,
								pass)))
				break;
		} else if (ITEM_TYPE(item) == XFS_LI_EFI) {
			xlog_recover_do_efi_trans(log, item, trans->r_lsn,
						  pass);
			if ((error = xlog_recover_do_efi_trans(log, item, trans->r_lsn,
						  pass)))
				break;
		} else if (ITEM_TYPE(item) == XFS_LI_EFD) {
			xlog_recover_do_efd_trans(log, item, pass);
		} else if (ITEM_TYPE(item) == XFS_LI_DQUOT) {
@@ -3798,7 +3823,7 @@ xlog_do_log_recovery(
	error = xlog_do_recovery_pass(log, head_blk, tail_blk,
				      XLOG_RECOVER_PASS2);
#ifdef DEBUG
	{
	if (!error) {
		int	i;

		for (i = 0; i < XLOG_BC_TABLE_SIZE; i++)