Commit 154c733a authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: refactor releasing finished intents during log recovery



Replace the open-coded AIL item walking with a proper helper when we're
trying to release an intent item that has been finished.  We add a new
->iop_match method to decide if an intent item matches a supplied ID.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarChandan Babu R <chandanrlinux@gmail.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent bba7b164
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -125,4 +125,7 @@ bool xlog_is_buffer_cancelled(struct xlog *log, xfs_daddr_t blkno, uint len);
bool xlog_put_buffer_cancelled(struct xlog *log, xfs_daddr_t blkno, uint len);
void xlog_recover_iodone(struct xfs_buf *bp);

void xlog_recover_release_intent(struct xlog *log, unsigned short intent_type,
		uint64_t intent_id);

#endif	/* __XFS_LOG_RECOVER_H__ */
+10 −32
Original line number Diff line number Diff line
@@ -578,12 +578,21 @@ xfs_bui_item_recover(
	return error;
}

STATIC bool
xfs_bui_item_match(
	struct xfs_log_item	*lip,
	uint64_t		intent_id)
{
	return BUI_ITEM(lip)->bui_format.bui_id == intent_id;
}

static const struct xfs_item_ops xfs_bui_item_ops = {
	.iop_size	= xfs_bui_item_size,
	.iop_format	= xfs_bui_item_format,
	.iop_unpin	= xfs_bui_item_unpin,
	.iop_release	= xfs_bui_item_release,
	.iop_recover	= xfs_bui_item_recover,
	.iop_match	= xfs_bui_item_match,
};

/*
@@ -675,45 +684,14 @@ xlog_recover_bud_commit_pass2(
	xfs_lsn_t			lsn)
{
	struct xfs_bud_log_format	*bud_formatp;
	struct xfs_bui_log_item		*buip = NULL;
	struct xfs_log_item		*lip;
	uint64_t			bui_id;
	struct xfs_ail_cursor		cur;
	struct xfs_ail			*ailp = log->l_ailp;

	bud_formatp = item->ri_buf[0].i_addr;
	if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
		return -EFSCORRUPTED;
	}
	bui_id = bud_formatp->bud_bui_id;

	/*
	 * Search for the BUI with the id in the BUD format structure in the
	 * AIL.
	 */
	spin_lock(&ailp->ail_lock);
	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
	while (lip != NULL) {
		if (lip->li_type == XFS_LI_BUI) {
			buip = (struct xfs_bui_log_item *)lip;
			if (buip->bui_format.bui_id == bui_id) {
				/*
				 * Drop the BUD reference to the BUI. This
				 * removes the BUI from the AIL and frees it.
				 */
				spin_unlock(&ailp->ail_lock);
				xfs_bui_release(buip);
				spin_lock(&ailp->ail_lock);
				break;
			}
		}
		lip = xfs_trans_ail_cursor_next(ailp, &cur);
	}

	xfs_trans_ail_cursor_done(&cur);
	spin_unlock(&ailp->ail_lock);

	xlog_recover_release_intent(log, XFS_LI_BUI, bud_formatp->bud_bui_id);
	return 0;
}

+10 −32
Original line number Diff line number Diff line
@@ -665,12 +665,21 @@ xfs_efi_item_recover(
	return error;
}

STATIC bool
xfs_efi_item_match(
	struct xfs_log_item	*lip,
	uint64_t		intent_id)
{
	return EFI_ITEM(lip)->efi_format.efi_id == intent_id;
}

static const struct xfs_item_ops xfs_efi_item_ops = {
	.iop_size	= xfs_efi_item_size,
	.iop_format	= xfs_efi_item_format,
	.iop_unpin	= xfs_efi_item_unpin,
	.iop_release	= xfs_efi_item_release,
	.iop_recover	= xfs_efi_item_recover,
	.iop_match	= xfs_efi_item_match,
};

