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

Commit 562da8e7 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Greg Kroah-Hartman
Browse files

xfs: refactor xfs_defer_finish_noroll



commit bb47d79750f1a68a75d4c7defc2da934ba31de14 upstream.

Split out a helper that operates on a single xfs_defer_pending structure
to untangle the code.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarChandan Babu R <chandan.babu@oracle.com>
Acked-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 42a2406f
Loading
Loading
Loading
Loading
+59 −69
Original line number Diff line number Diff line
@@ -359,6 +359,53 @@ xfs_defer_cancel_list(
	}
}

/*
 * Log an intent-done item for the first pending intent, and finish the work
 * items.
 */
static int
xfs_defer_finish_one(
	struct xfs_trans		*tp,
	struct xfs_defer_pending	*dfp)
{
	const struct xfs_defer_op_type	*ops = defer_op_types[dfp->dfp_type];
	void				*state = NULL;
	struct list_head		*li, *n;
	int				error;

	trace_xfs_defer_pending_finish(tp->t_mountp, dfp);

	dfp->dfp_done = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count);
	list_for_each_safe(li, n, &dfp->dfp_work) {
		list_del(li);
		dfp->dfp_count--;
		error = ops->finish_item(tp, li, dfp->dfp_done, &state);
		if (error == -EAGAIN) {
			/*
			 * Caller wants a fresh transaction; put the work item
			 * back on the list and log a new log intent item to
			 * replace the old one.  See "Requesting a Fresh
			 * Transaction while Finishing Deferred Work" above.
			 */
			list_add(li, &dfp->dfp_work);
			dfp->dfp_count++;
			dfp->dfp_done = NULL;
			xfs_defer_create_intent(tp, dfp, false);
		}

		if (error)
			goto out;
	}

	/* Done with the dfp, free it. */
	list_del(&dfp->dfp_list);
	kmem_free(dfp);
out:
	if (ops->finish_cleanup)
		ops->finish_cleanup(tp, state, error);
	return error;
}

/*
 * Finish all the pending work.  This involves logging intent items for
 * any work items that wandered in since the last transaction roll (if
@@ -372,11 +419,7 @@ xfs_defer_finish_noroll(
	struct xfs_trans		**tp)
{
	struct xfs_defer_pending	*dfp;
	struct list_head		*li;
	struct list_head		*n;
	void				*state;
	int				error = 0;
	const struct xfs_defer_op_type	*ops;
	LIST_HEAD(dop_pending);

	ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
@@ -385,73 +428,24 @@ xfs_defer_finish_noroll(

	/* Until we run out of pending work to finish... */
	while (!list_empty(&dop_pending) || !list_empty(&(*tp)->t_dfops)) {
		/* log intents and pull in intake items */
		xfs_defer_create_intents(*tp);
		list_splice_tail_init(&(*tp)->t_dfops, &dop_pending);

		/*
		 * Roll the transaction.
		 */
		error = xfs_defer_trans_roll(tp);
		if (error)
			goto out;
			goto out_shutdown;

		/* Log an intent-done item for the first pending item. */
		dfp = list_first_entry(&dop_pending, struct xfs_defer_pending,
				       dfp_list);
		ops = defer_op_types[dfp->dfp_type];
		trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp);
		dfp->dfp_done = ops->create_done(*tp, dfp->dfp_intent,
				dfp->dfp_count);

		/* Finish the work items. */
		state = NULL;
		list_for_each_safe(li, n, &dfp->dfp_work) {
			list_del(li);
			dfp->dfp_count--;
			error = ops->finish_item(*tp, li, dfp->dfp_done,
					&state);
			if (error == -EAGAIN) {
				/*
				 * Caller wants a fresh transaction;
				 * put the work item back on the list
				 * and jump out.
				 */
				list_add(li, &dfp->dfp_work);
				dfp->dfp_count++;
				break;
			} else if (error) {
				/*
				 * Clean up after ourselves and jump out.
				 * xfs_defer_cancel will take care of freeing
				 * all these lists and stuff.
				 */
				if (ops->finish_cleanup)
					ops->finish_cleanup(*tp, state, error);
				goto out;
			}
		}
		if (error == -EAGAIN) {
			/*
			 * Caller wants a fresh transaction, so log a new log
			 * intent item to replace the old one and roll the
			 * transaction.  See "Requesting a Fresh Transaction
			 * while Finishing Deferred Work" above.
			 */
			dfp->dfp_done = NULL;
			xfs_defer_create_intent(*tp, dfp, false);
		} else {
			/* Done with the dfp, free it. */
			list_del(&dfp->dfp_list);
			kmem_free(dfp);
		error = xfs_defer_finish_one(*tp, dfp);
		if (error && error != -EAGAIN)
			goto out_shutdown;
	}

		if (ops->finish_cleanup)
			ops->finish_cleanup(*tp, state, error);
	}
	trace_xfs_defer_finish_done(*tp, _RET_IP_);
	return 0;

out:
	if (error) {
out_shutdown:
	xfs_defer_trans_abort(*tp, &dop_pending);
	xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE);
	trace_xfs_defer_finish_error(*tp, error);
@@ -460,10 +454,6 @@ xfs_defer_finish_noroll(
	return error;
}

	trace_xfs_defer_finish_done(*tp, _RET_IP_);
	return 0;
}

int
xfs_defer_finish(
	struct xfs_trans	**tp)