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 */
rxrpc_alloc_data_txbuf(struct rxrpc_call * call,size_t data_size,size_t data_align,gfp_t gfp)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
rxrpc_see_txbuf(struct rxrpc_txbuf * txb,enum rxrpc_txbuf_trace what)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
rxrpc_free_txbuf(struct rxrpc_txbuf * txb)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
rxrpc_put_txbuf(struct rxrpc_txbuf * txb,enum rxrpc_txbuf_trace what)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