net: mana: reconfigure by replacing the queue set
Subsystems (6)
v6 cover net: mana: reconfigure by replacing the queue set
I am carrying Long Li's queue-set reconfiguration series forward for this revision. Long remains the author of twelve patches, and Dipayaan Roy remains the author of the detach change. Their authorship and signoffs are retained; I have added my signoff for this revision.
Replace detach/attach reconfiguration with pre-allocation and queue-set replacement. Allocation failure leaves the running configuration intact. Publication failure attempts rollback; a failed rollback closes the port and holds carrier down until a successful reopen.
EQs and statistics belong to the port. Valid user-configured RSS tables survive queue rebuilds. Channel-count changes reuse surviving queues:
reductions retire the tail and increases allocate only the added queues. Ring, MTU, private-flag and XDP layout changes still perform full rebuilds.
This series does not depend on the pending HWC concurrency/dynamic-depth v6 series linked below. Their CQ-publication changes overlap in gdma_main.c and hw_channel.c; whichever series lands second will need a rebase preserving both table-publication and per-CQ lifetime guarantees. Related HWC series:
https://lore.kernel.org/all/[email protected]/
Changes since v5:
- Rebase the independent queue-set series onto net-next base
47a1446725732cd3996edf607e8739334bbf4d78.
- Drain ALL old TX queues after closing the TX/XDP gate and waiting for readers, but before publishing pointers, counts or RSS. A shared 120-second drain deadline rejects a replacement by resuming the old configuration without reprogramming RSS or resetting the function. Retirement does not use FLR. Ordinary mana_dealloc_queues() remains byte-identical to this base: existing reset policy and independent failed-FLR hardening are deliberately not changed.
- Complete the shared EQ/CQ lifetime prerequisite in patch 2. Initialize EQ state before IRQ publication. After stopping a retiring CQ's NAPI and work and tearing down its WQ object, flush its actual parent EQ while the CQ callback is still published. Clear its table entry and wait for RCU IRQ readers before freeing the CQ and callback owner. Pair IRQ lookups with release publication at all CQ publishers; Ethernet publication follows NAPI/DIM initialization. Matching HWC and RDMA publication stores do not change their recovery policies.
- Move port-lifetime statistics preparation ahead of the first live swap, now patch 3. Introduce RX retirement, writer handoff and folding atomically with the first swap in patch 4, rather than relying on a later patch to make intermediate statistics readers safe.
- Keep publication barriers consistent with open/attach. Latch forced carrier shutdown regardless of the previous carrier state and clear it only after successful reopen. Retain the rollback reader grace period after restoring old pointers, before callers discard scratch state.
- Join TX queue selection to the publication gate in patch 4. Acquire port_is_up before count/RSS reads and snapshot real_num_tx_queues. Retiring tail RQs can outlive a TX-count reduction; when a recorded RX index no longer fits the live TX count, use the current RSS mapping instead of returning that stale index.
- Clear DRV_XOFF on inactive allocated TX queues in patch 4's cold-path restart helper, using netif_tx_start_queue() while preserving the availability checks and wake behavior for active queues. Publication stops all allocated queues, and the netdev watchdog scans allocated num_tx_queues, not just real_num_tx_queues. Leaving the inactive tail stopped after a channel shrink caused a watchdog timeout and recovery on the previous release candidate.
- Keep old RX statistics retired until rollback steering restoration succeeds. Restart DIM only for RXQs actually returning from retirement, with NAPI disabled, work cancelled and DIM reinitialized; carried RXQs and their counters are not reset.
- Reserve live MTU/XDP replacement with channel_changing under the existing vport_mutex through queue, fail-close and scratch cleanup. This excludes concurrent RDMA RAW-QP vport admission without changing early validation, no-op or down-port paths.
- Correct the full-page RX shortcut description to include all existing early-return conditions.
Resource and control-path costs:
Full rebuilds temporarily retain both sets of SQ/RQ/CQ objects, RX buffers and page pools. The port-owned EQ pool is shared, not doubled. Device resource limits can reject this temporary peak; no fixed hardware queue threshold is assumed. Allocation failure preserves the live configuration. The pre-publication TX drain can also reject a replacement without changing the live pointer/count/RSS configuration.
CQ retirement adds parent-EQ marker operations and RCU reader waits on the control path; these are not free and no latency improvement is claimed. The IRQ lookup uses an acquire load, not a new per-packet lock. This series does not introduce a general recovery policy for failed hardware commands.
Patch layout:
1: Queue-set helpers, preserving ordinary deallocation policy. 2: Shared EQ pool and EQ/CQ publication/retirement prerequisite. 3: Port-lifetime statistics preparation. 4: First live swap, nonreset drain, RX handoff and safe TX restart. 5-8: Ring, private-flag, MTU and XDP reconfiguration. 9: Remove the unreachable detach early return.
10-11: Release unused EQs and preserve user RSS tables. 12-13: Reuse queues across channel-count reductions and increases.
Overlap with separately submitted net fixes:
The XDP pre-allocation pointer fix is subsumed by patch 8's queue-set path, which leaves the live program unchanged during allocation:
https://lore.kernel.org/all/[email protected]/
The user-RSS-table fix overlaps patch 11. Keep the three-argument mana_rss_table_keep() and its queue-set callers in the overlapping blocks; the RTNL RSS requirement is shared with the standalone net submission:
https://lore.kernel.org/all/[email protected]/
Neither submission is resent as a standalone patch here. These merge notes do not prescribe changes to unrelated net-tree code.
History:
v5: https://lore.kernel.org/all/[email protected]/
v4: https://lore.kernel.org/all/[email protected]/
v3: https://lore.kernel.org/all/[email protected]/
v2 repost:
https://lore.kernel.org/all/[email protected]/ v2 earlier posting: https://lore.kernel.org/all/[email protected]/ Full-page RX predecessor (v12, not a queue-set v1): https://lore.kernel.org/all/[email protected]/
The link labelled "v1" in the old queue-set covers actually points to the four-patch full-page RX v12 predecessor, not an earlier 13-patch queue-set posting.
Testing:
Submission tip d7c25bddfea3 differs from the tested production history only by removing attribution/session trailers. All thirteen intermediate source trees are identical; build/runtime identities below are unchanged.
Production 6243b02cc714, kernel 7.3.0-rc4-mana-qset-v6-g6243b02cc714, passed 39 native functional cases per DUT on VM5 and VM6: >=35-second reduced-channel watchdog dwells, queue ownership, real IPv4 DF jumbo traffic at MTU 2000/payload 1972, and native XDP PASS/DROP/TX/REDIRECT.
The separate KASAN/DMA memory/fault fixture, 7.3.0-rc4-mana-qset-memdiag-rethook-g9d9757ecf25c, completed 64 PASS/2 UNSUPPORTED/0 FAIL/0 NOT_RUN per DUT, including all 25 fault cases with each token consumed exactly once. VM5 also completed twelve
Quoted 1 line
=180-second warning-reproduction trials with attributed security probes
active and untouched. No unexpected warning, KASAN/DMA-debug error or peer-health failure was observed. Fault4 recovered locally; its independent fallback was armed, verified and canceled, not executed.
That fixture's four-line FP64 rethook metadata correction and fault hooks are test-only, not in these thirteen patches or a production dependency. The entry window is unchanged; no global unwinding guarantee is claimed. Full-locking remains baseline-blocked: unmodified 47a reproduced the platform checker failure, and this fixture has no LOCKDEP/PROVE_RAW/ PROVE_RCU coverage. DIM enable returned EOPNOTSUPP. Native verbs is UNSUPPORTED in the memory matrix because no approved native baseline probe/result was supplied; RDMA sanity/link health is covered, not native verbs transfer. PF/non-host-mode and multiport hardware remain untested.
A final forward-UDP receiver comparison completed five release6243 and five baseline47a samples with complete raw records, matching identities, nested windows and valid client/server completion; no rows were rejected. Adjusted TGID CPU averaged 4056.4 versus 4188.4 USER_HZ ticks. Per iperf summary application Gbit it was 901.422346 versus 930.754115 (~3.15% lower); per native full-window path Gbit, 518.165386 versus 543.335320 (~4.63% lower). The process interval includes omit time; iperf's application summary does not. These are distinct denominators, not interval-matched application efficiency. Throughput was 99.9980098 versus 99.9980650 Mbit/s, with loss 0.000689492% versus 0.001422219% (release versus baseline).
This measures guest-scheduler-attributed process runtime, not whole-guest, driver or physical CPU efficiency. Aggregate /proc/stat is observational and need not conserve against adjusted process time. A separate earlier five-plus-five sender crossover did not reproduce the initial ~9% signal; observer/context and phase confounds remain. These bounded results are not a no-effect or blanket regression-free guarantee.
Current P4-P13 passed forced GCC W=1 builds, 150/150 target translation units; unchanged P1-P3 retain their original complete proof. Smatch is not credited: its frontend fails a valid type assertion on both baseline and feature. Historical supported Sparse coverage is not relabeled as a new current-tip run. Full-mail lint was rerun after removing the Copilot attribution/session trailers at the submitter's request. Hardware-command failure/recovery policies remain scoped as described above; these tests do not establish recovery from every device failure.
Full evidence, fixture identities and historical limitations are in the package's RUNTIME-HANDOFF.txt and audit/final-evidence.json. Public v5 review freshness was checked on 2026-10-02: all 21 findings and 28 thread messages were unchanged, with no new human replies. No actual Sashiko approval is claimed.
Dipayaan Roy (1):
net: mana: do not bail out of mana_detach on dealloc failure
Long Li (12):
net: mana: add queue-set allocation and teardown helpers
net: mana: share the EQ pool across a queue-set swap
net: mana: keep per-queue statistics in the port context
net: mana: swap queue sets in mana_set_channels
net: mana: swap queue sets in mana_set_ringparam
net: mana: swap queue sets in mana_set_priv_flags
net: mana: swap queue sets in mana_change_mtu
net: mana: swap queue sets in mana_xdp_set
net: mana: release EQs left idle by a channel-count reduction
net: mana: keep a user-configured RSS table across a queue rebuild
net: mana: keep the surviving queues when the channel count is reduced
net: mana: keep the existing queues when the channel count is raised
drivers/infiniband/hw/mana/cq.c | 3 +- .../net/ethernet/microsoft/mana/gdma_main.c | 22 +- .../net/ethernet/microsoft/mana/hw_channel.c | 3 +- .../net/ethernet/microsoft/mana/mana_bpf.c | 108 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 1328 +++++++++++++++-- .../ethernet/microsoft/mana/mana_ethtool.c | 314 ++-- include/net/mana/gdma.h | 8 +- include/net/mana/mana.h | 97 +- 8 files changed, 1610 insertions(+), 273 deletions(-)
base-commit: 47a1446725732cd3996edf607e8739334bbf4d78
PATCH v6 1/13 net: mana: add queue-set allocation and teardown helpers
From: Long Li <[email protected]>
Add queue-set allocation and teardown helpers using a scratch port context without releasing the vport. These prepare reconfiguration to retain its running queues if replacement allocation fails.
Leave ordinary mana_dealloc_queues() byte-identical to the pinned base. Do not introduce reset generations, sibling-port rebuilds, or an incomplete independent failed-FLR TX-buffer policy change.
Queue-set retirement itself performs no function reset. Its caller must drain old published TX queues before publishing a replacement; unpublished sets have never admitted TX. The first live-swap commit adds that nonresetting pre-publication wait. These helpers have no live replacement callers yet.
--- .../net/ethernet/microsoft/mana/mana_bpf.c | 24 +++ drivers/net/ethernet/microsoft/mana/mana_en.c | 184 +++++++++++++++++- include/net/mana/mana.h | 31 +++ 3 files changed, 236 insertions(+), 3 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +24 -0
@@ -263,3 +263,27 @@ int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf)return -EOPNOTSUPP ; } } + +struct bpf_prog *mana_chn_xdp_peek (struct mana_port_context *apc) +{ +ASSERT_RTNL (); + +if (!apc->rxqs || !apc->rxqs[0 ]) +return NULL ; + +return rtnl_dereference (apc->rxqs[0 ]->bpf_prog); +} + +/* Keep the per-queue program pointers until RX polling stops. */ +void mana_chn_xdp_release (struct bpf_prog *prog,unsigned int num_queues) +{ +unsigned int i; + +ASSERT_RTNL (); + +if (!prog) +return ; + +for (i =0 ; i < num_queues; i++) +bpf_prog_put (prog); +}
drivers/net/ethernet/microsoft/mana/mana_en.c +181 -3
211 lines not on this page · raw message
include/net/mana/mana.h +31 -0
@@ -143,6 +143,9 @@ struct mana_txq {bool napi_initialized; +/* Suppress completion wakeups on the replacement's netdev queue. */ +bool retiring; +struct mana_stats_tx stats; };
@@ -537,6 +540,7 @@ struct mana_context {u8 bm_hostmode;struct mana_ethtool_hc_stats hc_stats; +struct workqueue_struct *per_port_queue_reset_wq;/* Workqueue for querying hardware stats */ struct delayed_work gf_stats_work;
@@ -661,6 +665,23 @@ struct mana_port_context {u32 steer_cqe_coalescing; }; +struct mana_qset { +struct mana_eq *eqs; +struct mana_tx_qp **tx_qp; +struct mana_rxq **rxqs; + +u32 *indir_table; +u32 indir_table_sz; +mana_handle_t *rxobj_table; +mana_handle_t default_rxobj; + +unsigned int num_queues; +unsigned int rx_queue_size; +unsigned int tx_queue_size; +u32 priv_flags; + +}; +netdev_tx_t mana_start_xmit (struct sk_buff *skb,struct net_device *ndev);int mana_config_rss (struct mana_port_context *ac,enum TRI_STATE rx,bool update_hash,bool update_tab);
@@ -670,6 +691,14 @@ int mana_alloc_queues(struct net_device *ndev);int mana_attach (struct net_device *ndev);int mana_detach (struct net_device *ndev,bool from_close); +struct mana_port_context * +mana_qset_scratch_alloc (struct mana_port_context *apc); +void mana_qset_scratch_free (struct mana_port_context *scratch); +int mana_alloc_qset (struct mana_port_context *scratch,unsigned int num_queues, +unsigned int rx_queue_size,unsigned int tx_queue_size, +u32 priv_flags,struct mana_qset *out); +void mana_free_qset (struct mana_port_context *scratch,struct mana_qset *qset); +void mana_dim_change (struct mana_cq *cq,bool enable);int mana_probe (struct gdma_dev *gd,bool resuming);
@@ -685,6 +714,8 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, struct xdp_buff *xdp, void *buf_va, uint pkt_len);struct bpf_prog *mana_xdp_get (struct mana_port_context *apc);void mana_chn_setxdp (struct mana_port_context *apc,struct bpf_prog *prog); +struct bpf_prog *mana_chn_xdp_peek (struct mana_port_context *apc); +void mana_chn_xdp_release (struct bpf_prog *prog,unsigned int num_queues);int mana_bpf (struct net_device *ndev,struct netdev_bpf *bpf);int mana_query_gf_stats (struct mana_context *ac);int mana_query_link_cfg (struct mana_port_context *apc);
[email protected]
AI reviewRe: [PATCH net-next v6 01/13] net: mana: add queue-set allocation and teardown helpers
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines
From: Long Li <[email protected]>
Add queue-set allocation and teardown helpers using a scratch port context without releasing the vport. These prepare reconfiguration to retain its running queues if replacement allocation fails.
Leave ordinary
mana_dealloc_queues()byte-identical to the pinned base. Do not introduce reset generations, sibling-port rebuilds, or an incomplete independent failed-FLR TX-buffer policy change.
Quoted 8 lines
Queue-set retirement itself performs no function reset. Its caller must drain old published TX queues before publishing a replacement; unpublished sets have never admitted TX. The first live-swap commit adds that nonresetting pre-publication wait. These helpers have no live replacement callers yet.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
PATCH v6 2/13 net: mana: share the EQ pool across a queue-set swap
In reply to Wei HuFrom: Long Li <[email protected]>
Make the EQ pool port-owned so overlapping queue sets share EQs instead of requiring old + new vector allocations. Allocate max_queues slots and track populated entries with num_eqs.
Grow the pool before creating replacement CQs. Additional EQs survive allocation failure in this patch and are released at port teardown.
Initialize EQ callbacks, context, owner phase and throttle before IRQ publication, so a live shared IRQ cannot observe an uninitialized EQ. Preserve the existing hardware-create and unwind ordering.
A shared EQ also outlives individual CQs. After stopping a CQ's NAPI and work and tearing down its WQ object, flush its actual parent EQ while the CQ callback remains published. Remove only that CQ's table entry and wait for RCU IRQ readers before freeing the CQ and its callback owner.
Pair the IRQ lookup with release publication at all CQ publishers. For Ethernet, publish only after NAPI and DIM initialization. The HWC and RDMA sites need the matching stores, not changes to their teardown or recovery policies.
The EQ markers and reader waits are control-path costs; the IRQ lookup uses an acquire load without new validity checks. Report failed markers using the existing error-logging convention. This does not add a reset or reclamation policy for arbitrary failed hardware commands.
--- drivers/infiniband/hw/mana/cq.c | 3 +- .../net/ethernet/microsoft/mana/gdma_main.c | 22 ++-- .../net/ethernet/microsoft/mana/hw_channel.c | 3 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 115 ++++++++++++++---- include/net/mana/mana.h | 6 +- 5 files changed, 113 insertions(+), 36 deletions(-)
drivers/infiniband/hw/mana/cq.c +2 -1
@@ -155,7 +155,8 @@ int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq) gdma_cq->type =GDMA_CQ ; gdma_cq->cq.callback = mana_ib_cq_handler; gdma_cq->id = cq->queue.id; - gc->cq_table[cq->queue.id] = gdma_cq; +/* Pairs with the acquire load in mana_gd_process_eqe(). */ +smp_store_release (&gc->cq_table[cq->queue.id], gdma_cq);return 0 ; }
drivers/net/ethernet/microsoft/mana/gdma_main.c +11 -11
@@ -925,7 +925,8 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)if (WARN_ON_ONCE (cq_id >= gc->max_num_cqs))break ; - cq = gc->cq_table[cq_id]; +/* Match release publication of the CQ and its callback state. */ + cq =smp_load_acquire (&gc->cq_table[cq_id]);if (WARN_ON_ONCE (!cq || cq->type !=GDMA_CQ || cq->id != cq_id))break ;
@@ -1187,17 +1188,17 @@ static int mana_gd_create_eq(struct gdma_dev *gd,return -EINVAL ; } + queue->eq.callback = spec->eq.callback; + queue->eq.context = spec->eq.context; + queue->head |=INITIALIZED_OWNER_BIT (log2_num_entries); + queue->eq.log2_throttle_limit = spec->eq.log2_throttle_limit ?:1 ; + err =mana_gd_register_irq (queue, spec);if (err) {dev_err (dev,"Failed to register irq: %d\n" , err);return err; } - queue->eq.callback = spec->eq.callback; - queue->eq.context = spec->eq.context; - queue->head |=INITIALIZED_OWNER_BIT (log2_num_entries); - queue->eq.log2_throttle_limit = spec->eq.log2_throttle_limit ?:1 ; -if (create_hwq) { err =mana_gd_create_hw_eq (gc, queue);if (err)
@@ -1232,13 +1233,12 @@ static void mana_gd_destroy_cq(struct gdma_context *gc, {u32 id = queue->id; -if (id >= gc->max_num_cqs) +if (id >= gc->max_num_cqs || !gc->cq_table)return ; -if (!gc->cq_table[id]) -return ; - - gc->cq_table[id] =NULL ; +/* Leave a reused ID alone, but still drain readers of this CQ. */ +cmpxchg (&gc->cq_table[id], queue,NULL ); +synchronize_rcu (); } int mana_gd_create_hwc_queue(struct gdma_dev *gd,
drivers/net/ethernet/microsoft/mana/hw_channel.c +2 -1
@@ -702,7 +702,8 @@ static int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth,if (!gc->cq_table)return -ENOMEM ; - gc->cq_table[cq->id] = cq; +/* Pairs with the acquire load in mana_gd_process_eqe(). */ +smp_store_release (&gc->cq_table[cq->id], cq);return 0 ; }
drivers/net/ethernet/microsoft/mana/mana_en.c +94 -21
244 lines not on this page · raw message
include/net/mana/mana.h +4 -2
@@ -563,7 +563,9 @@ struct mana_port_context {u8 mac_addr[ETH_ALEN ]; +/* Port-owned EQ pool: max_queues slots, num_eqs populated. */ struct mana_eq *eqs; +unsigned int num_eqs;struct dentry *mana_eqs_debugfs;enum TRI_STATE rss_state;
@@ -666,7 +668,6 @@ struct mana_port_context { };struct mana_qset { -struct mana_eq *eqs;struct mana_tx_qp **tx_qp;struct mana_rxq **rxqs;
@@ -694,7 +695,8 @@ int mana_detach(struct net_device *ndev, bool from_close);struct mana_port_context *mana_qset_scratch_alloc (struct mana_port_context *apc);void mana_qset_scratch_free (struct mana_port_context *scratch); -int mana_alloc_qset (struct mana_port_context *scratch,unsigned int num_queues, +int mana_alloc_qset (struct mana_port_context *apc, +struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size,u32 priv_flags,struct mana_qset *out);void mana_free_qset (struct mana_port_context *scratch,struct mana_qset *qset);
[email protected]
AI reviewRe: [PATCH net-next v6 02/13] net: mana: share the EQ pool across a queue-set swap
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] net: mana: leak of DMA region handle in mana_gd_create_mana_eq() error path --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] net: mana: leak of DMA region handle in mana_gd_create_mana_eq() error path --
commit 1d0366c5b44b66d602e9a488b5674896e64e1285
Author: Long Li <[email protected]>
net: mana: share the EQ pool across a queue-set swap
This commit makes the EQ pool port-owned so that overlapping queue sets can share EQs instead of requiring allocations of new vectors. It allocates max_queues slots and tracks populated entries, growing the pool before creating replacement CQs.
Quoted 3 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +0
-0
[ ... ]
Quoted 3 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +3
-0+/* Grow the shared EQ pool without replacing live entries. */ +static int mana_grow_eqs (struct mana_port_context *apc,unsigned int need) +{
[ ... ]
drivers/net/ethernet/microsoft/mana/mana_en.c int mana_create_eq(struct mana_port_context *apc) · line 1858
Quoted 11 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +11
-0+for (i = apc->num_eqs; i < need; i++) { + msi = (i +1 ) % gc->num_msix_usable; + + gic =mana_gd_get_gic (gc, !gc->msi_sharing, &msi); +if (IS_ERR (gic)) { + err =PTR_ERR (gic); + goto out; + } + spec.eq.msix_index = msi; + + err =mana_gd_create_mana_eq (gd, &spec, &apc->eqs[i].eq);
[Severity: Medium]
Does this code leak the DMA region handle when queue creation fails?
The new mana_grow_eqs() function iteratively loops and relies on mana_gd_create_mana_eq(), but looking at the error path inside mana_gd_create_mana_eq():
mana_gd_create_mana_eq() {
...
err = mana_gd_create_dma_region(gd, gmi);
if (err)
goto out;
...
err = mana_gd_create_eq(gd, spec, true, queue);
if (err)
goto out;
...
out:
dev_err(gc->dev, "Failed to create queue type %d of size: %u, err: %d\n",
spec->type, spec->queue_size, err);
mana_gd_free_memory(gmi);
free_q:
kfree(queue);
return err;
}If mana_gd_create_eq() fails, execution jumps to the out label, which calls mana_gd_free_memory() and kfree() but entirely omits calling mana_gd_destroy_dma_region() for the successfully allocated DMA region. Since mana_gd_destroy_eq() does not destroy the DMA region either, the handle mapping remains persistently leaked.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
PATCH v6 3/13 net: mana: keep per-queue statistics in the port context
In reply to Wei HuFrom: Long Li <[email protected]>
Prepare port-lifetime RX/TX statistics before introducing live queue replacement. Allocate max_queues slots before netdev registration, unwind probe failures, and release them only after unregistering the netdev. Queue writers use pointers into these arrays.
Make ndo_get_stats64 and ethtool statistics independent of replaceable queue objects. Preserve counters while down, gating only the PHY query. Reserve zeroed retired-RX slots for the next patch; no second live queue generation or RX retirement handoff is enabled here.
--- .../net/ethernet/microsoft/mana/mana_bpf.c | 4 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 107 ++++++++++++++---- .../ethernet/microsoft/mana/mana_ethtool.c | 48 ++++++-- include/net/mana/mana.h | 15 ++- 4 files changed, 139 insertions(+), 35 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +2 -2
@@ -68,7 +68,7 @@ int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames, count++; } - tx_stats = &apc->tx_qp[q_idx]->txq.stats; + tx_stats = apc->tx_qp[q_idx]->txq.stats;u64_stats_update_begin (&tx_stats->syncp); tx_stats->xdp_xmit += count;
@@ -95,7 +95,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, act =bpf_prog_run_xdp (prog, xdp); - rx_stats = &rxq->stats; + rx_stats = rxq->stats;switch (act) {case XDP_PASS :
drivers/net/ethernet/microsoft/mana/mana_en.c +87 -20
216 lines not on this page · raw message
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +39 -9
79 lines not on this page · raw message
include/net/mana/mana.h +11 -4
@@ -102,7 +102,7 @@ struct mana_stats_rx {u64 pkt_len0_err;u64 coalesced_cqe[MANA_CQE_COAL_PKTS_8 -1 ];struct u64_stats_sync syncp; -}; +}____cacheline_aligned_in_smp ;struct mana_stats_tx {u64 packets;
@@ -117,7 +117,7 @@ struct mana_stats_tx {u64 csum_partial;u64 mana_map_err;struct u64_stats_sync syncp; -}; +}____cacheline_aligned_in_smp ;struct mana_txq {struct gdma_queue *gdma_sq;
@@ -146,7 +146,7 @@ struct mana_txq {/* Suppress completion wakeups on the replacement's netdev queue. */ bool retiring; -struct mana_stats_tx stats; +struct mana_stats_tx *stats; };/* skb data and frags dma mappings */
@@ -408,7 +408,7 @@ struct mana_rxq {u32 buf_index; -struct mana_stats_rx stats; +struct mana_stats_rx *stats;struct bpf_prog __rcu *bpf_prog;struct xdp_rxq_info xdp_rxq;
@@ -606,6 +606,13 @@ struct mana_port_context {unsigned int max_queues;unsigned int num_queues; +/* Port-lifetime arrays with max_queues slots. Readers sum live and +* retired RX counters. +*/ +struct mana_stats_rx *rxq_stats; +struct mana_stats_rx *rxq_stats_ret; +struct mana_stats_tx *txq_stats; +unsigned int rx_queue_size;unsigned int tx_queue_size;
[email protected]
AI reviewRe: [PATCH net-next v6 03/13] net: mana: keep per-queue statistics in the port context
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] net: mana: UAF in ndo_get_stats64 due to premature free in mana_remove - [Medium] net: mana: lost…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] net: mana: UAF in ndo_get_stats64 due to premature free in mana_remove
- [Medium] net: mana: lost xdp_xmit stats due to lockless update in mana_xdp_xmit() --
commit d18c42b1a688757d3c44ba3c118c5293e960c9e8
Author: Long Li <[email protected]>
net: mana: keep per-queue statistics in the port context
This patch prepares port-lifetime RX/TX statistics before introducing live queue replacement. It allocates max_queues slots before netdev registration and preserves counters while the interface is down.
Quoted 13 lines
drivers/net/ethernet/microsoft/mana/mana_bpf.c +1
-1@@ -68,7 +68,7 @@ int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames, count++; } - tx_stats = &apc->tx_qp[q_idx]->txq.stats; + tx_stats = apc->tx_qp[q_idx]->txq.stats;u64_stats_update_begin (&tx_stats->syncp); tx_stats->xdp_xmit += count;
Quoted 1 line
u64_stats_update_end(&tx_stats->syncp);
[Severity: Medium]
Can this result in lost statistic increments due to a data race?
When multiple CPUs perform XDP redirects to the same queue, they will execute mana_xdp_xmit() concurrently. Because tx_stats->xdp_xmit is updated outside of lock protection, the non-atomic addition operations can collide and cause lost increments.
Quoted 4 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +0
-0
[ ... ]
drivers/net/ethernet/microsoft/mana/mana_en.c void mana_remove(struct gdma_dev *gd, bool suspending) · line 4563
Quoted 8 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +1
-0@@ -4491,6 +4557,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)unregister_netdevice (ndev);mana_cleanup_indir_table (apc); +mana_free_queue_stats (apc);/* Remove the port from reset walks before freeing its netdev. */
[Severity: High]
Does this create a use-after-free race with lockless readers like mana_get_stats64()?
When mana_remove() calls unregister_netdevice(), the synchronize_net() call is deferred until rtnl_unlock() happens later. Because mana_free_queue_stats() is called here before the RCU grace period completes, concurrent readers querying the device could dereference the freed apc->rxq_stats and apc->txq_stats pointers.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Wei Hu
maintainerRE: [EXTERNAL] Re: [PATCH net-next v6 03/13] net: mana: keep per-queue statistics in the port context
Thanks for the review. I checked both findings against the v6 base, 47a144672573, and the rebased v7 base, d8674294aefe.
Quoted 2 lines
Does this create a use-after-free race with lockless readers like
mana_get_stats64()?
I do not think the reported unregister ordering is correct. The call from mana_remove() takes the immediate, non-batched unregister path:
unregister_netdevice(ndev)
-> unregister_netdevice_queue(ndev, NULL)
-> unregister_netdevice_many()
-> unregister_netdevice_many_notify()That path unlists the device and calls synchronize_net(), removes the netdev's sysfs object, and calls synchronize_net() again before returning. These steps are not deferred until the later rtnl_unlock()/netdev_run_todo() processing.
The /proc/net/dev walk holds RCU protection through dev_seq_start()/stop(). The sysfs statistics read is also RCU-protected and checks netif_is_alive(). Consequently, the reported readers are drained before unregister_netdevice() returns and mana_remove() calls mana_free_queue_stats(). This ordering is present in both bases.
I have therefore not added another grace period or moved the statistics arrays to a deferred destructor in v7 for the reported before-rtnl_unlock() window.
Quoted 1 line
Can this result in lost statistic increments due to a data race?
I agree that the xdp_xmit update can lose increments. Different CPUs can select the same TX queue, and u64_stats_sync does not exclude concurrent writers on the supported 64-bit configurations.
However, the same unlocked "tx_stats->xdp_xmit += count" is already present in mana_xdp_xmit() on the unmodified v6 base. This patch changes the stats storage from an embedded object to a pointer; it does not introduce that unlocked update.
I have recorded this as a real, independent statistics bug and am keeping its fix separate from the queue-set revision. I have not identified a queue-set regression or a blocking dependency that requires including it here. The race remains unfixed in v7; it is not being dismissed as a false positive.
Thanks,
Wei
PATCH v6 4/13 net: mana: swap queue sets in mana_set_channels
In reply to Wei HuFrom: Long Li <[email protected]>
Build a replacement queue set before quiescing TX. After closing the TX/XDP gate and draining its readers, wait up to 120 seconds for ALL old TX queues before changing pointers, queue counts or RSS. On a timeout, reject the replacement and resume the unchanged old config without reprogramming RSS or resetting the function.
Drain every old TX queue, including queues later patches may retain, so even a later failed-rollback close cannot invoke legacy FLR for old pending TX. Retirement and unpublished-set cleanup need no FLR. Allocation failure preserves live queues and configuration. After publication, failure attempts rollback; failed rollback closes the port and holds carrier down until a successful reopen.
The preceding statistics preparation removes reader dependence on queue lifetime. Add private retiring RX counters and writer handoff with this first live swap. Keep old RX counters retired until RSS restoration succeeds. Common resume_old handling for drain rejection and successful rollback restarts DIM only on actually retired RXQs, with NAPI disabled and DIM work drained, then folds counters after writer quiescence before reopening the old set.
Publish initialized fields before reopening TX/XDP and drain readers of transient RSS tables after restoring old pointers. Keep RX queue indices valid until retiring queues stop delivering them.
The temporary SQ/RQ/CQ peak is old plus new; the port EQ pool is shared, not doubled. Later patches avoid the extra queue allocation for channel-count changes; full per-queue rebuilds still need it.
Join queue selection to the publication gate so it cannot read transient RSS or queue-count state while TX is stopped. Old tail RX queues can outlive the TX-count reduction; fall back to the current RSS mapping when a recorded RX index is no longer valid.
--- .../net/ethernet/microsoft/mana/mana_bpf.c | 7 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 435 +++++++++++++++++- .../ethernet/microsoft/mana/mana_ethtool.c | 78 +++- include/net/mana/mana.h | 34 +- 4 files changed, 509 insertions(+), 45 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +6 -1
@@ -59,6 +59,11 @@ int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames,if (unlikely (!apc->port_is_up))return 0 ; +/* Pair with the smp_wmb() in mana_publish_qset() before reading queue +* state. +*/ +smp_rmb (); + q_idx =smp_processor_id () % ndev->real_num_tx_queues;for (i =0 ; i < n; i++) {
@@ -95,7 +100,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, act =bpf_prog_run_xdp (prog, xdp); - rx_stats = rxq->stats; + rx_stats =mana_rxq_stats (rxq);switch (act) {case XDP_PASS :
drivers/net/ethernet/microsoft/mana/mana_en.c +421 -14
568 lines not on this page · raw message
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +54 -24
106 lines not on this page · raw message
include/net/mana/mana.h +28 -6
@@ -408,8 +408,17 @@ struct mana_rxq {u32 buf_index; +/* Port-owned live slot; use mana_rxq_stats() to select the writer's +* slot. +*/ struct mana_stats_rx *stats; +/* Set under RTNL before another queue takes over this index. */ +bool retiring; + +/* Folded under RTNL after drain-stat writers quiesce. */ +struct mana_stats_rx drain_stats; +struct bpf_prog __rcu *bpf_prog;struct xdp_rxq_info xdp_rxq;void *xdp_save_va;/* for reusing */
@@ -606,8 +615,9 @@ struct mana_port_context {unsigned int max_queues;unsigned int num_queues; -/* Port-lifetime arrays with max_queues slots. Readers sum live and -* retired RX counters. +/* Port-lifetime arrays with max_queues slots. Live RX queues write +* rxq_stats[]; teardown and rollback fold drain_stats into +* rxq_stats_ret[] under RTNL. Readers sum both. */ struct mana_stats_rx *rxq_stats;struct mana_stats_rx *rxq_stats_ret;
@@ -623,12 +633,16 @@ struct mana_port_context {struct mutex vport_mutex;int vport_use_count; -/* Set by mana_set_channels() under vport_mutex to block RDMA -* from grabbing the vport during the detach/attach window. -* Checked by mana_cfg_vport() when called from the RDMA path. -*/ +/* Exclude RDMA during reconfiguration; protected by vport_mutex. */ bool channel_changing; +/* Caller must close the port after releasing the unpublished set. */ +bool publish_dead_end; + +/* Hold carrier off after failed rollback until a successful reopen. +*/ +bool carrier_forced_off; +/* Net shaper handle*/ struct net_shaper_handle handle;
@@ -702,10 +716,18 @@ int mana_detach(struct net_device *ndev, bool from_close);struct mana_port_context *mana_qset_scratch_alloc (struct mana_port_context *apc);void mana_qset_scratch_free (struct mana_port_context *scratch); +static inline struct mana_stats_rx *mana_rxq_stats (struct mana_rxq *rxq) +{ +return READ_ONCE (rxq->retiring) ? &rxq->drain_stats : rxq->stats; +} +int mana_alloc_qset (struct mana_port_context *apc,struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size,u32 priv_flags,struct mana_qset *out); +int mana_publish_qset (struct mana_port_context *apc,struct mana_qset *newq, +struct mana_qset *out_old); +void mana_publish_close_if_needed (struct mana_port_context *apc);void mana_free_qset (struct mana_port_context *scratch,struct mana_qset *qset);void mana_dim_change (struct mana_cq *cq,bool enable);
[email protected]
AI reviewRe: [PATCH net-next v6 04/13] net: mana: swap queue sets in mana_set_channels
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] networking: u64_stats_sync writer in mana_fold_rxq_stats does not disable preemption/BH --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] networking: u64_stats_sync writer in mana_fold_rxq_stats does not disable preemption/BH --
commit 93d72a1c224b35993067fa6f5051dfe42f90cf43
Author: Long Li <[email protected]>
net: mana: swap queue sets in mana_set_channels
Build a replacement queue set before quiescing TX. After closing the TX/XDP gate and draining its readers, wait up to 120 seconds for ALL old TX queues before changing pointers, queue counts or RSS.
Quoted 4 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +0
-0
[ ... ]
Quoted 12 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +8
-0@@ -1094,6 +1132,58 @@ static void mana_free_queue_stats(struct mana_port_context *apc) apc->txq_stats =NULL ; } +/* Fold under RTNL after drain_stats writers quiesce. Clear drain_stats to +* prevent double counting on rollback. +*/ +static void mana_fold_rxq_stats (struct mana_port_context *apc, +struct mana_rxq *rxq) +{ +struct mana_stats_rx *src = &rxq->drain_stats; +struct mana_stats_rx *dst;
drivers/net/ethernet/microsoft/mana/mana_en.c static void mana_free_queue_stats(struct mana_port_context *apc) · line 1152
Quoted 10 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +10
-0+unsigned int i; + +ASSERT_RTNL (); + +if (!apc->rxq_stats_ret || rxq->rxq_idx >= apc->max_queues) +return ; + + dst = &apc->rxq_stats_ret[rxq->rxq_idx]; + +u64_stats_update_begin (&dst->syncp);
[Severity: High]
Does this code expose a sequence counter race window to lockless readers?
The mana_fold_rxq_stats() function runs in process context under RTNL, but it calls u64_stats_update_begin() without first disabling preemption or bottom-halves (softirqs).
The u64_stats_sync API strictly requires writers to run with preemption disabled, and BH disabled if readers can be in softirq context. On 32-bit architectures, this macro increments a sequence counter.
If a reader (like ndo_get_stats64 invoked via dev_get_stats() from a softirq or another thread) preempts the writer on the same CPU while the sequence counter is odd, the reader could spin infinitely in u64_stats_fetch_retry() waiting for it to become even, causing a hard deadlock.
Should the update be wrapped in local_bh_disable() and local_bh_enable(), or use the _irqsave variant?
Quoted 19 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +19
-0+ dst->packets += src->packets; + dst->bytes += src->bytes; + dst->xdp_drop += src->xdp_drop; + dst->xdp_tx += src->xdp_tx; + dst->xdp_redirect += src->xdp_redirect; + dst->pkt_len0_err += src->pkt_len0_err; +for (i =0 ; i <ARRAY_SIZE (dst->coalesced_cqe); i++) + dst->coalesced_cqe[i] += src->coalesced_cqe[i]; +u64_stats_update_end (&dst->syncp); + + src->packets =0 ; + src->bytes =0 ; + src->xdp_drop =0 ; + src->xdp_tx =0 ; + src->xdp_redirect =0 ; + src->pkt_len0_err =0 ; +for (i =0 ; i <ARRAY_SIZE (src->coalesced_cqe); i++) + src->coalesced_cqe[i] =0 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Wei Hu
maintainerRE: [EXTERNAL] Re: [PATCH net-next v6 04/13] net: mana: swap queue sets in mana_set_channels
Thanks for the review.
Quoted 2 lines
Should the update be wrapped in
local_bh_disable()andlocal_bh_enable(), or use the_irqsavevariant?
I do not think that change is required for the reported odd-seqcount deadlock on the configurations supported by MANA.
On the v6 base, MICROSOFT_MANA depends on X86_64 or little-endian ARM64. The rebased v7 retains that PCI architecture restriction, and its upstream CDX transport separately requires 64BIT. Neither provides a supported 32-bit MANA path.
In include/linux/u64_stats_sync.h, struct u64_stats_sync has a seqcount only when BITS_PER_LONG == 32. In the 64-bit implementation, the update helpers are empty, fetch_begin returns zero, and fetch_retry returns false. There is therefore no odd sequence value or retry spin through which the reported same-CPU writer-preemption deadlock can occur.
The folding operation is serialized by RTNL and occurs after the retiring RX drain-stat writers have quiesced. I am leaving this unchanged in v7 rather than adding BH/IRQ disabling to address the unsupported 32-bit scenario. This is not a claim that arbitrary 32-bit use of these helpers would be safe; the series does not add that support.
Separately, the dashboard retains the pre-existing xdp_xmit writer concern also reported for patch 3. That unlocked increment already exists on the unmodified base. It is a real statistics race, recorded for a separate fix, and is not fixed by this revision.
Thanks,
Wei
PATCH v6 5/13 net: mana: swap queue sets in mana_set_ringparam
In reply to Wei HuFrom: Long Li <[email protected]>
Replace detach/attach with queue-set allocation and publication. Failed allocation now leaves the running queues and ring sizes unchanged, rather than risking a detached port after attach failure.
Skip requests whose rounded sizes already match. Keep RDMA excluded through failure cleanup, which can release the vport.
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
--- .../ethernet/microsoft/mana/mana_ethtool.c | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +45 -23
@@ -780,13 +780,11 @@ static int mana_set_ringparam(struct net_device *ndev, struct netlink_ext_ack *extack) {struct mana_port_context *apc =netdev_priv (ndev); +struct mana_port_context *scratch; +struct mana_qset newq, oldq;u32 new_tx, new_rx; -u32 old_tx, old_rx;int err; - old_tx = apc->tx_queue_size; - old_rx = apc->rx_queue_size; -if (ring->tx_pending <MIN_TX_BUFFERS_PER_QUEUE ) {NL_SET_ERR_MSG_FMT (extack,"tx:%d less than the min:%d" , ring->tx_pending,MIN_TX_BUFFERS_PER_QUEUE );
@@ -804,32 +802,56 @@ static int mana_set_ringparam(struct net_device *ndev,netdev_info (ndev,"Using nearest power of 2 values for Txq:%d Rxq:%d\n" , new_tx, new_rx); -/* pre-allocating new buffers to prevent failures in mana_attach() later */ - apc->rx_queue_size = new_rx; - err =mana_pre_alloc_rxbufs (apc, ndev->mtu, apc->num_queues); - apc->rx_queue_size = old_rx; -if (err) { -netdev_err (ndev,"Insufficient memory for new allocations\n" ); -return err; +if (new_rx == apc->rx_queue_size && new_tx == apc->tx_queue_size) +return 0 ; + +if (!apc->port_is_up) { + apc->rx_queue_size = new_rx; + apc->tx_queue_size = new_tx; +return 0 ; } - err =mana_detach (ndev, false); -if (err) { -netdev_err (ndev,"mana_detach failed: %d\n" , err); - goto out; +/* Exclude RDMA through failure cleanup, which may release the vport. */ +mutex_lock (&apc->vport_mutex); +if (apc->channel_changing) { +mutex_unlock (&apc->vport_mutex); +return -EBUSY ; + } + apc->channel_changing = true; +mutex_unlock (&apc->vport_mutex); + + scratch =mana_qset_scratch_alloc (apc); +if (!scratch) { + err = -ENOMEM ; + goto clear_flag; } - apc->tx_queue_size = new_tx; - apc->rx_queue_size = new_rx; + err =mana_alloc_qset (apc, scratch, apc->num_queues, new_rx, new_tx, + apc->priv_flags, &newq); +if (err) { +NL_SET_ERR_MSG_FMT (extack,"failed to change ring params: %d" , + err); + goto free_scratch; + } - err =mana_attach (ndev); + err =mana_publish_qset (apc, &newq, &oldq);if (err) { -netdev_err (ndev,"mana_attach failed: %d\n" , err); - apc->tx_queue_size = old_tx; - apc->rx_queue_size = old_rx; +NL_SET_ERR_MSG_FMT (extack,"failed to change ring params: %d" , + err); +mana_free_qset (scratch, &newq); + goto free_scratch; } -out: -mana_pre_dealloc_rxbufs (apc); + +mana_free_qset (scratch, &oldq); + +free_scratch: +/* Release unpublished queues before closing their shared EQ pool. */ +mana_publish_close_if_needed (apc); +mana_qset_scratch_free (scratch); +clear_flag: +mutex_lock (&apc->vport_mutex); + apc->channel_changing = false; +mutex_unlock (&apc->vport_mutex);return err; }
[email protected]
AI reviewRe: [PATCH net-next v6 05/13] net: mana: swap queue sets in mana_set_ringparam
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 9 lines
From: Long Li <[email protected]>
Replace detach/attach with queue-set allocation and publication. Failed allocation now leaves the running queues and ring sizes unchanged, rather than risking a detached port after attach failure.
Skip requests whose rounded sizes already match. Keep RDMA excluded through failure cleanup, which can release the vport.
Quoted 7 lines
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
PATCH v6 6/13 net: mana: swap queue sets in mana_set_priv_flags
In reply to Wei HuFrom: Long Li <[email protected]>
Rebuild queues through the swap path when USE_FULL_PAGE_RXBUF changes the RX layout. Carry priv_flags with the queue set so allocation failure leaves the live configuration unchanged and rollback restores the flags.
Retain shortcuts for an unchanged RX buffer flag, a down port, or a configuration whose MTU or XDP already requires full-page RX. A failed rollback closes the port.
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
--- .../ethernet/microsoft/mana/mana_ethtool.c | 74 +++++++++---------- 1 file changed, 36 insertions(+), 38 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +36 -38
@@ -881,7 +881,8 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags) {struct mana_port_context *apc =netdev_priv (ndev);u32 changed = apc->priv_flags ^ priv_flags; -u32 old_priv_flags = apc->priv_flags; +struct mana_port_context *scratch; +struct mana_qset newq, oldq;int err =0 ;if (!changed)
@@ -891,54 +892,51 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags)if (priv_flags & ~GENMASK (MANA_PRIV_FLAG_MAX -1 ,0 ))return -EINVAL ; - apc->priv_flags = priv_flags; - -if (changed &BIT (MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF )) { -if (!apc->port_is_up) -return 0 ; - -/* If XDP is attached or MTU is jumbo, single-buffer-per-page -* is already forced regardless of this flag. Skip the -* expensive detach/attach cycle since nothing changes. -*/ -if (ndev->mtu +MANA_RXBUF_PAD >PAGE_SIZE /2 || -mana_xdp_get (apc)) -return 0 ; +/* No rebuild is needed if the RX buffer flag is unchanged, the port is +* down, or full-page RX buffers are already required by MTU or XDP. +*/ +if (!(changed &BIT (MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF )) || + !apc->port_is_up || + ndev->mtu +MANA_RXBUF_PAD >PAGE_SIZE /2 || +mana_xdp_get (apc)) { + apc->priv_flags = priv_flags; +return 0 ; + } -/* Block RDMA from grabbing the vport during detach/attach */ -mutex_lock (&apc->vport_mutex); - apc->channel_changing = true; +mutex_lock (&apc->vport_mutex); +if (apc->channel_changing) {mutex_unlock (&apc->vport_mutex); +return -EBUSY ; + } + apc->channel_changing = true; +mutex_unlock (&apc->vport_mutex); - err =mana_pre_alloc_rxbufs (apc, ndev->mtu, apc->num_queues); -if (err) { -netdev_err (ndev, -"Insufficient memory for new allocations\n" ); - apc->priv_flags = old_priv_flags; - goto clear_flag; - } + scratch =mana_qset_scratch_alloc (apc); +if (!scratch) { + err = -ENOMEM ; + goto clear_flag; + } - err =mana_detach (ndev, false); -if (err) { -netdev_err (ndev,"mana_detach failed: %d\n" , err); - apc->priv_flags = old_priv_flags; - goto out; - } + err =mana_alloc_qset (apc, scratch, apc->num_queues, apc->rx_queue_size, + apc->tx_queue_size, priv_flags, &newq); +if (err) + goto free_scratch; - err =mana_attach (ndev); -if (err) { -netdev_err (ndev,"mana_attach failed: %d\n" , err); - apc->priv_flags = old_priv_flags; - } + err =mana_publish_qset (apc, &newq, &oldq); +if (err) { +mana_free_qset (scratch, &newq); + goto free_scratch; } -out: -mana_pre_dealloc_rxbufs (apc); +mana_free_qset (scratch, &oldq); + +free_scratch: +mana_publish_close_if_needed (apc); +mana_qset_scratch_free (scratch); clear_flag:mutex_lock (&apc->vport_mutex); apc->channel_changing = false;mutex_unlock (&apc->vport_mutex); -return err; }
[email protected]
AI reviewRe: [PATCH net-next v6 06/13] net: mana: swap queue sets in mana_set_priv_flags
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines
From: Long Li <[email protected]>
Rebuild queues through the swap path when
USE_FULL_PAGE_RXBUFchanges the RX layout. Carrypriv_flagswith the queue set so allocation failure leaves the live configuration unchanged and rollback restores the flags.Retain shortcuts for an unchanged RX buffer flag, a down port, or a configuration whose MTU or XDP already requires full-page RX. A failed rollback closes the port.
Quoted 7 lines
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
PATCH v6 7/13 net: mana: swap queue sets in mana_change_mtu
In reply to Wei HuFrom: Long Li <[email protected]>
Carry the MTU in the queue set and size replacement RX buffers from it. Publish ndev->mtu after RSS configuration succeeds; allocation failure leaves the live queues and advertised MTU unchanged.
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
Reserve RAW-QP admission under vport_mutex for the entire live replacement, including unpublished queues, fail-close and scratch cleanup. Preserve validation, no-op and down-port behavior.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 66 ++++++++++++++----- .../ethernet/microsoft/mana/mana_ethtool.c | 10 +-- include/net/mana/mana.h | 7 +- 3 files changed, 60 insertions(+), 23 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +48 -18
@@ -927,32 +927,52 @@ int mana_pre_alloc_rxbufs(struct mana_port_context *mpc, int new_mtu, int num_qustatic int mana_change_mtu (struct net_device *ndev,int new_mtu) {struct mana_port_context *mpc =netdev_priv (ndev); -unsigned int old_mtu = ndev->mtu; +struct mana_port_context *scratch; +struct mana_qset newq, oldq;int err; -/* Pre-allocate buffers to prevent failure in mana_attach later */ - err =mana_pre_alloc_rxbufs (mpc, new_mtu, mpc->num_queues); -if (err) { -netdev_err (ndev,"Insufficient memory for new MTU\n" ); -return err; +if (!mpc->port_is_up) { + mpc->configured_mtu = new_mtu; +WRITE_ONCE (ndev->mtu, new_mtu); +return 0 ; } - err =mana_detach (ndev, false); -if (err) { -netdev_err (ndev,"mana_detach failed: %d\n" , err); - goto out; +/* Fail-close may release the Ethernet vport reference. */ +mutex_lock (&mpc->vport_mutex); +if (mpc->channel_changing) { +mutex_unlock (&mpc->vport_mutex); +return -EBUSY ; + } + mpc->channel_changing = true; +mutex_unlock (&mpc->vport_mutex); + + scratch =mana_qset_scratch_alloc (mpc); +if (!scratch) { + err = -ENOMEM ; + goto clear_flag; } -WRITE_ONCE (ndev->mtu, new_mtu); + err =mana_alloc_qset (mpc, scratch, mpc->num_queues, + mpc->rx_queue_size, mpc->tx_queue_size, + mpc->priv_flags, new_mtu, &newq); +if (err) + goto free_scratch; - err =mana_attach (ndev); + err =mana_publish_qset (mpc, &newq, &oldq);if (err) { -netdev_err (ndev,"mana_attach failed: %d\n" , err); -WRITE_ONCE (ndev->mtu, old_mtu); +mana_free_qset (scratch, &newq); + goto free_scratch; } -out: -mana_pre_dealloc_rxbufs (mpc); +mana_free_qset (scratch, &oldq); + +free_scratch: +mana_publish_close_if_needed (mpc); +mana_qset_scratch_free (scratch); +clear_flag: +mutex_lock (&mpc->vport_mutex); + mpc->channel_changing = false; +mutex_unlock (&mpc->vport_mutex);return err; }
@@ -3306,7 +3326,8 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, rxq->rxq_idx = rxq_idx; rxq->rxobj =INVALID_MANA_HANDLE ; -mana_get_rxbuf_cfg (apc, ndev->mtu, &rxq->datasize, &rxq->alloc_size, +mana_get_rxbuf_cfg (apc, apc->configured_mtu, &rxq->datasize, + &rxq->alloc_size, &rxq->headroom, &rxq->frag_count);/* Create page pool for RX queue */ err =mana_create_page_pool (rxq, gc);
@@ -4017,6 +4038,7 @@ static void mana_qset_snapshot(const struct mana_port_context *ctx, out->rx_queue_size = ctx->rx_queue_size; out->tx_queue_size = ctx->tx_queue_size; out->priv_flags = ctx->priv_flags; + out->mtu = ctx->configured_mtu; }/* Vport identity and port debugfs outlive queue sets. */
@@ -4033,6 +4055,7 @@ static void mana_qset_install(struct mana_port_context *ctx, ctx->rx_queue_size = qset->rx_queue_size; ctx->tx_queue_size = qset->tx_queue_size; ctx->priv_flags = qset->priv_flags; + ctx->configured_mtu = qset->mtu; }/* Scratch starts without SQs/RQs and borrows the port's EQ pool. Never call
@@ -4073,7 +4096,7 @@ void mana_qset_scratch_free(struct mana_port_context *scratch)int mana_alloc_qset (struct mana_port_context *apc,struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size, -u32 priv_flags,struct mana_qset *out) +u32 priv_flags,int mtu,struct mana_qset *out) {struct net_device *ndev = scratch->ndev;int err;
@@ -4085,6 +4108,8 @@ int mana_alloc_qset(struct mana_port_context *apc, scratch->tx_queue_size = tx_queue_size; scratch->priv_flags = priv_flags; + scratch->configured_mtu = mtu; + err =mana_init_port_context (scratch);if (err) goto out_err;
@@ -4337,6 +4362,8 @@ int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq,if (err) goto rollback; +WRITE_ONCE (ndev->mtu, apc->configured_mtu); +/* Publish fields before opening the gate; pair with TX/XDP read * barriers. The post-gate full barrier cannot replace this. */
@@ -4392,6 +4419,8 @@ int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq,synchronize_net ();mana_fold_qset_rx_stats (apc, out_old); +WRITE_ONCE (ndev->mtu, apc->configured_mtu); +/* Publish restored fields before reopening the gate, as on success. */ smp_wmb ();
@@ -4544,6 +4573,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, apc->port_handle =INVALID_MANA_HANDLE ; apc->pf_filter_handle =INVALID_MANA_HANDLE ; apc->port_idx = port_idx; + apc->configured_mtu = ndev->mtu; apc->link_cfg_error =1 ; apc->cqe_coalescing_enable =0 ; apc->cqe8_coalescing_enable =0 ;
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +6 -4
@@ -738,7 +738,8 @@ static int mana_set_channels(struct net_device *ndev, } err =mana_alloc_qset (apc, scratch, new_count, apc->rx_queue_size, - apc->tx_queue_size, apc->priv_flags, &newq); + apc->tx_queue_size, apc->priv_flags, + apc->configured_mtu, &newq);if (err) goto free_scratch;
@@ -827,7 +828,7 @@ static int mana_set_ringparam(struct net_device *ndev, } err =mana_alloc_qset (apc, scratch, apc->num_queues, new_rx, new_tx, - apc->priv_flags, &newq); + apc->priv_flags, apc->configured_mtu, &newq);if (err) {NL_SET_ERR_MSG_FMT (extack,"failed to change ring params: %d" , err);
@@ -917,8 +918,9 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags) goto clear_flag; } - err =mana_alloc_qset (apc, scratch, apc->num_queues, apc->rx_queue_size, - apc->tx_queue_size, priv_flags, &newq); + err =mana_alloc_qset (apc, scratch, apc->num_queues, + apc->rx_queue_size, apc->tx_queue_size, + priv_flags, apc->configured_mtu, &newq);if (err) goto free_scratch;
include/net/mana/mana.h +6 -1
@@ -626,6 +626,10 @@ struct mana_port_context {unsigned int rx_queue_size;unsigned int tx_queue_size; +/* MTU used to size RX buffers, independent of ndev->mtu during a swap. +*/ +int configured_mtu; +mana_handle_t port_handle;mana_handle_t pf_filter_handle;
@@ -702,6 +706,7 @@ struct mana_qset {unsigned int tx_queue_size;u32 priv_flags; +int mtu; };netdev_tx_t mana_start_xmit (struct sk_buff *skb,struct net_device *ndev);
@@ -724,7 +729,7 @@ static inline struct mana_stats_rx *mana_rxq_stats(struct mana_rxq *rxq)int mana_alloc_qset (struct mana_port_context *apc,struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size, -u32 priv_flags,struct mana_qset *out); +u32 priv_flags,int mtu,struct mana_qset *out);int mana_publish_qset (struct mana_port_context *apc,struct mana_qset *newq,struct mana_qset *out_old);void mana_publish_close_if_needed (struct mana_port_context *apc);
[email protected]
AI reviewRe: [PATCH net-next v6 07/13] net: mana: swap queue sets in mana_change_mtu
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Deadlock on 32-bit systems due to u64_stats_update_begin with preemption enabled --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Deadlock on 32-bit systems due to u64_stats_update_begin with preemption enabled --
commit 9fbccd82cfbdb308859b32b732f45f8415ee4bd0
Author: Long Li <[email protected]>
net: mana: swap queue sets in mana_change_mtu
This commit carries the MTU in the queue set and replaces the RX buffers from it. It swaps queue sets in mana_change_mtu by allocating a new scratch context, publishing the new queue set, and cleaning up the old one upon success or failure.
Quoted 3 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +0
-0
[ ... ]
drivers/net/ethernet/microsoft/mana/mana_en.c int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq, · line 4425
Quoted 8 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +2
-0@@ -4392,6 +4419,8 @@ int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq,synchronize_net ();mana_fold_qset_rx_stats (apc, out_old); +WRITE_ONCE (ndev->mtu, apc->configured_mtu); +/* Publish restored fields before reopening the gate, as on success. */ smp_wmb ();
[Severity: High]
Can this lead to a deadlock on 32-bit systems?
The mana_publish_qset function executes under the rtnl lock with preemption enabled, which leads to this call chain:
mana_publish_qset()
mana_fold_qset_rx_stats()
mana_fold_rxq_stats() {
u64_stats_update_begin(&dst->syncp);
dst->packets += src->packets;
dst->bytes += src->bytes;
...
u64_stats_update_end(&dst->syncp);
}Because preemption is enabled, on 32-bit architectures, a reader such as ndo_get_stats64() could preempt the writer while the sequence count is odd. The reader would then spin forever in u64_stats_fetch_retry() waiting for an even sequence count, starving the preempted writer and resulting in a deadlock.
Should preemption or interrupts be disabled around this stats update to ensure readers cannot preempt the writer?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Wei Hu
maintainerRE: [EXTERNAL] Re: [PATCH net-next v6 07/13] net: mana: swap queue sets in mana_change_mtu
Thanks for the review.
Quoted 1 line
Can this lead to a deadlock on 32-bit systems?
The described odd-seqcount deadlock requires a 32-bit MANA configuration, which is not supported by either the v6 base or the rebased v7.
MICROSOFT_MANA is restricted to X86_64 or little-endian ARM64. The upstream CDX transport present in the v7 base also explicitly requires 64BIT. The common GDMA core is selected by those supported transports; it does not provide a separate 32-bit MANA device path.
On 64-bit, include/linux/u64_stats_sync.h has no seqcount in struct u64_stats_sync. Its update helpers are empty and fetch_retry always returns false. A reader cannot enter the odd-sequence retry loop described in the report, even if the folding task is preempted.
The MTU change does not change these architecture constraints or the 64-bit helper implementation. The fold remains under RTNL and after quiescing the retiring RX drain-stat writers.
I have therefore not added preemption/IRQ disabling for this report in v7. This conclusion concerns the reported seqcount deadlock, not a guarantee for a hypothetical future 32-bit port or for unrelated concurrent-writer statistics bugs.
Thanks,
Wei
PATCH v6 8/13 net: mana: swap queue sets in mana_xdp_set
In reply to Wei HuFrom: Long Li <[email protected]>
Carry the XDP program with the queue set and install its per-queue references before redirecting RSS. This keeps the RX buffer layout and program together during publication and rollback.
Do not replace the live program during allocation. This also avoids the pre-existing failed-preallocation stale-pointer bug; its standalone net fix is linked below.
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
Reserve RAW-QP admission under vport_mutex for the entire live replacement, including unpublished queues, fail-close and scratch cleanup. Preserve validation, no-op and down-port behavior.
--- .../net/ethernet/microsoft/mana/mana_bpf.c | 75 +++++++++++-------- drivers/net/ethernet/microsoft/mana/mana_en.c | 12 ++- .../ethernet/microsoft/mana/mana_ethtool.c | 11 +-- include/net/mana/mana.h | 5 +- 4 files changed, 60 insertions(+), 43 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +42 -33
@@ -177,6 +177,8 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, struct netlink_ext_ack *extack) {struct mana_port_context *apc =netdev_priv (ndev); +struct mana_port_context *scratch; +struct mana_qset newq, oldq;struct bpf_prog *old_prog;struct gdma_context *gc;int err;
@@ -196,47 +198,59 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,return -EOPNOTSUPP ; } -/* One refcnt of the prog is hold by the caller already, so -* don't increase refcnt for this one. -*/ - apc->bpf_prog = prog; -if (apc->port_is_up) { -/* Re-create rxq's after xdp prog was loaded or unloaded. -* Ex: re create rxq's to switch from full pages to smaller -* size page fragments when xdp prog is unloaded and -* vice-versa. -*/ +/* Fail-close may release the Ethernet vport reference. */ +mutex_lock (&apc->vport_mutex); +if (apc->channel_changing) { +mutex_unlock (&apc->vport_mutex); +return -EBUSY ; + } + apc->channel_changing = true; +mutex_unlock (&apc->vport_mutex); -/* Pre-allocate buffers to prevent failure in mana_attach */ - err =mana_pre_alloc_rxbufs (apc, ndev->mtu, apc->num_queues); -if (err) { + scratch =mana_qset_scratch_alloc (apc); +if (!scratch) {NL_SET_ERR_MSG_MOD (extack, -"XDP: Insufficient memory for tx/rx re-config" ); - apc->bpf_prog = old_prog; -return err; +"XDP: Insufficient memory for re-config" ); + err = -ENOMEM ; + goto clear_flag; } - err =mana_detach (ndev, false); + err =mana_alloc_qset (apc, scratch, apc->num_queues, + apc->rx_queue_size, apc->tx_queue_size, + apc->priv_flags, apc->configured_mtu, + prog, &newq);if (err) { -netdev_err (ndev, -"mana_detach failed at xdp set: %d\n" , err);NL_SET_ERR_MSG_MOD (extack, -"XDP: Re-config failed at detach" ); - goto err_dealloc_rxbuffs; +"XDP: Re-config failed at alloc" ); + goto free_scratch; } - err =mana_attach (ndev); + err =mana_publish_qset (apc, &newq, &oldq);if (err) { -netdev_err (ndev, -"mana_attach failed at xdp set: %d\n" , err);NL_SET_ERR_MSG_MOD (extack, -"XDP: Re-config failed at attach" ); - goto err_dealloc_rxbuffs; +"XDP: Re-config failed at publish" ); +mana_free_qset (scratch, &newq); +/* Free the queues before closing their shared EQ pool. +*/ +mana_publish_close_if_needed (apc); + goto free_scratch; } -mana_chn_setxdp (apc, prog); -mana_pre_dealloc_rxbufs (apc); +mana_free_qset (scratch, &oldq); +free_scratch: +mana_qset_scratch_free (scratch); +clear_flag: +mutex_lock (&apc->vport_mutex); + apc->channel_changing = false; +mutex_unlock (&apc->vport_mutex); +if (err) +return err; + }else { +/* Use the caller's program reference; mana_open() installs it +* on queues. +*/ + apc->bpf_prog = prog; }if (old_prog)
@@ -249,11 +263,6 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, ndev->max_mtu = gc->adapter_mtu -ETH_HLEN ;return 0 ; - -err_dealloc_rxbuffs: - apc->bpf_prog = old_prog; -mana_pre_dealloc_rxbufs (apc); -return err; }int mana_bpf (struct net_device *ndev,struct netdev_bpf *bpf)
drivers/net/ethernet/microsoft/mana/mana_en.c +8 -4
@@ -952,9 +952,9 @@ static int mana_change_mtu(struct net_device *ndev, int new_mtu) goto clear_flag; } - err =mana_alloc_qset (mpc, scratch, mpc->num_queues, - mpc->rx_queue_size, mpc->tx_queue_size, - mpc->priv_flags, new_mtu, &newq); + err =mana_alloc_qset (mpc, scratch, mpc->num_queues, mpc->rx_queue_size, + mpc->tx_queue_size, mpc->priv_flags, new_mtu, + mpc->bpf_prog, &newq);if (err) goto free_scratch;
@@ -4039,6 +4039,7 @@ static void mana_qset_snapshot(const struct mana_port_context *ctx, out->tx_queue_size = ctx->tx_queue_size; out->priv_flags = ctx->priv_flags; out->mtu = ctx->configured_mtu; + out->bpf_prog = ctx->bpf_prog; }/* Vport identity and port debugfs outlive queue sets. */
@@ -4056,6 +4057,7 @@ static void mana_qset_install(struct mana_port_context *ctx, ctx->tx_queue_size = qset->tx_queue_size; ctx->priv_flags = qset->priv_flags; ctx->configured_mtu = qset->mtu; + ctx->bpf_prog = qset->bpf_prog; }/* Scratch starts without SQs/RQs and borrows the port's EQ pool. Never call
@@ -4096,7 +4098,8 @@ void mana_qset_scratch_free(struct mana_port_context *scratch)int mana_alloc_qset (struct mana_port_context *apc,struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size, -u32 priv_flags,int mtu,struct mana_qset *out) +u32 priv_flags,int mtu,struct bpf_prog *bpf_prog, +struct mana_qset *out) {struct net_device *ndev = scratch->ndev;int err;
@@ -4109,6 +4112,7 @@ int mana_alloc_qset(struct mana_port_context *apc, scratch->priv_flags = priv_flags; scratch->configured_mtu = mtu; + scratch->bpf_prog = bpf_prog; err =mana_init_port_context (scratch);if (err)
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +6 -5
@@ -739,7 +739,7 @@ static int mana_set_channels(struct net_device *ndev, err =mana_alloc_qset (apc, scratch, new_count, apc->rx_queue_size, apc->tx_queue_size, apc->priv_flags, - apc->configured_mtu, &newq); + apc->configured_mtu, apc->bpf_prog, &newq);if (err) goto free_scratch;
@@ -828,7 +828,8 @@ static int mana_set_ringparam(struct net_device *ndev, } err =mana_alloc_qset (apc, scratch, apc->num_queues, new_rx, new_tx, - apc->priv_flags, apc->configured_mtu, &newq); + apc->priv_flags, apc->configured_mtu, + apc->bpf_prog, &newq);if (err) {NL_SET_ERR_MSG_FMT (extack,"failed to change ring params: %d" , err);
@@ -918,9 +919,9 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags) goto clear_flag; } - err =mana_alloc_qset (apc, scratch, apc->num_queues, - apc->rx_queue_size, apc->tx_queue_size, - priv_flags, apc->configured_mtu, &newq); + err =mana_alloc_qset (apc, scratch, apc->num_queues, apc->rx_queue_size, + apc->tx_queue_size, priv_flags, + apc->configured_mtu, apc->bpf_prog, &newq);if (err) goto free_scratch;
include/net/mana/mana.h +4 -1
@@ -707,6 +707,8 @@ struct mana_qset {u32 priv_flags;int mtu; +struct bpf_prog *bpf_prog; + };netdev_tx_t mana_start_xmit (struct sk_buff *skb,struct net_device *ndev);
@@ -729,7 +731,8 @@ static inline struct mana_stats_rx *mana_rxq_stats(struct mana_rxq *rxq)int mana_alloc_qset (struct mana_port_context *apc,struct mana_port_context *scratch,unsigned int num_queues,unsigned int rx_queue_size,unsigned int tx_queue_size, -u32 priv_flags,int mtu,struct mana_qset *out); +u32 priv_flags,int mtu,struct bpf_prog *bpf_prog, +struct mana_qset *out);int mana_publish_qset (struct mana_port_context *apc,struct mana_qset *newq,struct mana_qset *out_old);void mana_publish_close_if_needed (struct mana_port_context *apc);
[email protected]
AI reviewRe: [PATCH net-next v6 08/13] net: mana: swap queue sets in mana_xdp_set
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 15 lines
From: Long Li <[email protected]>
Carry the XDP program with the queue set and install its per-queue references before redirecting RSS. This keeps the RX buffer layout and program together during publication and rollback.
Do not replace the live program during allocation. This also avoids the pre-existing failed-preallocation stale-pointer bug; its standalone net fix is linked below.
This full rebuild temporarily keeps both sets of SQ/RQ/CQ objects, RX buffers and page pools live. The port-owned EQ pool is shared, not doubled. Device resource limits may reject this temporary peak; allocation failure preserves the live queues and configuration.
Quoted 8 lines
Reserve RAW-QP admission under
vport_mutexfor the entire live replacement, including unpublished queues, fail-close and scratch cleanup. Preserve validation, no-op and down-port behavior.Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
PATCH v6 9/13 net: mana: do not bail out of mana_detach on dealloc failure
In reply to Wei HuFrom: Dipayaan Roy <[email protected]>
Remove the early return after mana_dealloc_queues() so detach continues its device and port-context cleanup.
The return is currently unreachable: mana_dealloc_queues() only rejects an up port, and mana_detach() clears port_is_up before calling it. This is a robustness cleanup, not a fix for a reachable reset failure.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +1 -3
@@ -4537,10 +4537,8 @@ int mana_detach(struct net_device *ndev, bool from_close)if (apc->port_st_save) { err =mana_dealloc_queues (ndev); -if (err) { +if (err)netdev_err (ndev,"%s failed to deallocate queues: %d\n" , __func__, err); -return err; - } }if (!from_close) {
[email protected]
AI reviewRe: [PATCH net-next v6 09/13] net: mana: do not bail out of mana_detach on dealloc failure
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] mana_detach() unconditionally returns 0 making caller error checks dead code --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] mana_detach() unconditionally returns 0 making caller error checks dead code --
commit 69defa182668486dbe34c62749b906b0d4dc31b1
Author: Dipayaan Roy <[email protected]>
net: mana: do not bail out of mana_detach on dealloc failure
This commit removes the early error return from mana_detach() when mana_dealloc_queues() fails, ensuring that device and port-context cleanup continues.
drivers/net/ethernet/microsoft/mana/mana_en.c int mana_detach(struct net_device *ndev, bool from_close) · line 4543
Quoted 13 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +1
-3@@ -4537,10 +4537,8 @@ int mana_detach(struct net_device *ndev, bool from_close)if (apc->port_st_save) { err =mana_dealloc_queues (ndev); -if (err) { +if (err)netdev_err (ndev,"%s failed to deallocate queues: %d\n" , __func__, err); -return err; - }
[Severity: Low]
Because mana_detach() now unconditionally returns 0, the error checks in callers have become dead code. For example, in mana_per_port_queue_reset_work_handler():
err = mana_detach(ndev, false);
if (err) {
netdev_err(ndev, "mana_detach failed: %d\n", err);
goto dealloc_pre_rxbufs;
}Would it make sense to update mana_detach() to return void and remove the unreachable error handling paths in its callers?
Quoted 3 lines
drivers/net/ethernet/microsoft/mana/mana_en.c +0
-0}if (!from_close) {
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
PATCH v6 10/13 net: mana: release EQs left idle by a channel-count reduction
In reply to Wei HuFrom: Long Li <[email protected]>
Release EQs above the live queue count after retiring queues are freed or replacement allocation fails. All CQs using those EQs must be gone. Return their vector allocations to the pool; IRQ registrations remain.
Store each EQ's debugfs dentry in apc->eqs[] rather than a stack copy so shrinking can remove individual EQ directories.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 49 ++++++++++++++++--- .../ethernet/microsoft/mana/mana_ethtool.c | 1 - 2 files changed, 41 insertions(+), 9 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +41 -8
@@ -1910,6 +1910,8 @@ void mana_destroy_eq(struct mana_port_context *apc) msi = eq->eq.msix_index;mana_gd_destroy_queue (gc, eq);mana_gd_put_gic (gc, !gc->msi_sharing, msi); + apc->eqs[i].eq =NULL ; + apc->eqs[i].mana_eq_debugfs =NULL ; }kfree (apc->eqs);
@@ -1920,15 +1922,16 @@ EXPORT_SYMBOL_NS(mana_destroy_eq, "NET_MANA");static void mana_create_eq_debugfs (struct mana_port_context *apc,int i) { -struct mana_eq eq = apc->eqs[i]; +struct mana_eq *eq = &apc->eqs[i];char eqnum[32 ];sprintf (eqnum,"eq%d" , i); - eq.mana_eq_debugfs =debugfs_create_dir (eqnum, apc->mana_eqs_debugfs); -debugfs_create_u32 ("head" ,0400 , eq.mana_eq_debugfs, &eq.eq->head); -debugfs_create_u32 ("tail" ,0400 , eq.mana_eq_debugfs, &eq.eq->tail); -debugfs_create_u32 ("irq" ,0400 , eq.mana_eq_debugfs, &eq.eq->eq.irq); -debugfs_create_file ("eq_dump" ,0400 , eq.mana_eq_debugfs, eq.eq, &mana_dbg_q_fops); + eq->mana_eq_debugfs =debugfs_create_dir (eqnum, apc->mana_eqs_debugfs); +debugfs_create_u32 ("head" ,0400 , eq->mana_eq_debugfs, &eq->eq->head); +debugfs_create_u32 ("tail" ,0400 , eq->mana_eq_debugfs, &eq->eq->tail); +debugfs_create_u32 ("irq" ,0400 , eq->mana_eq_debugfs, &eq->eq->eq.irq); +debugfs_create_file ("eq_dump" ,0400 , eq->mana_eq_debugfs, eq->eq, + &mana_dbg_q_fops); }int mana_create_eq (struct mana_port_context *apc)
@@ -2037,11 +2040,37 @@ static int mana_grow_eqs(struct mana_port_context *apc, unsigned int need)return 0 ; out: -/* Retain partial growth for reuse; the live set still needs this pool. -*/ return err; } +/* All CQs referencing EQs at or above @keep must be destroyed first. */ +static void mana_shrink_eqs (struct mana_port_context *apc,unsigned int keep) +{ +struct gdma_context *gc = apc->ac->gdma_dev->gdma_context; +struct gdma_queue *eq; +unsigned int msi; +unsigned int i; + +if (!apc->eqs || keep >= apc->num_eqs) +return ; + +for (i = keep; i < apc->num_eqs; i++) { + eq = apc->eqs[i].eq; +if (!eq) +continue ; + +debugfs_remove_recursive (apc->eqs[i].mana_eq_debugfs); + apc->eqs[i].mana_eq_debugfs =NULL ; + + msi = eq->eq.msix_index; +mana_gd_destroy_queue (gc, eq); +mana_gd_put_gic (gc, !gc->msi_sharing, msi); + apc->eqs[i].eq =NULL ; + } + + apc->num_eqs = keep; +} +static int mana_fence_rq (struct mana_port_context *apc,struct mana_rxq *rxq) {struct mana_fence_rq_resp resp = {};
@@ -4151,6 +4180,8 @@ int mana_alloc_qset(struct mana_port_context *apc,kfree (scratch->rxqs); scratch->rxqs =NULL ; out_err: +mana_shrink_eqs (apc, apc->num_queues); +netdev_err (ndev,"%s(num_queues=%u) failed: %d\n" , __func__, num_queues, err);return err;
@@ -4511,6 +4542,8 @@ void mana_free_qset(struct mana_port_context *scratch, struct mana_qset *qset)*/ netif_set_real_num_rx_queues (apc->ndev, apc->num_queues); +mana_shrink_eqs (apc, apc->num_queues); +mana_qset_debugfs_publish (apc); }
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +0 -1
@@ -752,7 +752,6 @@ static int mana_set_channels(struct net_device *ndev,mana_free_qset (scratch, &oldq); free_scratch: -/* Release unpublished queues before closing their shared EQ pool. */ mana_publish_close_if_needed (apc);mana_qset_scratch_free (scratch); clear_flag:
[email protected]
AI reviewRe: [PATCH net-next v6 10/13] net: mana: release EQs left idle by a channel-count reduction
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 11 lines
From: Long Li <[email protected]>
Release EQs above the live queue count after retiring queues are freed or replacement allocation fails. All CQs using those EQs must be gone. Return their vector allocations to the pool; IRQ registrations remain.
Store each EQ's debugfs dentry in apc->eqs[] rather than a stack copy so shrinking can remove individual EQ directories.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
PATCH v6 11/13 net: mana: keep a user-configured RSS table across a queue rebuild
In reply to Wei HuFrom: Long Li <[email protected]>
Preserve a user RSS table whenever all entries fit the requested queue count. Regenerate driver defaults. On growth, a retained user table does not steer RSS traffic to the added queues until the user updates it.
Report table loss only after successful queue-set publication. The non-swap allocation path still replaces invalid tables silently because its callers do not consistently hold the notification's netdev lock.
Require RTNL for RSS setters to serialize them with reset/resume rebuilds.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 41 +++++++++++++++++-- .../ethernet/microsoft/mana/mana_ethtool.c | 3 +- include/net/mana/mana.h | 2 + 3 files changed, 42 insertions(+), 4 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +38 -3
@@ -3595,6 +3595,27 @@ static void mana_rss_table_init(struct mana_port_context *apc)ethtool_rxfh_indir_default (i, apc->num_queues); } +/* Keep user tables with valid indices; defer loss notification. */ +static bool mana_rss_table_keep (struct mana_port_context *apc, +unsigned int num_queues,bool *lost) +{ +u32 i; + + *lost = false; + +if (!netif_is_rxfh_configured (apc->ndev)) +return false; + +for (i =0 ; i < apc->indir_table_sz; i++) { +if (apc->indir_table[i] >= num_queues) { + *lost = true; +return false; + } + } + +return true; +} +int mana_disable_vport_rx (struct mana_port_context *apc) { return mana_cfg_vport_steering(apc, TRI_STATE_FALSE, false, false,
@@ -3865,6 +3886,7 @@ int mana_alloc_queues(struct net_device *ndev) {struct mana_port_context *apc =netdev_priv (ndev);struct gdma_dev *gd = apc->ac->gdma_dev; +bool indir_lost;int err; err =mana_create_vport (apc, ndev);
@@ -3910,7 +3932,9 @@ int mana_alloc_queues(struct net_device *ndev) goto destroy_rxq; } -mana_rss_table_init (apc); +/* Loss notification needs a netdev instance lock we may lack. */ +if (!mana_rss_table_keep (apc, apc->num_queues, &indir_lost)) +mana_rss_table_init (apc); err =mana_config_rss (apc,TRI_STATE_TRUE , true, true);if (err) {
@@ -4069,9 +4093,10 @@ static void mana_qset_snapshot(const struct mana_port_context *ctx, out->priv_flags = ctx->priv_flags; out->mtu = ctx->configured_mtu; out->bpf_prog = ctx->bpf_prog; + + out->rxfh_indir_lost = false; } -/* Vport identity and port debugfs outlive queue sets. */ static void mana_qset_install (struct mana_port_context *ctx,const struct mana_qset *qset) {
@@ -4131,6 +4156,7 @@ int mana_alloc_qset(struct mana_port_context *apc, struct mana_qset *out) {struct net_device *ndev = scratch->ndev; +bool indir_lost;int err;ASSERT_RTNL ();
@@ -4166,9 +4192,14 @@ int mana_alloc_qset(struct mana_port_context *apc,if (err) goto cleanup_rxq; -mana_rss_table_init (scratch); +if (mana_rss_table_keep (apc, num_queues, &indir_lost)) +memcpy (scratch->indir_table, apc->indir_table, + apc->indir_table_sz *sizeof (*apc->indir_table)); +else +mana_rss_table_init (scratch);mana_qset_snapshot (scratch, out); + out->rxfh_indir_lost = indir_lost;return 0 ; cleanup_rxq:
@@ -4407,6 +4438,10 @@ int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq,WRITE_ONCE (apc->port_is_up, true);mana_start_txqs (apc); +/* Report a lost user table only after successful publication. */ +if (newq->rxfh_indir_lost) +ethtool_rxfh_indir_lost (ndev); +return 0 ; rollback:
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +2 -1
@@ -953,7 +953,8 @@ const struct ethtool_ops mana_ethtool_ops = { .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS |ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM |ETHTOOL_OP_NEEDS_RTNL_SPFLAGS | - ETHTOOL_OP_NEEDS_RTNL_GLINK, +ETHTOOL_OP_NEEDS_RTNL_GLINK | + ETHTOOL_OP_NEEDS_RTNL_RSS, .get_ethtool_stats = mana_get_ethtool_stats, .get_sset_count = mana_get_sset_count, .get_strings = mana_get_strings,
include/net/mana/mana.h +2 -0
@@ -709,6 +709,8 @@ struct mana_qset {int mtu;struct bpf_prog *bpf_prog; +/* Notify the core only after this set is published. */ +bool rxfh_indir_lost; };netdev_tx_t mana_start_xmit (struct sk_buff *skb,struct net_device *ndev);
[email protected]
AI reviewRe: [PATCH net-next v6 11/13] net: mana: keep a user-configured RSS table across a queue rebuild
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 6 lines
From: Long Li <[email protected]>
Preserve a user RSS table whenever all entries fit the requested queue count. Regenerate driver defaults. On growth, a retained user table does not steer RSS traffic to the added queues until the user updates it.
Quoted 8 lines
Report table loss only after successful queue-set publication. The non-swap allocation path still replaces invalid tables silently because its callers do not consistently hold the notification's netdev lock.
Require RTNL for RSS setters to serialize them with reset/resume rebuilds.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
PATCH v6 12/13 net: mana: keep the surviving queues when the channel count is reduced
In reply to Wei HuFrom: Long Li <[email protected]>
Split the live set into a kept prefix and a retiring tail. Reductions allocate only pointer arrays and steering tables, retaining the kept queues' page pools, buffers, NAPI state and XDP references.
After publication, wait for TX-selection readers before freeing the old containers, then retire only the tail. Failed publication discards the new containers without freeing shared queues.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 112 +++++++++++++++++- .../ethernet/microsoft/mana/mana_ethtool.c | 30 +++++ include/net/mana/mana.h | 4 + 3 files changed, 143 insertions(+), 3 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +109 -3
@@ -4149,6 +4149,114 @@ void mana_qset_scratch_free(struct mana_port_context *scratch)kvfree (scratch); } +/* Split into kept queues and a retiring tail without changing live ownership. +* Queue i retains EQ i. +*/ +int mana_split_qset (struct mana_port_context *apc, +struct mana_port_context *scratch,unsigned int new_count, +struct mana_qset *out_new,struct mana_qset *out_tail) +{ +unsigned int old_count = apc->num_queues; +struct mana_tx_qp **new_tx, **tail_tx; +struct mana_rxq **new_rx, **tail_rx; +unsigned int tail_count; +bool indir_lost; +unsigned int i; +int err; + +ASSERT_RTNL (); + +if (WARN_ON (new_count ==0 || new_count >= old_count)) +return -EINVAL ; +if (WARN_ON (!apc->tx_qp || !apc->rxqs)) +return -EINVAL ; + + tail_count = old_count - new_count; + +/* Build steering separately so it cannot index beyond the shortened RX +* array. +*/ + scratch->num_queues = new_count; + err =mana_rss_table_alloc (scratch); +if (err) +return err; + +if (mana_rss_table_keep (apc, new_count, &indir_lost)) +memcpy (scratch->indir_table, apc->indir_table, + apc->indir_table_sz *sizeof (*apc->indir_table)); +else +mana_rss_table_init (scratch); + + new_tx = kzalloc_objs(struct mana_tx_qp *, new_count); + new_rx = kzalloc_objs(struct mana_rxq *, new_count); + tail_tx = kzalloc_objs(struct mana_tx_qp *, tail_count); + tail_rx = kzalloc_objs(struct mana_rxq *, tail_count); +if (!new_tx || !new_rx || !tail_tx || !tail_rx) { + err = -ENOMEM ; + goto free_arrays; + } + +for (i =0 ; i < new_count; i++) { + new_tx[i] = apc->tx_qp[i]; + new_rx[i] = apc->rxqs[i]; + } +for (i =0 ; i < tail_count; i++) { + tail_tx[i] = apc->tx_qp[new_count + i]; + tail_rx[i] = apc->rxqs[new_count + i]; + } + + out_new->tx_qp = new_tx; + out_new->rxqs = new_rx; + out_new->indir_table = scratch->indir_table; + out_new->indir_table_sz = scratch->indir_table_sz; + out_new->rxobj_table = scratch->rxobj_table; + out_new->default_rxobj = apc->rxqs[0 ]->rxobj; + out_new->num_queues = new_count; + out_new->rx_queue_size = apc->rx_queue_size; + out_new->tx_queue_size = apc->tx_queue_size; + out_new->priv_flags = apc->priv_flags; + out_new->mtu = apc->configured_mtu; + out_new->bpf_prog = apc->bpf_prog; + out_new->rxfh_indir_lost = indir_lost; + + scratch->indir_table =NULL ; + scratch->rxobj_table =NULL ; + +memset (out_tail,0 ,sizeof (*out_tail)); + out_tail->tx_qp = tail_tx; + out_tail->rxqs = tail_rx; + out_tail->default_rxobj =INVALID_MANA_HANDLE ; + out_tail->num_queues = tail_count; + out_tail->rx_queue_size = apc->rx_queue_size; + out_tail->tx_queue_size = apc->tx_queue_size; + out_tail->priv_flags = apc->priv_flags; + out_tail->mtu = apc->configured_mtu; + out_tail->bpf_prog = apc->bpf_prog; + +return 0 ; + +free_arrays: +kfree (new_tx); +kfree (new_rx); +kfree (tail_tx); +kfree (tail_rx); +mana_cleanup_indir_table (scratch); +return err; +} + +/* Free containers only; the live port still owns the queues. */ +void mana_discard_split (struct mana_qset *newq,struct mana_qset *tailq) +{ +kfree (newq->tx_qp); +kfree (newq->rxqs); +kfree (newq->indir_table); +kfree (newq->rxobj_table); +kfree (tailq->tx_qp); +kfree (tailq->rxqs); +memset (newq,0 ,sizeof (*newq)); +memset (tailq,0 ,sizeof (*tailq)); +} + int mana_alloc_qset(struct mana_port_context *apc, struct mana_port_context *scratch, unsigned int num_queues, unsigned int rx_queue_size, unsigned int tx_queue_size,
@@ -4419,9 +4527,7 @@ int mana_publish_qset(struct mana_port_context *apc, struct mana_qset *newq,if (err) goto rollback; -/* Install XDP and per-RXQ references before steering reaches new -* queues. -*/ +/* Install XDP before steering reaches the incoming RXQs. */ mana_chn_setxdp (apc,mana_xdp_get (apc)); err =mana_config_rss (apc,TRI_STATE_TRUE , true, true);
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +30 -0
@@ -737,6 +737,36 @@ static int mana_set_channels(struct net_device *ndev, goto clear_flag; } +if (new_count < apc->num_queues) { +struct mana_qset tailq; + + err =mana_split_qset (apc, scratch, new_count, &newq, &tailq); +if (err) + goto free_scratch; + + err =mana_publish_qset (apc, &newq, &oldq); +if (err) { +/* Discard containers only; their queues still belong to +* the old set. +*/ +mana_discard_split (&newq, &tailq); + goto free_scratch; + } + +/* Wait for ndo_select_queue() readers of oldq.indir_table. Free +* only containers; the queues belong to the kept set or tail. +*/ +synchronize_net (); + +kfree (oldq.tx_qp); +kfree (oldq.rxqs); +kfree (oldq.indir_table); +kfree (oldq.rxobj_table); + +mana_free_qset (scratch, &tailq); + goto free_scratch; + } + err =mana_alloc_qset (apc, scratch, new_count, apc->rx_queue_size, apc->tx_queue_size, apc->priv_flags, apc->configured_mtu, apc->bpf_prog, &newq);
include/net/mana/mana.h +4 -0
@@ -735,6 +735,10 @@ int mana_alloc_qset(struct mana_port_context *apc, unsigned int rx_queue_size, unsigned int tx_queue_size, u32 priv_flags, int mtu, struct bpf_prog *bpf_prog, struct mana_qset *out); +int mana_split_qset (struct mana_port_context *apc, +struct mana_port_context *scratch,unsigned int new_count, +struct mana_qset *out_new,struct mana_qset *out_tail); +void mana_discard_split (struct mana_qset *newq,struct mana_qset *tailq);int mana_publish_qset (struct mana_port_context *apc,struct mana_qset *newq,struct mana_qset *out_old);void mana_publish_close_if_needed (struct mana_port_context *apc);
[email protected]
AI reviewRe: [PATCH net-next v6 12/13] net: mana: keep the surviving queues when the channel count is reduced
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 6 lines
From: Long Li <[email protected]>
Split the live set into a kept prefix and a retiring tail. Reductions allocate only pointer arrays and steering tables, retaining the kept queues' page pools, buffers, NAPI state and XDP references.
Quoted 6 lines
After publication, wait for TX-selection readers before freeing the old containers, then retire only the tail. Failed publication discards the new containers without freeing shared queues.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
PATCH v6 13/13 net: mana: keep the existing queues when the channel count is raised
In reply to Wei HuFrom: Long Li <[email protected]>
Keep existing queues and allocate only the added tail. Growing N to M now needs M SQ/RQ pairs at peak, rather than N + M.
Track the fresh queues separately for failure cleanup and XDP references. Wait for TX-selection readers before freeing old containers, and clear slots during partial teardown. Full rebuilds now keep the current count.
Advertise in-driver resize recovery after converting the live resize paths. Failed rollback still requires recovery.
--- .../net/ethernet/microsoft/mana/mana_bpf.c | 2 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 209 +++++++++++++++--- .../ethernet/microsoft/mana/mana_ethtool.c | 31 ++- include/net/mana/gdma.h | 8 +- include/net/mana/mana.h | 7 +- 5 files changed, 217 insertions(+), 40 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_bpf.c +1 -1
@@ -216,7 +216,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, goto clear_flag; } - err =mana_alloc_qset (apc, scratch, apc->num_queues, + err =mana_alloc_qset (apc, scratch, apc->rx_queue_size, apc->tx_queue_size, apc->priv_flags, apc->configured_mtu, prog, &newq);
drivers/net/ethernet/microsoft/mana/mana_en.c +181 -28
342 lines not on this page · raw message
drivers/net/ethernet/microsoft/mana/mana_ethtool.c +22 -9
@@ -684,7 +684,7 @@ static int mana_set_channels(struct net_device *ndev,struct mana_port_context *apc =netdev_priv (ndev);unsigned int new_count = channels->combined_count;struct mana_port_context *scratch; -struct mana_qset newq, oldq; +struct mana_qset newq, oldq, freshq;int err;if (new_count <1 || new_count > apc->max_queues) {
@@ -767,19 +767,33 @@ static int mana_set_channels(struct net_device *ndev, goto free_scratch; } - err =mana_alloc_qset (apc, scratch, new_count, apc->rx_queue_size, - apc->tx_queue_size, apc->priv_flags, - apc->configured_mtu, apc->bpf_prog, &newq); + err =mana_grow_qset (apc, scratch, new_count, &newq, &freshq);if (err) goto free_scratch; err =mana_publish_qset (apc, &newq, &oldq);if (err) { -mana_free_qset (scratch, &newq); +/* Free only the new queues, then discard the merged containers. +*/ +mana_free_qset (scratch, &freshq); +mana_discard_grow (&newq); goto free_scratch; } -mana_free_qset (scratch, &oldq); +/* Wait for ndo_select_queue() readers of oldq.indir_table. All queues +* are now live in newq; free only the old and fresh containers. +*/ +synchronize_net (); + +kfree (oldq.tx_qp); +kfree (oldq.rxqs); +kfree (oldq.indir_table); +kfree (oldq.rxobj_table); +kfree (freshq.tx_qp); +kfree (freshq.rxqs); + +/* No retirement runs to publish the new queues' debugfs nodes. */ +mana_qset_debugfs_publish (apc); free_scratch:mana_publish_close_if_needed (apc);
@@ -856,7 +870,7 @@ static int mana_set_ringparam(struct net_device *ndev, goto clear_flag; } - err =mana_alloc_qset (apc, scratch, apc->num_queues, new_rx, new_tx, + err =mana_alloc_qset (apc, scratch, new_rx, new_tx, apc->priv_flags, apc->configured_mtu, apc->bpf_prog, &newq);if (err) {
@@ -876,7 +890,6 @@ static int mana_set_ringparam(struct net_device *ndev,mana_free_qset (scratch, &oldq); free_scratch: -/* Release unpublished queues before closing their shared EQ pool. */ mana_publish_close_if_needed (apc);mana_qset_scratch_free (scratch); clear_flag:
@@ -948,7 +961,7 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags) goto clear_flag; } - err =mana_alloc_qset (apc, scratch, apc->num_queues, apc->rx_queue_size, + err =mana_alloc_qset (apc, scratch, apc->rx_queue_size, apc->tx_queue_size, priv_flags, apc->configured_mtu, apc->bpf_prog, &newq);if (err)
include/net/mana/gdma.h +7 -1
@@ -686,6 +686,11 @@ enum {/* Driver supports non-contiguous queue buffers */ #define GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS BIT(30) +/* Resize failures are handled in-driver; a failed rollback still needs +* recovery. +*/ +#define GDMA_DRV_CAP_FLAG_1_SELF_RECOVERY_ON_QUEUE_RESIZE_FAILURE BIT(31) +#define GDMA_DRV_CAP_FLAGS1 \ (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \ GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -703,7 +708,8 @@ enum {GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT | \GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION | \ - GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS) +GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS | \ + GDMA_DRV_CAP_FLAG_1_SELF_RECOVERY_ON_QUEUE_RESIZE_FAILURE) #define GDMA_DRV_CAP_FLAGS2 0
include/net/mana/mana.h +6 -1
@@ -731,7 +731,7 @@ static inline struct mana_stats_rx *mana_rxq_stats(struct mana_rxq *rxq) }int mana_alloc_qset (struct mana_port_context *apc, -struct mana_port_context *scratch,unsigned int num_queues, +struct mana_port_context *scratch,unsigned int rx_queue_size,unsigned int tx_queue_size,u32 priv_flags,int mtu,struct bpf_prog *bpf_prog,struct mana_qset *out);
@@ -739,10 +739,15 @@ int mana_split_qset(struct mana_port_context *apc, struct mana_port_context *scratch, unsigned int new_count, struct mana_qset *out_new, struct mana_qset *out_tail);void mana_discard_split (struct mana_qset *newq,struct mana_qset *tailq); +int mana_grow_qset (struct mana_port_context *apc, +struct mana_port_context *scratch,unsigned int new_count, +struct mana_qset *out_new,struct mana_qset *out_fresh); +void mana_discard_grow (struct mana_qset *newq);int mana_publish_qset (struct mana_port_context *apc,struct mana_qset *newq,struct mana_qset *out_old);void mana_publish_close_if_needed (struct mana_port_context *apc);void mana_free_qset (struct mana_port_context *scratch,struct mana_qset *qset); +void mana_qset_debugfs_publish (struct mana_port_context *apc);void mana_dim_change (struct mana_cq *cq,bool enable);
[email protected]
AI reviewRe: [PATCH net-next v6 13/13] net: mana: keep the existing queues when the channel count is raised
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 9 lines
From: Long Li <[email protected]>
Keep existing queues and allocate only the added tail. Growing N to M now needs M SQ/RQ pairs at peak, rather than N + M.
Track the fresh queues separately for failure cleanup and XDP references. Wait for TX-selection readers before freeing old containers, and clear slots during partial teardown. Full rebuilds now keep the current count.
Quoted 5 lines
Advertise in-driver resize recovery after converting the live resize paths. Failed rollback still requires recovery.
Signed-off-by Long Li <[email protected]>Signed-off-by Wei Hu <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=13
Simon Horman
reviewerQuoted 15 lines · Wei Hu
I am carrying Long Li's queue-set reconfiguration series forward for this revision. Long remains the author of twelve patches, and Dipayaan Roy remains the author of the detach change. Their authorship and signoffs are retained; I have added my signoff for this revision.
Replace detach/attach reconfiguration with pre-allocation and queue-set replacement. Allocation failure leaves the running configuration intact. Publication failure attempts rollback; a failed rollback closes the port and holds carrier down until a successful reopen.
EQs and statistics belong to the port. Valid user-configured RSS tables survive queue rebuilds. Channel-count changes reuse surviving queues:
reductions retire the tail and increases allocate only the added queues. Ring, MTU, private-flag and XDP layout changes still perform full rebuilds.
Quoted 6 lines
This series does not depend on the pending HWC concurrency/dynamic-depth v6 series linked below. Their CQ-publication changes overlap in
gdma_main.candhw_channel.c; whichever series lands second will need a rebase preserving both table-publication and per-CQ lifetime guarantees. Related HWC series:
https://lore.kernel.org/all/[email protected]/
Hi Wei,
Unfortunately this patch-set did not apply cleanly to net-next, and thus our CI did not run.
Please rebase and repost.
...
--
pw-bot: changes-requested