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_wire_header *whdr; 23 struct rxrpc_txbuf *txb; 24 size_t total, hoff; 25 void *buf; 26 27 txb = kzalloc(sizeof(*txb), gfp); 28 if (!txb) 29 return NULL; 30 31 hoff = round_up(sizeof(*whdr), data_align) - sizeof(*whdr); 32 total = hoff + sizeof(*whdr) + data_size; 33 34 data_align = umax(data_align, L1_CACHE_BYTES); 35 mutex_lock(&call->conn->tx_data_alloc_lock); 36 buf = page_frag_alloc_align(&call->conn->tx_data_alloc, total, gfp, 37 data_align); 38 mutex_unlock(&call->conn->tx_data_alloc_lock); 39 if (!buf) { 40 kfree(txb); 41 return NULL; 42 } 43 44 whdr = buf + hoff; 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 = sizeof(*whdr); 52 txb->flags = call->conn->out_clientflag; 53 txb->seq = call->send_top + 1; 54 txb->nr_kvec = 1; 55 txb->kvec[0].iov_base = whdr; 56 txb->kvec[0].iov_len = sizeof(*whdr); 57 58 whdr->epoch = htonl(call->conn->proto.epoch); 59 whdr->cid = htonl(call->cid); 60 whdr->callNumber = htonl(call->call_id); 61 whdr->seq = htonl(txb->seq); 62 whdr->type = RXRPC_PACKET_TYPE_DATA; 63 whdr->flags = 0; 64 whdr->userStatus = 0; 65 whdr->securityIndex = call->security_ix; 66 whdr->_rsvd = 0; 67 whdr->serviceId = htons(call->dest_srx.srx_service); 68 69 trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 1, 70 rxrpc_txbuf_alloc_data); 71 72 atomic_inc(&rxrpc_nr_txbuf); 73 return txb; 74 } 75 76 void rxrpc_get_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 77 { 78 int r; 79 80 __refcount_inc(&txb->ref, &r); 81 trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r + 1, what); 82 } 83 84 void rxrpc_see_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 85 { 86 int r = refcount_read(&txb->ref); 87 88 trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, r, what); 89 } 90 91 static void rxrpc_free_txbuf(struct rxrpc_txbuf *txb) 92 { 93 int i; 94 95 trace_rxrpc_txbuf(txb->debug_id, txb->call_debug_id, txb->seq, 0, 96 rxrpc_txbuf_free); 97 for (i = 0; i < txb->nr_kvec; i++) 98 if (txb->kvec[i].iov_base && 99 !is_zero_pfn(page_to_pfn(virt_to_page(txb->kvec[i].iov_base)))) 100 page_frag_free(txb->kvec[i].iov_base); 101 kfree(txb); 102 atomic_dec(&rxrpc_nr_txbuf); 103 } 104 105 void rxrpc_put_txbuf(struct rxrpc_txbuf *txb, enum rxrpc_txbuf_trace what) 106 { 107 unsigned int debug_id, call_debug_id; 108 rxrpc_seq_t seq; 109 bool dead; 110 int r; 111 112 if (txb) { 113 debug_id = txb->debug_id; 114 call_debug_id = txb->call_debug_id; 115 seq = txb->seq; 116 dead = __refcount_dec_and_test(&txb->ref, &r); 117 trace_rxrpc_txbuf(debug_id, call_debug_id, seq, r - 1, what); 118 if (dead) 119 rxrpc_free_txbuf(txb); 120 } 121 } 122