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