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

Commit 0244b960 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Ben Myers
Browse files

xfs: cleanup the transaction commit path a bit



Now that the nodelaylog mode is gone we can simplify the transaction commit
path a bit by removing the xfs_trans_commit_cil routine.  Restoring the
process flags is merged into xfs_trans_commit which already does it for
the error path, and allocating the log vectors is merged into
xlog_cil_format_items, which already fills them with data, thus avoiding
one loop over all log items.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 93b8a585
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -184,8 +184,7 @@ void xlog_iodone(struct xfs_buf *);
struct xlog_ticket *xfs_log_ticket_get(struct xlog_ticket *ticket);
void	  xfs_log_ticket_put(struct xlog_ticket *ticket);

void	xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
				struct xfs_log_vec *log_vector,
int	xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
				xfs_lsn_t *commit_lsn, int flags);
bool	xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);

+58 −20
Original line number Diff line number Diff line
@@ -159,37 +159,72 @@ xlog_cil_init_post_recovery(
 * format the regions into the iclog as though they are being formatted
 * directly out of the objects themselves.
 */
static void
xlog_cil_format_items(
	struct log		*log,
	struct xfs_log_vec	*log_vector)
static struct xfs_log_vec *
xlog_cil_prepare_log_vecs(
	struct xfs_trans	*tp)
{
	struct xfs_log_vec *lv;
	struct xfs_log_item_desc *lidp;
	struct xfs_log_vec	*lv = NULL;
	struct xfs_log_vec	*ret_lv = NULL;

	ASSERT(log_vector);
	for (lv = log_vector; lv; lv = lv->lv_next) {

	/* Bail out if we didn't find a log item.  */
	if (list_empty(&tp->t_items)) {
		ASSERT(0);
		return NULL;
	}

	list_for_each_entry(lidp, &tp->t_items, lid_trans) {
		struct xfs_log_vec *new_lv;
		void	*ptr;
		int	index;
		int	len = 0;

		/* Skip items which aren't dirty in this transaction. */
		if (!(lidp->lid_flags & XFS_LID_DIRTY))
			continue;

		/* Skip items that do not have any vectors for writing */
		lidp->lid_size = IOP_SIZE(lidp->lid_item);
		if (!lidp->lid_size)
			continue;

		new_lv = kmem_zalloc(sizeof(*new_lv) +
				lidp->lid_size * sizeof(struct xfs_log_iovec),
				KM_SLEEP);

		/* The allocated iovec region lies beyond the log vector. */
		new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
		new_lv->lv_niovecs = lidp->lid_size;
		new_lv->lv_item = lidp->lid_item;

		/* build the vector array and calculate it's length */
		IOP_FORMAT(lv->lv_item, lv->lv_iovecp);
		for (index = 0; index < lv->lv_niovecs; index++)
			len += lv->lv_iovecp[index].i_len;
		IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp);
		for (index = 0; index < new_lv->lv_niovecs; index++)
			len += new_lv->lv_iovecp[index].i_len;

		lv->lv_buf_len = len;
		lv->lv_buf = kmem_alloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
		ptr = lv->lv_buf;
		new_lv->lv_buf_len = len;
		new_lv->lv_buf = kmem_alloc(new_lv->lv_buf_len,
				KM_SLEEP|KM_NOFS);
		ptr = new_lv->lv_buf;

		for (index = 0; index < lv->lv_niovecs; index++) {
			struct xfs_log_iovec *vec = &lv->lv_iovecp[index];
		for (index = 0; index < new_lv->lv_niovecs; index++) {
			struct xfs_log_iovec *vec = &new_lv->lv_iovecp[index];

			memcpy(ptr, vec->i_addr, vec->i_len);
			vec->i_addr = ptr;
			ptr += vec->i_len;
		}
		ASSERT(ptr == lv->lv_buf + lv->lv_buf_len);
		ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len);

		if (!ret_lv)
			ret_lv = new_lv;
		else
			lv->lv_next = new_lv;
		lv = new_lv;
	}

	return ret_lv;
}

/*
@@ -622,28 +657,30 @@ xlog_cil_push(
 * background commit, returns without it held once background commits are
 * allowed again.
 */
void
int
xfs_log_commit_cil(
	struct xfs_mount	*mp,
	struct xfs_trans	*tp,
	struct xfs_log_vec	*log_vector,
	xfs_lsn_t		*commit_lsn,
	int			flags)
{
	struct log		*log = mp->m_log;
	int			log_flags = 0;
	int			push = 0;
	struct xfs_log_vec	*log_vector;

	if (flags & XFS_TRANS_RELEASE_LOG_RES)
		log_flags = XFS_LOG_REL_PERM_RESERV;

	/*
	 * do all the hard work of formatting items (including memory
	 * Do all the hard work of formatting items (including memory
	 * allocation) outside the CIL context lock. This prevents stalling CIL
	 * pushes when we are low on memory and a transaction commit spends a
	 * lot of time in memory reclaim.
	 */
	xlog_cil_format_items(log, log_vector);
	log_vector = xlog_cil_prepare_log_vecs(tp);
	if (!log_vector)
		return ENOMEM;

	/* lock out background commit */
	down_read(&log->l_cilp->xc_ctx_lock);
@@ -696,6 +733,7 @@ xfs_log_commit_cil(
	 */
	if (push)
		xlog_cil_push(log, 0);
	return 0;
}

/*
+4 −77
Original line number Diff line number Diff line
@@ -1324,82 +1324,6 @@ xfs_trans_committed_bulk(
	spin_unlock(&ailp->xa_lock);
}

/*
 * Walk the log items and allocate log vector structures for
 * each item large enough to fit all the vectors they require.
 * Note that this format differs from the old log vector format in
 * that there is no transaction header in these log vectors.
 */
STATIC struct xfs_log_vec *
xfs_trans_alloc_log_vecs(
	xfs_trans_t	*tp)
{
	struct xfs_log_item_desc *lidp;
	struct xfs_log_vec	*lv = NULL;
	struct xfs_log_vec	*ret_lv = NULL;


	/* Bail out if we didn't find a log item.  */
	if (list_empty(&tp->t_items)) {
		ASSERT(0);
		return NULL;
	}

	list_for_each_entry(lidp, &tp->t_items, lid_trans) {
		struct xfs_log_vec *new_lv;

		/* Skip items which aren't dirty in this transaction. */
		if (!(lidp->lid_flags & XFS_LID_DIRTY))
			continue;

		/* Skip items that do not have any vectors for writing */
		lidp->lid_size = IOP_SIZE(lidp->lid_item);
		if (!lidp->lid_size)
			continue;

		new_lv = kmem_zalloc(sizeof(*new_lv) +
				lidp->lid_size * sizeof(struct xfs_log_iovec),
				KM_SLEEP);

		/* The allocated iovec region lies beyond the log vector. */
		new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
		new_lv->lv_niovecs = lidp->lid_size;
		new_lv->lv_item = lidp->lid_item;
		if (!ret_lv)
			ret_lv = new_lv;
		else
			lv->lv_next = new_lv;
		lv = new_lv;
	}

	return ret_lv;
}

static int
xfs_trans_commit_cil(
	struct xfs_mount	*mp,
	struct xfs_trans	*tp,
	xfs_lsn_t		*commit_lsn,
	int			flags)
{
	struct xfs_log_vec	*log_vector;

	/*
	 * Get each log item to allocate a vector structure for
	 * the log item to to pass to the log write code. The
	 * CIL commit code will format the vector and save it away.
	 */
	log_vector = xfs_trans_alloc_log_vecs(tp);
	if (!log_vector)
		return ENOMEM;

	xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);

	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	xfs_trans_free(tp);
	return 0;
}

/*
 * Commit the given transaction to the log.
 *
@@ -1456,13 +1380,16 @@ xfs_trans_commit(
		xfs_trans_apply_sb_deltas(tp);
	xfs_trans_apply_dquot_deltas(tp);

	error = xfs_trans_commit_cil(mp, tp, &commit_lsn, flags);
	error = xfs_log_commit_cil(mp, tp, &commit_lsn, flags);
	if (error == ENOMEM) {
		xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
		error = XFS_ERROR(EIO);
		goto out_unreserve;
	}

	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	xfs_trans_free(tp);

	/*
	 * If the transaction needs to be synchronous, then force the
	 * log out now and wait for it.