/*
@@ -733,46 +742,15 @@ xlog_recover_efd_commit_pass2(
	struct xlog_recover_item	*item,
	xfs_lsn_t			lsn)
{
	struct xfs_ail_cursor		cur;
	struct xfs_efd_log_format	*efd_formatp;
	struct xfs_efi_log_item		*efip = NULL;
	struct xfs_log_item		*lip;
	struct xfs_ail			*ailp = log->l_ailp;
	uint64_t			efi_id;

	efd_formatp = item->ri_buf[0].i_addr;
	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;

	/*
	 * Search for the EFI with the id in the EFD format structure in the
	 * AIL.
	 */
	spin_lock(&ailp->ail_lock);
	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
	while (lip != NULL) {
		if (lip->li_type == XFS_LI_EFI) {
			efip = (struct xfs_efi_log_item *)lip;
			if (efip->efi_format.efi_id == efi_id) {
				/*
				 * Drop the EFD reference to the EFI. This
				 * removes the EFI from the AIL and frees it.
				 */
				spin_unlock(&ailp->ail_lock);
				xfs_efi_release(efip);
				spin_lock(&ailp->ail_lock);
				break;
			}
		}
		lip = xfs_trans_ail_cursor_next(ailp, &cur);
	}

	xfs_trans_ail_cursor_done(&cur);
	spin_unlock(&ailp->ail_lock);

	xlog_recover_release_intent(log, XFS_LI_EFI, efd_formatp->efd_efi_id);
	return 0;
}

+34 −1
Original line number Diff line number Diff line
@@ -1779,6 +1779,38 @@ xlog_clear_stale_blocks(
	return 0;
}

/*
 * Release the recovered intent item in the AIL that matches the given intent
 * type and intent id.
 */
void
xlog_recover_release_intent(
	struct xlog		*log,
	unsigned short		intent_type,
	uint64_t		intent_id)
{
	struct xfs_ail_cursor	cur;
	struct xfs_log_item	*lip;
	struct xfs_ail		*ailp = log->l_ailp;

	spin_lock(&ailp->ail_lock);
	for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); lip != NULL;
	     lip = xfs_trans_ail_cursor_next(ailp, &cur)) {
		if (lip->li_type != intent_type)
			continue;
		if (!lip->li_ops->iop_match(lip, intent_id))
			continue;

		spin_unlock(&ailp->ail_lock);
		lip->li_ops->iop_release(lip);
		spin_lock(&ailp->ail_lock);
		break;
	}

	xfs_trans_ail_cursor_done(&cur);
	spin_unlock(&ailp->ail_lock);
}

/******************************************************************************
 *
 *		Log recover routines
@@ -2583,7 +2615,8 @@ xlog_finish_defer_ops(
/* Is this log item a deferred action intent? */
static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
{
	return lip->li_ops->iop_recover != NULL;
	return lip->li_ops->iop_recover != NULL &&
	       lip->li_ops->iop_match != NULL;
}

/*
+10 −32
Original line number Diff line number Diff line
@@ -591,12 +591,21 @@ xfs_cui_item_recover(
	return error;
}

STATIC bool
xfs_cui_item_match(
	struct xfs_log_item	*lip,
	uint64_t		intent_id)
{
	return CUI_ITEM(lip)->cui_format.cui_id == intent_id;
}

static const struct xfs_item_ops xfs_cui_item_ops = {
	.iop_size	= xfs_cui_item_size,
	.iop_format	= xfs_cui_item_format,
	.iop_unpin	= xfs_cui_item_unpin,
	.iop_release	= xfs_cui_item_release,
	.iop_recover	= xfs_cui_item_recover,
	.iop_match	= xfs_cui_item_match,
};

/*
@@ -684,45 +693,14 @@ xlog_recover_cud_commit_pass2(
	xfs_lsn_t			lsn)
{
	struct xfs_cud_log_format	*cud_formatp;
	struct xfs_cui_log_item		*cuip = NULL;
	struct xfs_log_item		*lip;
	uint64_t			cui_id;
	struct xfs_ail_cursor		cur;
	struct xfs_ail			*ailp = log->l_ailp;

	cud_formatp = item->ri_buf[0].i_addr;
	if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
		return -EFSCORRUPTED;
	}
	cui_id = cud_formatp->cud_cui_id;

	/*
	 * Search for the CUI with the id in the CUD format structure in the
	 * AIL.
	 */
	spin_lock(&ailp->ail_lock);
	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
	while (lip != NULL) {
		if (lip->li_type == XFS_LI_CUI) {
			cuip = (struct xfs_cui_log_item *)lip;
			if (cuip->cui_format.cui_id == cui_id) {
				/*
				 * Drop the CUD reference to the CUI. This
				 * removes the CUI from the AIL and frees it.
				 */
				spin_unlock(&ailp->ail_lock);
				xfs_cui_release(cuip);
				spin_lock(&ailp->ail_lock);
				break;
			}
		}
		lip = xfs_trans_ail_cursor_next(ailp, &cur);
	}

	xfs_trans_ail_cursor_done(&cur);
	spin_unlock(&ailp->ail_lock);

	xlog_recover_release_intent(log, XFS_LI_CUI, cud_formatp->cud_cui_id);
	return 0;
}

Loading