root/net/rxrpc/call_state.c
// SPDX-License-Identifier: GPL-2.0-or-later
/* Call state changing functions.
 *
 * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 */

#include "ar-internal.h"

/*
 * Transition a call to the complete state.
 */
bool rxrpc_set_call_completion(struct rxrpc_call *call,
                                 enum rxrpc_call_completion compl,
                                 u32 abort_code,
                                 int error)
{
        if (__rxrpc_call_state(call) == RXRPC_CALL_COMPLETE)
                return false;

        call->abort_code = abort_code;
        call->error = error;
        call->completion = compl;
        /* Allow reader of completion state to operate locklessly */
        rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
        trace_rxrpc_call_complete(call);
        wake_up(&call->waitq);
        rxrpc_notify_socket(call);
        return true;
}

/*
 * Record that a call successfully completed.
 */
bool rxrpc_call_completed(struct rxrpc_call *call)
{
        return rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
}

/*
 * Record that a call is locally aborted.
 */
bool rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
                      u32 abort_code, int error, enum rxrpc_abort_reason why)
{
        trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
                          abort_code, error);
        if (!rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
                                       abort_code, error))
                return false;
        if (test_bit(RXRPC_CALL_EXPOSED, &call->flags))
                rxrpc_send_abort_packet(call);
        return true;
}

/*
 * Record that a call errored out before even getting off the ground, thereby
 * setting the state to allow it to be destroyed.
 */
void rxrpc_prefail_call(struct rxrpc_call *call, enum rxrpc_call_completion compl,
                        int error)
{
        call->abort_code        = RX_CALL_DEAD;
        call->error             = error;
        call->completion        = compl;
        call->_state            = RXRPC_CALL_COMPLETE;
        trace_rxrpc_call_complete(call);
        WARN_ON_ONCE(__test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags));
}