1*02a19356SDavid Howells // SPDX-License-Identifier: GPL-2.0-or-later 2*02a19356SDavid Howells /* RxRPC Tx data buffering. 3*02a19356SDavid Howells * 4*02a19356SDavid Howells * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved. 5*02a19356SDavid Howells * Written by David Howells (dhowells@redhat.com) 6*02a19356SDavid Howells */ 7*02a19356SDavid Howells 8*02a19356SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9*02a19356SDavid Howells 10*02a19356SDavid Howells #include <linux/slab.h> 11*02a19356SDavid Howells #include "ar-internal.h" 12*02a19356SDavid Howells 13*02a19356SDavid Howells static atomic_t rxrpc_txbuf_debug_ids; 14*02a19356SDavid Howells atomic_t rxrpc_nr_txbuf; 15*02a19356SDavid Howells 16*02a19356SDavid Howells /* 17*02a19356SDavid Howells * Allocate and partially initialise an I/O request structure. 18*02a19356SDavid Howells */ 19*02a19356SDavid Howells struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, 20*02a19356SDavid Howells gfp_t gfp) 21*02a19356SDavid Howells { 22*02a19356SDavid Howells struct rxrpc_txbuf *txb; 23*02a19356SDavid Howells 24*02a19356SDavid Howells txb = kmalloc(sizeof(*txb), gfp); 25*02a19356SDavid Howells if (txb) { 26*02a19356SDavid Howells INIT_LIST_HEAD(&txb->call_link); 27*02a19356SDavid Howells INIT_LIST_HEAD(&txb->tx_link); 28*02a19356SDavid Howells refcount_set(&txb->ref, 1); 29*02a19356SDavid Howells txb->call = call; 30*02a19356SDavid Howells txb->call_debug_id = call->debug_id; 31*02a19356SDavid Howells txb->debug_id = atomic_inc_return(&rxrpc_txbuf_debug_ids); 32*02a19356SDavid Howells txb->space = sizeof(txb->data); 33*02a19356SDavid Howells txb->len = 0; 34*02a19356SDavid Howells txb->offset = 0; 35*02a19356SDavid Howells txb->flags = 0; 36*02a19356SDavid Howells txb->seq = call->tx_top + 1; 37*02a19356SDavid Howells txb->wire.epoch = htonl(call->conn->proto.epoch); 38*02a19356SDavid Howells txb->wire.cid = htonl(call->cid); 39*02a19356SDavid Howells txb->wire.callNumber = htonl(call->call_id); 40*02a19356SDavid Howells txb->wire.seq = htonl(txb->seq); 41*02a19356SDavid Howells txb->wire.type = packet_type; 42*02a19356SDavid Howells txb->wire.flags = call->conn->out_clientflag; 43*02a19356SDavid Howells txb->wire.userStatus = 0; 44*02a19356SDavid Howells txb->wire.securityIndex = call->security_ix; 45*02a19356SDavid Howells txb->wire._rsvd = 0; 46*02a19356SDavid Howells txb->wire.serviceId = htons(call->service_id); 47*02a19356SDavid Howells 48*02a19356SDavid Howells trace_rxrpc_txbuf(txb->debug_id, 49*02a19356SDavid Howells txb->call_debug_id, txb->seq, 1, 50*02a19356SDavid Howells packet_type == RXRPC_PACKET_TYPE_DATA ? 51*02a19356SDavid Howells rxrpc_txbuf_alloc_data : 52*02a19356SDavid Howells rxrpc_txbuf_alloc_ack); 53*02a19356SDavid Howells atomic_inc(&rxrpc_nr_txbuf); 54*02a19356SDavid Howells } 55*02a19356SDavid Howells 56*02a19356SDavid Howells return txb; 57*02a19356SDavid Howells } 58*02a19356SDavid Howells 59*02a19356SDavid Howells void rxrpc_get_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 60*02a19356SDavid Howells { 61*02a19356SDavid Howells int r; 62*02a19356SDavid Howells 63*02a19356SDavid Howells __refcount_inc(&txb->ref, &r); 64*02a19356SDavid Howells trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r + 1, what); 65*02a19356SDavid Howells } 66*02a19356SDavid Howells 67*02a19356SDavid Howells void rxrpc_see_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 68*02a19356SDavid Howells { 69*02a19356SDavid Howells int r = refcount_read(&txb->ref); 70*02a19356SDavid Howells 71*02a19356SDavid Howells trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r, what); 72*02a19356SDavid Howells } 73*02a19356SDavid Howells 74*02a19356SDavid Howells static void rxrpc_free_txbuf(struct rcu_head *rcu) 75*02a19356SDavid Howells { 76*02a19356SDavid Howells struct rxrpc_txbuf *txb = container_of(rcu, struct rxrpc_txbuf, rcu); 77*02a19356SDavid Howells 78*02a19356SDavid Howells trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 0, 79*02a19356SDavid Howells rxrpc_txbuf_free); 80*02a19356SDavid Howells kfree(txb); 81*02a19356SDavid Howells atomic_dec(&rxrpc_nr_txbuf); 82*02a19356SDavid Howells } 83*02a19356SDavid Howells 84*02a19356SDavid Howells void rxrpc_put_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 85*02a19356SDavid Howells { 86*02a19356SDavid Howells unsigned int debug_id, call_debug_id; 87*02a19356SDavid Howells rxrpc_seq_t seq; 88*02a19356SDavid Howells bool dead; 89*02a19356SDavid Howells int r; 90*02a19356SDavid Howells 91*02a19356SDavid Howells if (txb) { 92*02a19356SDavid Howells debug_id = txb->debug_id; 93*02a19356SDavid Howells call_debug_id = txb->call_debug_id; 94*02a19356SDavid Howells seq = txb->seq; 95*02a19356SDavid Howells dead = __refcount_dec_and_test(&txb->ref, &r); 96*02a19356SDavid Howells trace_rxrpc_txbuf(debug_id, call_debug_id, seq, r - 1, what); 97*02a19356SDavid Howells if (dead) 98*02a19356SDavid Howells call_rcu(&txb->rcu, rxrpc_free_txbuf); 99*02a19356SDavid Howells } 100*02a19356SDavid Howells } 101