Example #1
0
/*
 * Process operation work.
 *
 * For incoming requests, call the protocol request handler. The operation
 * result should be -EINPROGRESS at this point.
 *
 * For outgoing requests, the operation result value should have
 * been set before queueing this.  The operation callback function
 * allows the original requester to know the request has completed
 * and its result is available.
 */
static void gb_operation_work(struct work_struct *work)
{
	struct gb_operation *operation;

	operation = container_of(work, struct gb_operation, work);

	if (gb_operation_is_incoming(operation))
		gb_operation_request_handle(operation);
	else
		operation->callback(operation);

	gb_operation_put_active(operation);
	gb_operation_put(operation);
}
Example #2
0
/*
 * Cancel an outgoing operation synchronously, and record the given error to
 * indicate why.
 */
void gb_operation_cancel(struct gb_operation *operation, int errno)
{
	if (WARN_ON(gb_operation_is_incoming(operation)))
		return;

	if (gb_operation_result_set(operation, errno)) {
		gb_message_cancel(operation->request);
		queue_work(gb_operation_completion_wq, &operation->work);
	}
	trace_gb_message_cancel_outgoing(operation->request);

	atomic_inc(&operation->waiters);
	wait_event(gb_operation_cancellation_queue,
			!gb_operation_is_active(operation));
	atomic_dec(&operation->waiters);
}
Example #3
0
/*
 * Looks up an outgoing operation on a connection and returns a refcounted
 * pointer if found, or NULL otherwise.
 */
static struct gb_operation *
gb_operation_find_outgoing(struct gb_connection *connection, u16 operation_id)
{
	struct gb_operation *operation;
	unsigned long flags;
	bool found = false;

	spin_lock_irqsave(&connection->lock, flags);
	list_for_each_entry(operation, &connection->operations, links)
		if (operation->id == operation_id &&
				!gb_operation_is_incoming(operation)) {
			gb_operation_get(operation);
			found = true;
			break;
		}
	spin_unlock_irqrestore(&connection->lock, flags);

	return found ? operation : NULL;
}
Example #4
0
/*
 * Increment operation active count and add to connection list unless the
 * connection is going away.
 *
 * Caller holds operation reference.
 */
static int gb_operation_get_active(struct gb_operation *operation)
{
	struct gb_connection *connection = operation->connection;
	unsigned long flags;

	spin_lock_irqsave(&connection->lock, flags);

	if (connection->state != GB_CONNECTION_STATE_ENABLED &&
			connection->state != GB_CONNECTION_STATE_ENABLED_TX &&
			!gb_operation_is_incoming(operation)) {
		spin_unlock_irqrestore(&connection->lock, flags);
		return -ENOTCONN;
	}

	if (operation->active++ == 0)
		list_add_tail(&operation->links, &connection->operations);

	spin_unlock_irqrestore(&connection->lock, flags);

	return 0;
}
Example #5
0
/*
 * Cancel an incoming operation synchronously. Called during connection tear
 * down.
 */
void gb_operation_cancel_incoming(struct gb_operation *operation, int errno)
{
	if (WARN_ON(!gb_operation_is_incoming(operation)))
		return;

	if (!gb_operation_is_unidirectional(operation)) {
		/*
		 * Make sure the request handler has submitted the response
		 * before cancelling it.
		 */
		flush_work(&operation->work);
		if (!gb_operation_result_set(operation, errno))
			gb_message_cancel(operation->response);
	}
	trace_gb_message_cancel_incoming(operation->response);

	atomic_inc(&operation->waiters);
	wait_event(gb_operation_cancellation_queue,
			!gb_operation_is_active(operation));
	atomic_dec(&operation->waiters);
}
Example #6
0
/*
 * Cancel all active operations on a connection.
 *
 * Should only be called during connection tear down.
 */
static void gb_connection_cancel_operations(struct gb_connection *connection,
						int errno)
{
	struct gb_operation *operation;

	spin_lock_irq(&connection->lock);
	while (!list_empty(&connection->operations)) {
		operation = list_last_entry(&connection->operations,
						struct gb_operation, links);
		gb_operation_get(operation);
		spin_unlock_irq(&connection->lock);

		if (gb_operation_is_incoming(operation))
			gb_operation_cancel_incoming(operation, errno);
		else
			gb_operation_cancel(operation, errno);

		gb_operation_put(operation);

		spin_lock_irq(&connection->lock);
	}
	spin_unlock_irq(&connection->lock);
}