Thread (22 messages) 22 messages, 2 authors, 1d ago

Re: [PATCH net-next v5 05/15] libie: add bookkeeping support for control queue messages

From: Larysa Zaremba <hidden>
Date: 2026-07-20 16:08:03
Also in: linux-doc

Sashiko says:
quoted
+	wait_for_completion_timeout(&xn->cmd_completion_event,
+				    msecs_to_jiffies(params->timeout_ms));
+
+	spin_lock(&xn->xn_lock);
+	switch (xn->state) {
+	case LIBIE_CTLQ_XN_WAITING:
+		ret = -ETIMEDOUT;
+		break;
+	case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
+		params->recv_mem = xn->recv_mem;
+		break;
+	default:
+		ret = -EBADMSG;
+		break;
+	}
+
+	/* Free the receive buffer in case of failure. On timeout, receive
+	 * buffer is not allocated.
+	 */
+	if (ret && ret != -ETIMEDOUT)
+		libie_ctlq_release_rx_buf(&xn->recv_mem);
Can this cause a double free on a stale receive buffer if the transaction was
aborted? When a transaction is returned to the free pool, xn->recv_mem is not
cleared. If it is reallocated and enters the WAITING state, it still contains
the recv_mem pointer from its last successful use. If libie_ctlq_xn_shutdown()
aborts this transaction, its state changes to SHUTDOWN. This switch falls through
to the default case setting ret = -EBADMSG, and this cleanup logic will call
libie_ctlq_release_rx_buf() on the stale recv_mem pointer.
LIBIE_CTLQ_XN_WAITING can only occur in the previous critical sections,
since it's only applicable to idle transactions.

[...]
quoted
+	wait_for_completion_timeout(&xn->cmd_completion_event,
+				    msecs_to_jiffies(params->timeout_ms));
params->timeout_ms is declared u64 in struct libie_ctlq_xn_send_params
(and stored to xn->timeout_ms which is also u64), but msecs_to_jiffies()
takes const unsigned int. On 64-bit builds, values above UINT_MAX get
silently truncated to 32 bits before conversion, and the MAX_JIFFY_OFFSET
clamp inside _msecs_to_jiffies() only fires against a value that already
fits in int, so it can't rescue the truncation.
The async path uses ktime_ms_delta against a u64 correctly, so the sync
and async paths would disagree for the same input.
Should timeout_ms be u32 in both structures (matching msecs_to_jiffies()),
or should the value be clamped before conversion here?
quoted
+		if (!libie_cp_can_send_onstack(msg->data_len)) {
+			libie_cp_unmap_dma_mem(dev, &msg->send_mem);
+			params->rel_tx_buf(msg->send_mem.va);
[Medium, Medium]
Two questions about locking context here.
First, params->rel_tx_buf() is being called while ctlq->lock (a plain
spin_lock) is held. In libie_ctlq_xn_send() the same callback is invoked
at the free_buf label with no locks held, so the two libie call sites
impose different atomic-context constraints on the same driver-supplied
callback. Should rel_tx_buf either be moved outside the critical section
or explicitly documented as required to be non-sleeping?
I see no reason to do this currently
Second, xnm->free_xns_bm_lock, xn->xn_lock, and ctlq->lock are all
acquired with plain spin_lock() throughout the new code. If a future
consumer drives libie_ctlq_xn_recv() from softirq (NAPI-like, which the
budget parameter and page_pool usage suggest) while libie_ctlq_xn_send()
runs from process context on the same CPU, wouldn't the softirq deadlock
against the process-context lock holder? Would spin_lock_bh() variants,
or an explicit documented callable-context contract, be preferable?
No softirqs

[...]
quoted
+/**
+ * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
+ * @xnm: pointer to the transaction manager
+ * @ctx: controlq context structure
+ *
+ * All Rx processing must be stopped beforehand.
+ */
+void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
+			  struct libie_ctlq_ctx *ctx)
+{
+	libie_ctlq_xn_shutdown(xnm);
+	libie_ctlq_xn_deinit_dma(&ctx->mmio_info.pdev->dev, xnm,
+				 LIBIE_CTLQ_MAX_XN_ENTRIES);
+	kfree(xnm);
+	libie_ctlq_deinit(ctx);
+}
+EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
[High, Medium]
Two concerns about this deinit path.
First, do large in-flight sends leak DMA mappings and TX buffers?
libie_ctlq_xn_shutdown() only manages xn slot state and does not touch
the TX descriptor ring. libie_ctlq_xn_deinit_dma() only walks
xn->dma_mem (the copybreak buffers), not ctlq_msg->send_mem for larger
sends. libie_ctlq_deinit() eventually reaches libie_ctlq_free_tx_msgs()
which does only kfree(ctlq->tx_msg[i]).
Nothing on this path calls libie_cp_unmap_dma_mem() on msg->send_mem or
invokes rel_tx_buf() for a msg->send_mem.va that a caller supplied via
kmalloc. Wouldn't every posted-but-not-yet-completion-cleaned large send
leak its DMA mapping and buffer? The kerneldoc only requires "All Rx
processing must be stopped beforehand" and doesn't warn that
libie_ctlq_xn_send_clean(force=true) must be called first.
Could be phrased better, but idpf and ixd use the API correctly, so no 
real consequences.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help