xref: /openbmc/linux/net/rxrpc/txbuf.c (revision 02a19356)
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