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

Commit eeb11688 authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner
Browse files

xfs: refactor xlog_recover_process_data()



Clean up xlog_recover_process_data() structure in preparation for
fixing the allocation and freeing context of the transaction being
recovered.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 52addcf9
Loading
Loading
Loading
Loading
+132 −76
Original line number Diff line number Diff line
@@ -3535,14 +3535,126 @@ xlog_recover_commit_trans(
}

STATIC int
xlog_recover_unmount_trans(
	struct xlog		*log)
xlog_recovery_process_trans(
	struct xlog		*log,
	struct xlog_recover	*trans,
	xfs_caddr_t		dp,
	unsigned int		len,
	unsigned int		flags,
	int			pass)
{
	/* Do nothing now */
	int			error = -EIO;

	/* mask off ophdr transaction container flags */
	flags &= ~XLOG_END_TRANS;
	if (flags & XLOG_WAS_CONT_TRANS)
		flags &= ~XLOG_CONTINUE_TRANS;

	switch (flags) {
	/* expected flag values */
	case 0:
	case XLOG_CONTINUE_TRANS:
		error = xlog_recover_add_to_trans(log, trans, dp, len);
		break;
	case XLOG_WAS_CONT_TRANS:
		error = xlog_recover_add_to_cont_trans(log, trans, dp, len);
		break;
	case XLOG_COMMIT_TRANS:
		error = xlog_recover_commit_trans(log, trans, pass);
		break;

	/* unexpected flag values */
	case XLOG_UNMOUNT_TRANS:
		xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
		error = 0; /* just skip trans */
		break;
	case XLOG_START_TRANS:
		xfs_warn(log->l_mp, "%s: bad transaction", __func__);
		ASSERT(0);
		break;
	default:
		xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags);
		ASSERT(0);
		break;
	}
	return error;
}

STATIC struct xlog_recover *
xlog_recover_ophdr_to_trans(
	struct hlist_head	rhash[],
	struct xlog_rec_header	*rhead,
	struct xlog_op_header	*ohead)
{
	struct xlog_recover	*trans;
	xlog_tid_t		tid;
	struct hlist_head	*rhp;

	tid = be32_to_cpu(ohead->oh_tid);
	rhp = &rhash[XLOG_RHASH(tid)];
	trans = xlog_recover_find_tid(rhp, tid);
	if (trans)
		return trans;

	/*
	 * If this is a new transaction, the ophdr only contains the
	 * start record. In that case, the only processing we need to do
	 * on this opheader is allocate a new recovery container to hold
	 * the recovery ops that will follow.
	 */
	if (ohead->oh_flags & XLOG_START_TRANS) {
		ASSERT(be32_to_cpu(ohead->oh_len) == 0);
		xlog_recover_new_tid(rhp, tid, be64_to_cpu(rhead->h_lsn));
	}
	return NULL;
}

STATIC int
xlog_recover_process_ophdr(
	struct xlog		*log,
	struct hlist_head	rhash[],
	struct xlog_rec_header	*rhead,
	struct xlog_op_header	*ohead,
	xfs_caddr_t		dp,
	xfs_caddr_t		end,
	int			pass)
{
	struct xlog_recover	*trans;
	int			error;
	unsigned int		len;

	/* Do we understand who wrote this op? */
	if (ohead->oh_clientid != XFS_TRANSACTION &&
	    ohead->oh_clientid != XFS_LOG) {
		xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
			__func__, ohead->oh_clientid);
		ASSERT(0);
		return -EIO;
	}

	/*
	 * Check the ophdr contains all the data it is supposed to contain.
	 */
	len = be32_to_cpu(ohead->oh_len);
	if (dp + len > end) {
		xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len);
		WARN_ON(1);
		return -EIO;
	}

	trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead);
	if (!trans) {
		/* nothing to do, so skip over this ophdr */
		return 0;
	}

	error = xlog_recovery_process_trans(log, trans, dp, len,
					    ohead->oh_flags, pass);
	if (error)
		xlog_recover_free_trans(trans);
	return error;
}

/*
 * There are two valid states of the r_state field.  0 indicates that the
 * transaction structure is in a normal state.  We have either seen the
@@ -3560,86 +3672,30 @@ xlog_recover_process_data(
	xfs_caddr_t		dp,
	int			pass)
{
	xfs_caddr_t		lp;
	struct xlog_op_header	*ohead;
	xfs_caddr_t		end;
	int			num_logops;
	xlog_op_header_t	*ohead;
	xlog_recover_t		*trans;
	xlog_tid_t		tid;
	int			error;
	unsigned long		hash;
	uint			flags;

	lp = dp + be32_to_cpu(rhead->h_len);
	end = dp + be32_to_cpu(rhead->h_len);
	num_logops = be32_to_cpu(rhead->h_num_logops);

	/* check the log format matches our own - else we can't recover */
	if (xlog_header_check_recover(log->l_mp, rhead))
		return -EIO;

	while ((dp < lp) && num_logops) {
		ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
		ohead = (xlog_op_header_t *)dp;
		dp += sizeof(xlog_op_header_t);
		if (ohead->oh_clientid != XFS_TRANSACTION &&
		    ohead->oh_clientid != XFS_LOG) {
			xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
					__func__, ohead->oh_clientid);
			ASSERT(0);
			return -EIO;
		}
		tid = be32_to_cpu(ohead->oh_tid);
		hash = XLOG_RHASH(tid);
		trans = xlog_recover_find_tid(&rhash[hash], tid);
		if (trans == NULL) {		   /* not found; add new tid */
			if (ohead->oh_flags & XLOG_START_TRANS)
				xlog_recover_new_tid(&rhash[hash], tid,
					be64_to_cpu(rhead->h_lsn));
		} else {
			if (dp + be32_to_cpu(ohead->oh_len) > lp) {
				xfs_warn(log->l_mp, "%s: bad length 0x%x",
					__func__, be32_to_cpu(ohead->oh_len));
				WARN_ON(1);
				return -EIO;
			}
			flags = ohead->oh_flags & ~XLOG_END_TRANS;
			if (flags & XLOG_WAS_CONT_TRANS)
				flags &= ~XLOG_CONTINUE_TRANS;
			switch (flags) {
			case XLOG_COMMIT_TRANS:
				error = xlog_recover_commit_trans(log,
								trans, pass);
				break;
			case XLOG_UNMOUNT_TRANS:
				error = xlog_recover_unmount_trans(log);
				break;
			case XLOG_WAS_CONT_TRANS:
				error = xlog_recover_add_to_cont_trans(log,
						trans, dp,
						be32_to_cpu(ohead->oh_len));
				break;
			case XLOG_START_TRANS:
				xfs_warn(log->l_mp, "%s: bad transaction",
					__func__);
				ASSERT(0);
				error = -EIO;
				break;
			case 0:
			case XLOG_CONTINUE_TRANS:
				error = xlog_recover_add_to_trans(log, trans,
						dp, be32_to_cpu(ohead->oh_len));
				break;
			default:
				xfs_warn(log->l_mp, "%s: bad flag 0x%x",
					__func__, flags);
				ASSERT(0);
				error = -EIO;
				break;
			}
			if (error) {
				xlog_recover_free_trans(trans);
	while ((dp < end) && num_logops) {

		ohead = (struct xlog_op_header *)dp;
		dp += sizeof(*ohead);
		ASSERT(dp <= end);

		/* errors will abort recovery */
		error = xlog_recover_process_ophdr(log, rhash, rhead, ohead,
						    dp, end, pass);
		if (error)
			return error;
			}
		}

		dp += be32_to_cpu(ohead->oh_len);
		num_logops--;
	}