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

Commit 42ceedb3 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Ben Myers
Browse files

xfs: share code for grant head availability checks



Reviewed-by: default avatarMark Tinguely <tinguely@sgi.com>
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 e179840d
Loading
Loading
Loading
Loading
+60 −73
Original line number Diff line number Diff line
@@ -245,6 +245,60 @@ xlog_grant_head_wait(
	return XFS_ERROR(EIO);
}

/*
 * Atomically get the log space required for a log ticket.
 *
 * Once a ticket gets put onto head->waiters, it will only return after the
 * needed reservation is satisfied.
 *
 * This function is structured so that it has a lock free fast path. This is
 * necessary because every new transaction reservation will come through this
 * path. Hence any lock will be globally hot if we take it unconditionally on
 * every pass.
 *
 * As tickets are only ever moved on and off head->waiters under head->lock, we
 * only need to take that lock if we are going to add the ticket to the queue
 * and sleep. We can avoid taking the lock if the ticket was never added to
 * head->waiters because the t_queue list head will be empty and we hold the
 * only reference to it so it can safely be checked unlocked.
 */
STATIC int
xlog_grant_head_check(
	struct log		*log,
	struct xlog_grant_head	*head,
	struct xlog_ticket	*tic,
	int			*need_bytes)
{
	int			free_bytes;
	int			error = 0;

	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));

	/*
	 * If there are other waiters on the queue then give them a chance at
	 * logspace before us.  Wake up the first waiters, if we do not wake
	 * up all the waiters then go to sleep waiting for more free space,
	 * otherwise try to get some space for this transaction.
	 */
	*need_bytes = xlog_ticket_reservation(log, head, tic);
	free_bytes = xlog_space_left(log, &head->grant);
	if (!list_empty_careful(&head->waiters)) {
		spin_lock(&head->lock);
		if (!xlog_grant_head_wake(log, head, &free_bytes) ||
		    free_bytes < *need_bytes) {
			error = xlog_grant_head_wait(log, head, tic,
						     *need_bytes);
		}
		spin_unlock(&head->lock);
	} else if (free_bytes < *need_bytes) {
		spin_lock(&head->lock);
		error = xlog_grant_head_wait(log, head, tic, *need_bytes);
		spin_unlock(&head->lock);
	}

	return error;
}

static void
xlog_tic_reset_res(xlog_ticket_t *tic)
{
@@ -2511,59 +2565,18 @@ xlog_state_get_iclog_space(xlog_t *log,
	return 0;
}	/* xlog_state_get_iclog_space */

/*
 * Atomically get the log space required for a log ticket.
 *
 * Once a ticket gets put onto the reserveq, it will only return after the
 * needed reservation is satisfied.
 *
 * This function is structured so that it has a lock free fast path. This is
 * necessary because every new transaction reservation will come through this
 * path. Hence any lock will be globally hot if we take it unconditionally on
 * every pass.
 *
 * As tickets are only ever moved on and off the l_reserve.waiters under the
 * l_reserve.lock, we only need to take that lock if we are going to add
 * the ticket to the queue and sleep. We can avoid taking the lock if the ticket
 * was never added to the reserveq because the t_queue list head will be empty
 * and we hold the only reference to it so it can safely be checked unlocked.
 */
STATIC int
xlog_grant_log_space(
	struct log		*log,
	struct xlog_ticket	*tic)
{
	int			free_bytes, need_bytes;
	int			need_bytes;
	int			error = 0;

	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));

	trace_xfs_log_grant_enter(log, tic);

	/*
	 * If there are other waiters on the queue then give them a chance at
	 * logspace before us.  Wake up the first waiters, if we do not wake
	 * up all the waiters then go to sleep waiting for more free space,
	 * otherwise try to get some space for this transaction.
	 */
	need_bytes = tic->t_unit_res;
	if (tic->t_flags & XFS_LOG_PERM_RESERV)
		need_bytes *= tic->t_ocnt;
	free_bytes = xlog_space_left(log, &log->l_reserve_head.grant);
	if (!list_empty_careful(&log->l_reserve_head.waiters)) {
		spin_lock(&log->l_reserve_head.lock);
		if (!xlog_grant_head_wake(log, &log->l_reserve_head, &free_bytes) ||
		    free_bytes < need_bytes) {
			error = xlog_grant_head_wait(log, &log->l_reserve_head,
						     tic, need_bytes);
		}
		spin_unlock(&log->l_reserve_head.lock);
	} else if (free_bytes < need_bytes) {
		spin_lock(&log->l_reserve_head.lock);
		error = xlog_grant_head_wait(log, &log->l_reserve_head, tic,
					     need_bytes);
		spin_unlock(&log->l_reserve_head.lock);
	}
	error = xlog_grant_head_check(log, &log->l_reserve_head, tic,
				      &need_bytes);
	if (error)
		return error;

@@ -2576,16 +2589,13 @@ xlog_grant_log_space(

/*
 * Replenish the byte reservation required by moving the grant write head.
 *
 * Similar to xlog_grant_log_space, the function is structured to have a lock
 * free fast path.
 */
STATIC int
xlog_regrant_write_log_space(
	struct log		*log,
	struct xlog_ticket	*tic)
{
	int			free_bytes, need_bytes;
	int			need_bytes;
	int			error = 0;

	tic->t_curr_res = tic->t_unit_res;
@@ -2594,33 +2604,10 @@ xlog_regrant_write_log_space(
	if (tic->t_cnt > 0)
		return 0;

	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));

	trace_xfs_log_regrant_write_enter(log, tic);

	/*
	 * If there are other waiters on the queue then give them a chance at
	 * logspace before us.  Wake up the first waiters, if we do not wake
	 * up all the waiters then go to sleep waiting for more free space,
	 * otherwise try to get some space for this transaction.
	 */
	need_bytes = tic->t_unit_res;
	free_bytes = xlog_space_left(log, &log->l_write_head.grant);
	if (!list_empty_careful(&log->l_write_head.waiters)) {
		spin_lock(&log->l_write_head.lock);
		if (!xlog_grant_head_wake(log, &log->l_write_head, &free_bytes) ||
		    free_bytes < need_bytes) {
			error = xlog_grant_head_wait(log, &log->l_write_head,
						     tic, need_bytes);
		}
		spin_unlock(&log->l_write_head.lock);
	} else if (free_bytes < need_bytes) {
		spin_lock(&log->l_write_head.lock);
		error = xlog_grant_head_wait(log, &log->l_write_head, tic,
					     need_bytes);
		spin_unlock(&log->l_write_head.lock);
	}

	error = xlog_grant_head_check(log, &log->l_write_head, tic,
				      &need_bytes);
	if (error)
		return error;