xref: /linux/net/rxrpc/txbuf.c (revision 1b98f357dadd6ea613a435fbaef1a5dd7b35fd21)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* RxRPC Tx data buffering.
3  *
4  * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/slab.h>
11 #include "ar-internal.h"
12 
13 static atomic_t rxrpc_txbuf_debug_ids;
14 atomic_t rxrpc_nr_txbuf;
15 
16 /*
17  * Allocate and partially initialise a data transmission buffer.
18  */
19 struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size,
20 					   size_t data_align, gfp_t gfp)
21 {
22 	struct rxrpc_txbuf *txb;
23 	size_t total, doff, jsize = sizeof(struct rxrpc_jumbo_header);
24 	void *buf;
25 
26 	txb = kzalloc(sizeof(*txb), gfp);
27 	if (!txb)
28 		return NULL;
29 
30 	/* We put a jumbo header in the buffer, but not a full wire header to
31 	 * avoid delayed-corruption problems with zerocopy.
32 	 */
33 	doff = round_up(jsize, data_align);
34 	total = doff + data_size;
35 
36 	data_align = umax(data_align, L1_CACHE_BYTES);
37 	mutex_lock(&call->conn->tx_data_alloc_lock);
38 	buf = page_frag_alloc_align(&call->conn->tx_data_alloc, total, gfp,
39 				    data_align);
40 	mutex_unlock(&call->conn->tx_data_alloc_lock);
41 	if (!buf) {
42 		kfree(txb);
43 		return NULL;
44 	}
45 
46 	refcount_set(&txb->ref, 1);
47 	txb->call_debug_id	= call->debug_id;
48 	txb->debug_id		= atomic_inc_return(&rxrpc_txbuf_debug_ids);
49 	txb->alloc_size		= data_size;
50 	txb->space		= data_size;
51 	txb->offset		= 0;
52 	txb->flags		= call->conn->out_clientflag;
53 	txb->seq		= call->send_top + 1;
54 	txb->data		= buf + doff;
55 
56 	trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 1,
57 			  rxrpc_txbuf_alloc_data);
58 
59 	atomic_inc(&rxrpc_nr_txbuf);
60 	return txb;
61 }
62 
63 void rxrpc_see_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what)
64 {
65 	int r = refcount_read(&txb->ref);
66 
67 	trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r, what);
68 }
69 
70 static void rxrpc_free_txbuf(struct rxrpc_txbuf *txb)
71 {
72 	trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 0,
73 			  rxrpc_txbuf_free);
74 	if (txb->data)
75 		page_frag_free(txb->data);
76 	kfree(txb);
77 	atomic_dec(&rxrpc_nr_txbuf);
78 }
79 
80 void rxrpc_put_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what)
81 {
82 	unsigned int debug_id, call_debug_id;
83 	rxrpc_seq_t seq;
84 	bool dead;
85 	int r;
86 
87 	if (txb) {
88 		debug_id = txb->debug_id;
89 		call_debug_id = txb->call_debug_id;
90 		seq = txb->seq;
91 		dead = __refcount_dec_and_test(&txb->ref, &r);
92 		trace_rxrpc_txbuf(debug_id, call_debug_id, seq, r - 1, what);
93 		if (dead)
94 			rxrpc_free_txbuf(txb);
95 	}
96 }
97