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.