All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nitin Shetty J <nshettyj@marvell.com>
To: <netdev-bot+sashiko@kernel.org>
Cc: <netdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<gakula@marvell.com>, <sgoutham@marvell.com>,
	<rkannoth@marvell.com>, <sbhatta@marvell.com>,
	<andrew+netdev@lunn.ch>, <davem@davemloft.net>,
	<edumazet@google.com>, <kuba@kernel.org>, <pabeni@redhat.com>,
	<bbhushan2@marvell.com>, <horms@kernel.org>, <hkalra@marvell.com>
Subject: Re: [PATCH net v4] octeontx2-af: Fix rep link state sync and workqueue races
Date: Sun, 27 Sep 2026 22:57:23 +0530	[thread overview]
Message-ID: <arlR+8AuYPUQfk+j@kernel-ep2> (raw)
In-Reply-To: <178996520304.2160803.1095101901851529954@kernel.org>

On 2026-09-21 at 10:03:23, netdev-bot+sashiko@kernel.org (netdev-bot+sashiko@kernel.org) wrote:
> Thank you for your contribution! Sashiko AI review found 9 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 2 · Medium: 6 (1) · Low: 1 (1)
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
> 
> - [High] Converting `rvu_rep_notify_pfvf_state()` into an asynchronous
>   rep_evt_wq item lets a PFVF_STATE notification be delivered to the…
> - [High] The `rvu->rswitch` bookkeeping (`used_entries`, `start_entry`,
>   `entry2pcifunc`) is mutated by the devlink-driven…
> - [Medium] The commit message describes only four changes (move wq init,
>   fix UAF/races, add bounds checking, serialize LBK config) and carries…
> - [Medium] The patch teaches `rvu_rep_install_mcam_rules()` to recognise
>   PF/VFs whose NIXLF is already initialized…
> - [Medium] `rvu_rep_notify_pfvf_state()` no longer sends the PF/VF-state
>   up-message itself; it funnels the event through…
> - [Medium] The representor workqueue allocation was moved out of
>   `rvu_rep_install_mcam_rules()` into the `GET_REP_CNT` mailbox handler,…
> - [Medium] The new teardown guard in `rvu_rep_wq_handler()` (`if
>   (!READ_ONCE(rvu->rep_evt_teardown)) rvu_rep_up_notify(...)`) is a…
> - [Medium] All the new access-control checks introduced by this patch
>   (-EPERM in `rvu_mbox_handler_get_rep_cnt()`/`rvu_rep_get_rep_map()`…
> - [Low] In `rvu_rep_open()`/`rvu_rep_stop()` the patch adds `if
>   (rep->pcifunc & RVU_PFVF_FUNC_MASK) return 0;`, so administratively…
> 
> Pre-existing issues:
> - [Medium] The new `err_disable_lbk` rollback in
>   `rvu_rep_install_mcam_rules()` only clears the TL2 LBK link…
> - [Low] Producer/consumer disagreement on the rep_event pcifunc selector:
>   `rvu_rep_up_notify()` addresses the up-message with `pf =…
> 
> --
> 
> octeontx2-af: Fix rep link state sync and workqueue races
> 
> This moves the representor event workqueue allocation out of
> rvu_rep_install_mcam_rules() and into the GET_REP_CNT mailbox handler,
> adds ownership/bounds checks to the representor mailbox handlers, and
> serializes LBK link configuration under rsrc_lock.  It also converts
> rvu_rep_notify_pfvf_state() from an inline up-mailbox send into a
> queued representor event.
> 
> Fixes: b8fea84a0468 ("octeontx2-pf: Add support to sync link state between representor and VFs")
> Link: https://lore.kernel.org/lkml/aqrInFMnvs4K48+3@kernel-ep2/
> 
> A few questions below, mostly about the pieces of the diff that are not
> described in the changelog and about the lifetime of the queued events.
> 
> > octeontx2-af: Fix rep link state sync and workqueue races
> >
> > Move rep event workqueue init to rvu_mbox_handler_get_rep_cnt(),
> > fix use-after-free and race conditions in rep event handling,
> > add bounds checking, and serialize LBK link configuration.
> 
> [Severity: Medium]
> Could this be split, and could the message describe the behaviour changes
> it does not currently mention?  The four items listed above do not seem to
> cover everything in the diff:
> 
> - rvu_rep_notify_pfvf_state() changes from an inline synchronous up-mbox
>   send into a queued rep_evt_wq item that can now return -EINVAL, -EPERM
>   or -ENOMEM, or be dropped by the worker.  Incidentally, the old code
>   did mutex_lock(&rvu->mbox_lock) while rvu_afpf_mbox_handler() already
>   holds that same non-recursive mutex around
>   __rvu_mbox_handler(mwork, TYPE_AFPF, true), so this conversion also
>   quietly removes a self-deadlock on the AF-PF path.  Should that be
>   called out as its own fix?
> 
> - rvu_rep_up_notify() now sets msg->pcifunc = event->pcifunc and
>   re-targets PFVF_STATE at the representor PF.
> 
> - rvu_rep_install_mcam_rules() now enables LBK links for every PF/VF that
>   already has NIXLF_INITIALIZED set, and rvu_switch_disable() in rep mode
>   now walks all PFs/VFs disabling LBK links.
> 
> - rvu_switch_enable()'s error path now resets rswitch->entry2pcifunc,
>   used_entries and start_entry, which fixes a dangling pointer that came
>   from a different commit than b8fea84a0468.
> 
> With a single Fixes tag covering all of these, the get_rep_cnt response
> overflow, the missing permission checks and the rswitch bookkeeping fix
> cannot be backported separately.  Would separate patches with their own
> Fixes tags work better here?
> 
sure. I will wait for the remaining automated review feedback on v5,
then post a v6 with the split series.

> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
> > index 937b085582b5f..4a4e7e434d4b9 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
> > @@ -3715,12 +3715,29 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> >  
> >  static void rvu_remove(struct pci_dev *pdev)
> >  {
> > +	struct workqueue_struct *rep_wq;
> >  	struct rvu *rvu = pci_get_drvdata(pdev);
> >  
> >  	rvu_dbg_exit(rvu);
> >  	rvu_unregister_dl(rvu);
> > +
> > +	/* Block get_rep_cnt() from allocating a new rep_evt_wq. */
> > +	mutex_lock(&rvu->rsrc_lock);
> > +	WRITE_ONCE(rvu->rep_evt_teardown, true);
> > +	rep_wq = rvu->rep_evt_wq;
> > +	WRITE_ONCE(rvu->rep_evt_wq, NULL);
> > +	mutex_unlock(&rvu->rsrc_lock);
> > +
> >  	rvu_unregister_interrupts(rvu);
> >  	rvu_flr_wq_destroy(rvu);
> > +
> > +	/* Flush both mbox workqueues before destroying rep_wq. */
> > +	flush_workqueue(rvu->afpf_wq_info.mbox_wq);
> > +	if (rvu->afvf_wq_info.mbox_wq)
> > +		flush_workqueue(rvu->afvf_wq_info.mbox_wq);
> > +	if (rep_wq)
> > +		destroy_workqueue(rep_wq);
> > +
> >  	rvu_cgx_exit(rvu);
> >  	rvu_fwdata_exit(rvu);
> >  	rvu_mcs_exit(rvu);
> 
> [ ... ]
> 
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c
> > index a2781e0f504e3..705821fbf011b 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c
> > @@ -44,6 +44,8 @@ static int rvu_rep_up_notify(struct rvu *rvu, struct rep_event *event)
> >  	if (event->event & RVU_EVENT_MAC_ADDR_CHANGE)
> >  		ether_addr_copy(pfvf->mac_addr, event->evt_data.mac);
> >  
> > +	if (event->event & RVU_EVENT_PFVF_STATE)
> > +		pf = rvu_get_pf(rvu->pdev, event->hdr.pcifunc);
> >  	mutex_lock(&rvu->mbox_lock);
> >  	msg = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
> >  	if (!msg) {
> > @@ -53,6 +55,10 @@ static int rvu_rep_up_notify(struct rvu *rvu, struct rep_event *event)
> >  
> >  	msg->hdr.pcifunc = event->pcifunc;
> >  	msg->event = event->event;
> > +	msg->pcifunc = event->pcifunc;
> 
> [Severity: Low]
> This isn't a bug introduced by this patch, but the producer and consumer
> still seem to disagree about the pcifunc selector for the non-PFVF_STATE
> events.  For a VF representee, rvu_rep_up_notify() routes with
> pf = rvu_get_pf(rvu->pdev, event->pcifunc) and stamps
> msg->hdr.pcifunc = event->pcifunc, so the up-message carries VF function
> bits.  On the receiving side the parent PF drops it:
> 
> drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c:otx2_pfaf_mbox_up_handler() {
> 	...
> 	devid = msg->pcifunc & RVU_PFVF_FUNC_MASK;
> 	/* Skip processing VF's messages */
> 	if (!devid)
> 		otx2_process_mbox_msg_up(pf, msg);
> 	...
> }
> 
> and the forwarded copy hits the default case of
> otx2vf_process_mbox_msg_up(), which answers with otx2_reply_invalid_msg()
> and -ENODEV.  Since this patch adds a VF bail-out in rvu_rep_open() and
> rvu_rep_stop() but leaves rvu_rep_change_mtu() and
> rvu_rep_dl_port_fn_hw_addr_set() emitting MTU/MAC events with a VF
> pcifunc, the emit sites are now inconsistent.  Is changing the MTU on a
> VF representor netdev expected to be propagated at all?
> 
Since it is pre-existing issue will take it up in separate patch.

> > +
> > +	if (event->event & RVU_EVENT_PFVF_STATE)
> > +		msg->hdr.pcifunc = event->hdr.pcifunc;
> >  
> >  	memcpy(&msg->evt_data, &event->evt_data, sizeof(struct rep_evt_data));
> >  
> > @@ -87,7 +93,12 @@ static void rvu_rep_wq_handler(struct work_struct *work)
> >  
> >  		event = &qentry->event;
> >  
> > -		rvu_rep_up_notify(rvu, event);
> > +		/* Once teardown has started the AF-PF mbox interrupt may
> > +		 * already be disabled, so sending would just block until
> > +		 * otx2_mbox_wait_for_rsp() times out. Drop the event instead.
> > +		 */
> > +		if (!READ_ONCE(rvu->rep_evt_teardown))
> > +			rvu_rep_up_notify(rvu, event);
> 
> [Severity: Medium]
> Can the worker still hit the stall this comment describes?  The check and
> the send are not atomic with respect to rvu_remove():
> 
> CPU0 rvu_rep_wq_handler()
> 	READ_ONCE(rvu->rep_evt_teardown)	/* false */
> 
> CPU1 rvu_remove()
> 	WRITE_ONCE(rvu->rep_evt_teardown, true);
> 	WRITE_ONCE(rvu->rep_evt_wq, NULL);
> 	rvu_unregister_interrupts(rvu);		/* AF-PF mbox irq gone */
> 
> CPU0 then proceeds into rvu_rep_up_notify(), which does
> 
> 	otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pf);
> 
> with rvu->mbox_lock held, and no response interrupt can be serviced, so
> it waits the full MBOX_RSP_TIMEOUT.  The following destroy_workqueue()
> then waits on that worker, and rvu_afpf_mbox_handler() needs the same
> rvu->mbox_lock.  Would draining rep_evt_wq before
> rvu_unregister_interrupts() avoid this?
> 
will fix this in next patch version.

> >  		kfree(qentry);
> >  	} while (1);
> >  }
> > @@ -95,16 +106,28 @@ static void rvu_rep_wq_handler(struct work_struct *work)
> >  int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req,
> >  				      struct msg_rsp *rsp)
> >  {
> > +	struct workqueue_struct *wq;
> >  	struct rep_evtq_ent *qentry;
> >  
> > -	/* The mailbox dispatcher normalises only the header pcifunc; the
> > -	 * nested struct rep_event::pcifunc body field is sender-controlled
> > -	 * and is later used by rvu_rep_up_notify() to index rvu->pf[] /
> > -	 * rvu->hwvf[].  Reject out-of-range body selectors before queueing.
> > -	 */
> > +	wq = smp_load_acquire(&rvu->rep_evt_wq);
> > +	if (!wq)
> > +		return -EINVAL;
> > +
> > +	/* Only the registered representor PF may send REP_EVENT_NOTIFY. */
> > +	if (req->hdr.pcifunc != rvu->rep_pcifunc)
> > +		return -EPERM;
> 
> [Severity: Medium]
> What does this check authenticate?  rvu->rep_pcifunc is set by whichever
> PF sends GET_REP_CNT first, and the only identity helper is circular:
> 
> drivers/net/ethernet/marvell/octeontx2/af/rvu.h:is_rep_dev() {
> 	if (rvu->rep_pcifunc && rvu->rep_pcifunc == pcifunc)
> 		return true;
> 	...
> }
> 
> Nothing ties rep_pcifunc to the PCI_DEVID_RVU_REP function, so any PF
> that wins the race becomes the representor.  It then learns the whole
> PF/VF map, can rewrite pfvf->mac_addr of any CGX-mapped PF/VF through
> RVU_EVENT_MAC_ADDR_CHANGE in rvu_rep_up_notify(), inject MTU/port-state
> up-messages into other functions' mailboxes, and is treated as the
> representor by the from_rep_dev target selection in
> rvu_mbox_handler_npc_install_flow().  Meanwhile the real representor
> driver's probe fails, because rvu_rep_get_rep_map() returns -EPERM for
> it.  Should the AF validate the caller's device id before accepting the
> registration?
> 
yes. currently it has no identity check beyond "PF, not VF". The Fix
needs a real way to authenticate the caller. will take it up in separate
patch.

> > +
> >  	if (!is_pf_func_valid(rvu, req->pcifunc))
> >  		return -EINVAL;
> >  
> > +	/* Only CGX-mapped PFs are present in the representor map. */
> > +	if (!is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, req->pcifunc)))
> > +		return -EINVAL;
> > +
> > +	if ((req->event & RVU_EVENT_PFVF_STATE) &&
> > +	    rvu_get_pf(rvu->pdev, req->hdr.pcifunc) >= rvu->hw->total_pfs)
> > +		return -EINVAL;
> > +
> >  	qentry = kmalloc_obj(*qentry, GFP_ATOMIC);
> >  	if (!qentry)
> >  		return -ENOMEM;
> > @@ -113,37 +136,23 @@ int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req,
> >  	spin_lock(&rvu->rep_evtq_lock);
> >  	list_add_tail(&qentry->node, &rvu->rep_evtq_head);
> >  	spin_unlock(&rvu->rep_evtq_lock);
> > -	queue_work(rvu->rep_evt_wq, &rvu->rep_evt_work);
> > +	queue_work(wq, &rvu->rep_evt_work);
> >  	return 0;
> >  }
> >  
> >  int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable)
> >  {
> > -	struct rep_event *req;
> > -	int pf;
> > +	struct rep_event req = { 0 };
> > +	struct msg_rsp rsp;
> >  
> >  	if (!is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)))
> >  		return 0;
> >  
> > -	pf = rvu_get_pf(rvu->pdev, rvu->rep_pcifunc);
> > -
> > -	mutex_lock(&rvu->mbox_lock);
> > -	req = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
> > -	if (!req) {
> > -		mutex_unlock(&rvu->mbox_lock);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	req->hdr.pcifunc = rvu->rep_pcifunc;
> > -	req->event |= RVU_EVENT_PFVF_STATE;
> > -	req->pcifunc = pcifunc;
> > -	req->evt_data.vf_state = enable;
> > -
> > -	otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
> > -	otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);
> > -
> > -	mutex_unlock(&rvu->mbox_lock);
> > -	return 0;
> > +	req.hdr.pcifunc = rvu->rep_pcifunc;
> > +	req.event = RVU_EVENT_PFVF_STATE;
> > +	req.pcifunc = pcifunc;
> > +	req.evt_data.vf_state = enable;
> > +	return rvu_mbox_handler_rep_event_notify(rvu, &req, &rsp);
> >  }
> 
> [Severity: Medium]
> Does routing this through the worker make PF/VF state changes wait for a
> mailbox response that may never come?  The old code only did
> otx2_mbox_wait_for_zero() plus otx2_mbox_msg_send_up() and never waited,
> while rvu_rep_up_notify() ends with
> 
> 	otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pf);
> 
> 	mutex_unlock(&rvu->mbox_lock);
> 
> i.e. up to MBOX_RSP_TIMEOUT with rvu->mbox_lock held, and
> rvu_afpf_mbox_handler() takes that same mutex for every AF-PF batch.
> 
> rvu->rep_mode and rvu->rep_pcifunc are only cleared by an explicit
> ESW_CFG message, so if the representor PF disappears abnormally (FLR,
> crash, forced unbind, guest reset of a passed-through PF), every
> representee nix_lf_start_rx/stop_rx/teardown still enqueues an event, and
> each one is retried for the full timeout.  rvu_rep_wq_handler() only
> skips the send when rvu->rep_evt_teardown is set, and that happens
> exclusively in rvu_remove().  Should the AF stop treating a gone
> representor as registered?
> 
i will fix the mutex lock issue in next patch version. i agree the
representor PF disappearing abnormally issue, will take it up in
separate patch.

> [Severity: High]
> Can this asynchronous handoff outlive the representor netdevs?  Delivery
> now happens from the rep worker at an unbounded time after the producing
> mailbox handler returned, and on the NIC side teardown is reachable at
> runtime:
> 
> drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c:otx2_devlink_eswitch_mode_set() {
> 	case DEVLINK_ESWITCH_MODE_LEGACY:
> 		rvu_rep_destroy(pfvf);
> 	...
> }
> 
> drivers/net/ethernet/marvell/octeontx2/nic/rep.c:rvu_rep_destroy() {
> 	...
> 		free_netdev(rep->netdev);
> 		kfree(rep->flow_cfg);
> 	}
> 	kfree(priv->reps);
> }
> 
> priv->reps is not set to NULL and priv->rep_cnt / priv->rep_pf_map[] stay
> intact, and nothing drains rvu->rep_evt_wq at this point:
> rvu_mbox_handler_esw_cfg() only clears rvu->rep_mode, and the worker's
> new guard tests rvu->rep_evt_teardown, which only rvu_remove() sets.  A
> still-queued event therefore reaches rvu_rep_state_evt_handler(), where
> rvu_rep_get_repid() still returns a valid index and the handler reads the
> freed priv->reps array and writes rep->flags through freed memory.  Is
> some flush of the AF representor event queue needed before
> rvu_rep_destroy() frees the reps?
> 
will fix this in next patch version.

> >  
> >  #define RVU_LF_RX_STATS(reg) \
> > @@ -325,6 +334,7 @@ int rvu_rep_install_mcam_rules(struct rvu *rvu)
> >  	u16 start = rswitch->start_entry;
> >  	struct rvu_hwinfo *hw = rvu->hw;
> >  	u16 pcifunc, entry = 0;
> > +	struct rvu_pfvf *pfvf;
> >  	int pf, vf, numvfs;
> >  	int err, nixlf, i;
> >  	u8 rep;
> > @@ -334,19 +344,22 @@ int rvu_rep_install_mcam_rules(struct rvu *rvu)
> >  			continue;
> >  
> >  		pcifunc = rvu_make_pcifunc(rvu->pdev, pf, 0);
> > +		pfvf = rvu_get_pfvf(rvu, pcifunc);
> >  		rvu_get_nix_blkaddr(rvu, pcifunc);
> > +		if (test_bit(NIXLF_INITIALIZED, &pfvf->flags))
> > +			rvu_switch_enable_lbk_link(rvu, pcifunc, true);
> 
> [Severity: Medium]
> Should this path also publish RVU_EVENT_PFVF_STATE for the functions it
> finds already initialized?  The LBK link is enabled here, but
> rvu_rep_notify_pfvf_state() has only three callers
> (rvu_mbox_handler_nix_lf_start_rx(), nix_lf_stop_rx() and
> rvu_nix_lf_teardown()), all gated on rvu->rep_mode already being set.
> 
> So for a PF/VF that was brought up before switchdev mode was enabled, no
> state event is ever generated.  rvu_rep_create() allocates rep_dev with
> flags == 0, rvu_rep_state_evt_handler() is the only writer of
> RVU_REP_VF_INITIALIZED, and rvu_rep_open() starts with
> 
> 	if (!(rep->flags & RVU_REP_VF_INITIALIZED))
> 		return 0;
> 
> so the representor netdev never gets netif_carrier_on() or
> netif_tx_start_all_queues() and its stats stay empty until the
> representee interface is bounced.  Does the initial-state half of the
> link state sync still work in that ordering?
> 
will fix this in next patch version.

> >  		rep = true;
> >  		for (i = 0; i < 2; i++) {
> >  			err = rvu_rep_install_rx_rule(rvu, pcifunc,
> >  						      start + entry, rep);
> >  			if (err)
> > -				return err;
> > +				goto err_disable_lbk;
> 
> [ ... ]
> 
> > +err_disable_lbk:
> > +	/* Undo any LBK links enabled above before the MCAM rule failure.
> > +	 * Disabling a link that was never enabled is a safe no-op.
> > +	 */
> > +	for (pf = 1; pf < hw->total_pfs; pf++) {
> > +		if (!is_pf_cgxmapped(rvu, pf))
> > +			continue;
> > +		pcifunc = rvu_make_pcifunc(rvu->pdev, pf, 0);
> > +		rvu_switch_enable_lbk_link(rvu, pcifunc, false);
> > +		rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
> > +		for (vf = 0; vf < numvfs; vf++) {
> > +			pcifunc = rvu_make_pcifunc(rvu->pdev, pf, vf + 1);
> > +			rvu_switch_enable_lbk_link(rvu, pcifunc, false);
> > +		}
> >  	}
> > -	return 0;
> > +	return err;
> >  }
> 
> [Severity: Medium]
> This is a pre-existing issue, but does this rollback also need to release
> the TX VTAG entries?  Every rvu_rep_install_tx_rule() that already
> succeeded allocated and programmed a NIX TX VTAG definition through
> rvu_rep_tx_vlan_cfg() -> nix_tx_vtag_cfg() -> nix_tx_vtag_alloc():
> 
> drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c:rvu_rep_tx_vlan_cfg() {
> 	err = rvu_mbox_handler_nix_vtag_cfg(rvu, &req, &rsp);
> 	...
> 	*vidx = rsp.vtag0_idx;
> }
> 
> Those entries are not freed by the new err_disable_lbk loop, not by
> npc_delete_flow in rvu_switch_enable()'s uninstall path, and not by the
> rep_mode branch of rvu_switch_disable(), which goes straight to
> free_ents.  With NIX_TX_VTAG_DEF_MAX at 0x400 and two entries per
> representee per enable, repeated eswitch mode toggles (or repeated failed
> enables) would eventually return NIX_AF_ERR_TX_VTAG_NOSPC until the
> representee NIX LFs are freed.  Would freeing them alongside the LBK
> rollback be reasonable?
> 
Since it is pre-existing issue will fix it in separate patch.

> [ ... ]
> 
> > @@ -443,35 +466,111 @@ int rvu_mbox_handler_esw_cfg(struct rvu *rvu, struct esw_cfg_req *req,
> 
> [ ... ]
> 
> > +	/* Only a PF can register as the representor, not a VF. */
> > +	if (req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) {
> > +		ret = -EPERM;
> > +		goto unlock;
> > +	}
> 
> [ ... ]
> 
> > +	/* Initialize the wq for handling REP events */
> > +	spin_lock_init(&rvu->rep_evtq_lock);
> > +	INIT_LIST_HEAD(&rvu->rep_evtq_head);
> > +	INIT_WORK(&rvu->rep_evt_work, rvu_rep_wq_handler);
> > +	wq = alloc_workqueue("rep_evt_wq", WQ_UNBOUND, 0);
> > +	if (!wq) {
> > +		dev_err(rvu->dev, "REP workqueue allocation failed\n");
> > +		devm_kfree(rvu->dev, map);
> > +		ret = -ENOMEM;
> > +		goto unlock;
> > +	}
> 
> [Severity: Medium]
> What happens to this workqueue if rvu_probe() fails after
> rvu_register_interrupts() has enabled the AF-PF mailbox interrupts?  A PF
> sending GET_REP_CNT in that window allocates and publishes rep_evt_wq
> here, but the probe unwind
> 
> 	err_dl:
> 		rvu_unregister_dl(rvu);
> 	err_irq:
> 		rvu_unregister_interrupts(rvu);
> 	err_flr:
> 		rvu_flr_wq_destroy(rvu);
> 	err_mbox:
> 		rvu_mbox_destroy(&rvu->afpf_wq_info);
> 	...
> 		devm_kfree(dev, rvu);
> 
> never drains or destroys it, so the workqueue is leaked.  Worse,
> rvu->rep_evt_work, rvu->rep_evtq_head and rvu->rep_evtq_lock all live
> inside the rvu structure that devm_kfree() releases, so a REP_EVENT_NOTIFY
> queued in the same window would run the worker against freed memory.  The
> teardown added by this patch only exists in rvu_remove(), which is not
> called for a failed probe.
> 
will fix this in next patch version.

> > +
> > +	rvu->rep_cnt = cnt;
> > +	rsp->rep_cnt = cnt;
> > +	rvu->rep2pfvf_map = map;
> > +	rvu->rep_pcifunc = req->hdr.pcifunc;
> > +
> > +	/* Pairs with smp_load_acquire() in rvu_mbox_handler_rep_event_notify()
> > +	 * to publish the above initialization before wq becomes visible.
> > +	 */
> > +	smp_store_release(&rvu->rep_evt_wq, wq);
> > +unlock:
> > +	mutex_unlock(&rvu->rsrc_lock);
> > +	return ret;
> >  }
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> > index 49ce38685a7e6..92719399a953f 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
> > @@ -203,10 +210,16 @@ void rvu_switch_enable(struct rvu *rvu)
> >  	return;
> >  
> >  uninstall_rules:
> > +	if (rvu->rep_mode && rvu->rep_pcifunc)
> > +		rvu_switch_enable_lbk_link(rvu, rvu->rep_pcifunc, false);
> > +
> >  	uninstall_req.start = rswitch->start_entry;
> >  	uninstall_req.end =  rswitch->start_entry + rswitch->used_entries - 1;
> >  	rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
> >  	kfree(rswitch->entry2pcifunc);
> > +	rswitch->entry2pcifunc = NULL;
> > +	rswitch->used_entries = 0;
> > +	rswitch->start_entry = 0;
> 
> [Severity: High]
> Can this order of stores turn the existing unlocked access into a NULL
> dereference?  entry2pcifunc is cleared before used_entries, and the
> readers run from the mailbox workqueues with no lock in common with the
> devlink path:
> 
> drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c:rvu_rep_update_rules() {
> 	u32 max = rswitch->used_entries;
> 	...
> 	if (!rswitch->used_entries)
> 		return;
> 	...
> 	for (entry = 0; entry < max; entry++) {
> 		if (rswitch->entry2pcifunc[entry] == pcifunc)
> 	...
> }
> 
> CPU0 rvu_devlink_eswitch_mode_set() -> rvu_switch_enable()
> 	kfree(rswitch->entry2pcifunc);
> 	rswitch->entry2pcifunc = NULL;
> 	rswitch->used_entries = 0;
> 
> CPU1 rvu_mbox_handler_nix_lf_start_rx() -> rvu_switch_update_rules()
> 	-> rvu_rep_update_rules()	/* used_entries still non-zero */
> 	rswitch->entry2pcifunc[entry]	/* NULL deref */
> 
> rswitch->switch_lock is only taken inside
> rvu_mbox_handler_npc_install_flow(), not by these readers or writers.
> Ordering the stores the other way (as rvu_switch_disable() does) still
> leaves a window, so would real serialization of the rswitch bookkeeping
> be needed here?
> 
will fix this in next patch version.

> >  free_entries:
> >  	free_req.all = 1;
> >  	rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
> 
> [ ... ]
> 
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> > index 0f5d5642d3f7a..ef47e7e219016 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> > @@ -459,6 +465,9 @@ static int rvu_rep_open(struct net_device *dev)
> >  	netif_carrier_on(dev);
> >  	netif_tx_start_all_queues(dev);
> >  
> > +	if (rep->pcifunc & RVU_PFVF_FUNC_MASK)
> > +		return 0;
> > +
> 
> [Severity: Low]
> This bail-out (and the identical one in rvu_rep_stop()) stops VF
> representors from emitting RVU_EVENT_PORT_STATE at all.  As far as I can
> tell nothing consumed those events before either: the parent PF skips
> up-messages whose pcifunc has function bits set in
> otx2_pfaf_mbox_up_handler(), and otx2vf_process_mbox_msg_up() only
> implements MBOX_MSG_CGX_LINK_EVENT and replies with -ENODEV for
> REP_EVENT_UP_NOTIFY.  Is the intent to remove a send that never had a
> receiver?  If so, could the changelog say so, since the subject mentions
> fixing rep link state sync?
>
yes, the guard just stops the message that never had a receiver.
Will call this out explicitly in the changelog on the next version.

> >  	evt.event = RVU_EVENT_PORT_STATE;
> >  	evt.evt_data.port_state = 1;
> >  	evt.pcifunc = rep->pcifunc;
> 
> [ ... ]
> 
> -- 
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260917042057.1627523-1-nshettyj%40marvell.com
> 

      reply	other threads:[~2026-09-27 18:07 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-17  4:20 [PATCH net v4] octeontx2-af: Fix rep link state sync and workqueue races nshettyj
2026-09-21  4:33 ` netdev-bot+sashiko
2026-09-27 17:27   ` Nitin Shetty J [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=arlR+8AuYPUQfk+j@kernel-ep2 \
    --to=nshettyj@marvell.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bbhushan2@marvell.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gakula@marvell.com \
    --cc=hkalra@marvell.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=rkannoth@marvell.com \
    --cc=sbhatta@marvell.com \
    --cc=sgoutham@marvell.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.