Netdev List
 help / color / mirror / Atom feed
From: Jacob Keller <jacob.e.keller@intel.com>
To: <netdev-bot+sashiko@kernel.org>, <anthony.l.nguyen@intel.com>
Cc: <davem@davemloft.net>, <kuba@kernel.org>, <pabeni@redhat.com>,
	<edumazet@kernel.org>, <andrew+netdev@lunn.ch>,
	<netdev@vger.kernel.org>, <maciej.machnikowski@intel.com>,
	<przemyslaw.korba@intel.com>, <grzegorz.nitka@intel.com>,
	<sergey.temerkhanov@intel.com>, <arkadiusz.kubalewski@intel.com>,
	<poros@redhat.com>, <richardcochran@gmail.com>,
	<horms@kernel.org>, <pmenzel@molgen.mpg.de>,
	<aleksandr.loktionov@intel.com>, <alexander.nowlin@intel.com>
Subject: Re: [PATCH net v2 02/15] ice: use reference counting and SRCU for PTP port access
Date: Tue, 13 Oct 2026 14:41:39 -0700	[thread overview]
Message-ID: <d116cef5-9c93-4a04-9168-88bc378a5485@intel.com> (raw)
In-Reply-To: <179184691959.434549.12801470720231194166@kernel.org>

On 10/12/2026 4:15 PM, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 1 · Medium: 1 (2) · Low: 0
> 
> 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] In the non-READY branch of ice_ptp_release() (state
>   ICE_PTP_RESETTING or ICE_PTP_ERROR), the PF cancels its work, calls…
> - [Medium] Lost-wakeup hang in ice_ptp_cleanup_pf()
>   (drivers/net/ethernet/intel/ice/ice_ptp.c).
> 
> Pre-existing issues:
> - [Medium] ice_ptp_cleanup_pf() cannot safely run twice, and the non-
>   READY branch of ice_ptp_release() can run it twice.
> - [Medium] ice_ptp_prepare_rebuild_sec() (E825 clock owner, non-PFR
>   reset) calls ice_ptp_prepare_for_reset(peer_pf) while holding only…
> 
> --
> 
> ice: use reference counting and SRCU for PTP port access
> 
> This patch replaces the mutex that protects the ice adapter PTP port list
> with an SRCU-protected list and adds a kref to each ice_ptp_port. Readers
> skip ports whose kref has already dropped to zero.
> 
> ice_ptp_cleanup_pf() unlinks the port, drops the initial reference, waits
> for the count to reach zero with wait_var_event(), and then calls
> synchronize_srcu().
> 
>> diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
>> index fe21cee4f9dee..94a66e9d8c05d 100644
>> --- a/drivers/net/ethernet/intel/ice/ice_ptp.c
>> +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
> 
> [ ... ]
> 
>> @@ -673,20 +676,33 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
>>  	pf->ptp.tx_hwtstamp_good += tstamp_good;
>>  }
>>  
>> +static void ice_ptp_release_port_srcu(struct kref *ref)
>> +{
>> +	wake_up_var(ref);
>> +}
> 
> [Severity: Medium]
> Is a full memory barrier needed before this wake_up_var()?
> 
> The kernel-doc for wake_up_var() in kernel/sched/wait_bit.c says:
> 
>   In order for this to function properly there must be a full memory
>   barrier after the variable is updated ... If the variable was updated
>   by a fully ordered operation such as atomic_dec_and_test() then no
>   extra barrier is required. Otherwise smb_mb() is needed.
> 
> kref_put() goes through refcount_dec_and_test(). That is
> atomic_fetch_sub_release() followed by smp_acquire__after_ctrl_dep() on
> success, so it gives release ordering plus acquire on success. It is not
> fully ordered. __wake_up_bit() then checks waitqueue_active() without
> taking the waitqueue lock.
> 
> Can this interleaving happen on a weakly ordered architecture such as
> arm64?
> 
> CPU1 (last reader, e.g. ice_ptp_tx_tstamp_owner)
> kref_put()
>   refcount_dec_and_test()      /* refs 1 -> 0, release only */
>   ice_ptp_release_port_srcu()
>     wake_up_var(ref)
>       waitqueue_active() sees an empty queue
> 
> CPU2 (ice_ptp_cleanup_pf)
> wait_var_event(ref, !kref_read(ref))
>   adds itself to the waitqueue, set_current_state()
>   kref_read(ref) still returns 1
>   schedule()
> 
> If so, the remover sleeps in TASK_UNINTERRUPTIBLE with no timeout.
> var_wake_function() filters on the key, so an unrelated wakeup on the
> same hashed queue would not wake it.
> 
> Would adding smp_mb__after_atomic() before wake_up_var(), or using a
> fully ordered decrement, avoid this?
> 

I guess this would require the memory barrier.. despite the name
refcount_dec_and_test() doesn't provide the necessary barrier and there
is no equivalent kref_put() call, so I suppose a full memory barrier is
required.

:\

>>  static void ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
>>  {
> 
> [ ... ]
> 
>> @@ -1424,16 +1449,22 @@ static void ice_ptp_reset_phy_timestamping(struct ice_pf *pf)
>>   */
>>  static void ice_ptp_restart_all_phy(struct ice_pf *pf)
>>  {
>> -	struct list_head *entry;
>> +	struct ice_port_list *ports = &pf->adapter->ports;
>> +	struct ice_ptp_port *port;
>> +	int srcu_idx;
>>  
>> -	list_for_each(entry, &pf->adapter->ports.ports) {
>> -		struct ice_ptp_port *port = list_entry(entry,
>> -						       struct ice_ptp_port,
>> -						       list_node);
>> +	srcu_idx = srcu_read_lock(&ports->srcu);
>> +	list_for_each_entry_srcu(port, &ports->list, list_node,
>> +				 srcu_read_lock_held(&ports->srcu)) {
>> +		if (!kref_get_unless_zero(&port->ref))
>> +			continue;
>>  
>>  		if (port->link_up)
>>  			ice_ptp_port_phy_restart(port);
> 
> [Severity: High]
> Can this loop reach a port whose PF has already destroyed its kthread
> worker?
> 
> When the state is ICE_PTP_RESETTING or ICE_PTP_ERROR, ice_ptp_release()
> takes its non-READY branch. That branch tears down the worker and the
> clock before the port is removed from the list:
> 

This was pointed out on the previous patch and we need to re-order
teardown to fix this.

> ice_ptp_release() {
>     ...
> 	if (pf->ptp.state != ICE_PTP_READY) {
> 		if (pf->ptp.kworker) {
> 			kthread_cancel_delayed_work_sync(&pf->ptp.work);
> 			...
> 			kthread_destroy_worker(pf->ptp.kworker);
> 			pf->ptp.kworker = NULL;
> 		}
> 		if (pf->ptp.clock) {
> 			ptp_clock_unregister(pf->ptp.clock);
> 			pf->ptp.clock = NULL;
> 		}
> 		ice_ptp_cleanup_pf(pf);
>     ...
> }
> 
> ice_ptp_cleanup_pf() is the only place that unlinks the port, so
> kref_get_unless_zero() here still succeeds until it runs. port->link_up
> can also still be true, because only ice_ptp_link_change() rewrites it,
> and only in the READY state.
> 
> For ICE_MAC_GENERIC, ice_ptp_port_phy_restart() then does:
> 
> 	kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
> 	...
> 	kthread_queue_delayed_work(pf->ptp.kworker, &ptp_port->ov_work,
> 				   0);
> 
> kthread_destroy_worker() frees the worker but does not clear
> ov_work.work.worker. The cancel would therefore take the lock of a freed
> worker. The queue call would then pass a NULL pf->ptp.kworker.
> 
> The clock owner can hit this through ice_ptp_rebuild_owner(). Because
> ptp_clock_unregister() can sleep, the window is wider than it looks.
> 
> The same window seems to affect ice_ptp_prepare_rebuild_sec(). It calls
> ice_ptp_prepare_for_reset(peer_pf), which runs
> kthread_cancel_delayed_work_sync(&ptp->work) on the peer.
> 
> The READY branch already calls ice_ptp_cleanup_pf() before it cancels
> any work. Should the non-READY branch also call ice_ptp_cleanup_pf()
> before destroying the worker?
> 
> The commit message says the kref "ensures that a PF will have a valid
> lifetime and not be removed until the reference is released". It also
> lists ice_ptp_restart_all_phy() as one of the iterations being fixed.
> 


> 
> [Severity: Medium]
> This is a pre-existing issue, but does anything here serialize the peer's
> ptp->state against the peer's own ice_ptp_release()?
> 
> ice_ptp_prepare_for_reset() checks and sets the peer's state without a
> lock:
> 
> 	if (ptp->state != ICE_PTP_READY)
> 		return;
> 
> 	ptp->state = ICE_PTP_RESETTING;
> 
> 	/* Disable timestamping for both Tx and Rx */
> 	ice_ptp_disable_timestamp_mode(pf);
> 
> 	kthread_cancel_delayed_work_sync(&ptp->work);
> 
> At the same time, ice_ptp_release() on the peer reads this field and
> writes ICE_PTP_UNINIT to it.
> 
> If the owner writes RESETTING after the peer has written UNINIT, the
> peer exits release in a non-READY state. A later ice_ptp_release() would
> then repeat the cleanup.
> 
> In the opposite order, the peer takes the non-READY branch and destroys
> its kworker while the owner is about to cancel work on it. That is the
> same ordering problem described above for ice_ptp_restart_all_phy().
> Calling ice_ptp_cleanup_pf() first in that branch would fix this case
> too.
> 
> The kref and SRCU here protect the port memory and the list linkage. They
> do not protect the PF state machine. The commit message notes that the
> change "focuses solely on the port list".
> 

Yep. This likely needs to be handled as part of the work on the
ctrl_pf/ctrl_ptp.

>> +
>> +		kref_put(&port->ref, ice_ptp_release_port_srcu);
>>  	}
>> +	srcu_read_unlock(&ports->srcu, srcu_idx);
>>  }
> 
> [ ... ]
> 
>> @@ -3110,13 +3157,23 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
>>  
>>  static void ice_ptp_cleanup_pf(struct ice_pf *pf)
>>  {
> 
> [ ... ]
> 
>> +	spin_lock(&ports->lock);
>> +	list_del_rcu(&ptp->port.list_node);
>> +	spin_unlock(&ports->lock);
>> +
>> +	ref = &ptp->port.ref;
>> +	kref_put(ref, ice_ptp_release_port_srcu);
>> +
>> +	wait_var_event(ref, !kref_read(ref));
> 
> [Severity: Medium]
> This isn't a bug introduced by this patch, but what happens if
> ice_ptp_cleanup_pf() runs twice for the same PF?
> 
> The non-READY branch of ice_ptp_release() calls ice_ptp_cleanup_pf() and
> returns without setting ptp.state to ICE_PTP_UNINIT. This sequence seems
> to run the cleanup twice:
> 
> ice_devlink_reinit_down()->ice_unload()->ice_deinit_features()
>   ->ice_ptp_release()
>     (state is ICE_PTP_ERROR or ICE_PTP_RESETTING, cleanup #1)
> 
> ice_devlink_reinit_up() fails before ice_init_features()
>     (ice_ptp_init() never resets the state)
> 
> ice_remove()->ice_unload()->...->ice_ptp_release()
>     (cleanup #2)
> 
> Before this patch, the second list_del() on a poisoned node either
> faulted or, with LIST_HARDENED/DEBUG_LIST, warned and was skipped.
> 
> With this patch, the second kref_put() runs on a kref that is already
> zero. refcount_dec_and_test() warns and saturates the counter without
> calling the release function.
> 
> kref_read() then never returns zero. wait_var_event() would block
> uninterruptibly forever while devl_lock is held. On hardened-list
> kernels, the result changes from a warning to a hang.
> 
> Should the non-READY branch move the state to ICE_PTP_UNINIT, or should
> ice_ptp_cleanup_pf() be made safe to call twice?
> 

I suppose setting to ICE_PTP_UNINIT makes sense. This is the same issue
as reported on the previous patch.

>> +
>> +	synchronize_srcu(&ports->srcu);
>>  }
> 


  reply	other threads:[~2026-10-13 21:48 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08 21:55 [PATCH net v2 00/15][pull request] ice: E82x: timestamp processing logic fixes Tony Nguyen
2026-10-08 21:55 ` [PATCH net v2 01/15] ice: fix removal of PTP timestamp tracker during reset Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 21:31     ` Jacob Keller
2026-10-08 21:55 ` [PATCH net v2 02/15] ice: use reference counting and SRCU for PTP port access Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 21:41     ` Jacob Keller [this message]
2026-10-08 21:56 ` [PATCH net v2 03/15] ice: fix PHY port restart serialization Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 21:43     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 04/15] ice: set in_use only after preparing Tx timestamp index Tony Nguyen
2026-10-08 21:56 ` [PATCH net v2 05/15] ice: call PTP link change only from link events Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 21:58     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 06/15] ice: E822: keep Tx timestamps disabled during offset calibration Tony Nguyen
2026-10-08 21:56 ` [PATCH net v2 07/15] ice: E822: cancel offset verification work during reset preparation Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:07     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 08/15] ice: E825: stop clearing PHY_REG_TX_OFFSET_READY Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:08     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 09/15] ice: E825: clear PHY_REG_TX_MEMORY_STATUS prior to soft reset Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:11     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 10/15] ice: E825: perform a soft reset when starting the PHY timer Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:32     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 11/15] ice: wait for in-flight Tx timestamps before flushing the tracker Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:39     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 12/15] ice: keep Tx timestamp slots tracked until completion or timeout Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:44     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 13/15] ice: skip reading Tx ready bitmap on ports with no timestamps Tony Nguyen
2026-10-08 21:56 ` [PATCH net v2 14/15] ice: don't clear in_use until HW clears ready bitmap Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 22:59     ` Jacob Keller
2026-10-08 21:56 ` [PATCH net v2 15/15] ice: Recalibrate PHY after settime64 on E825-C Tony Nguyen
2026-10-12 23:15   ` netdev-bot+sashiko
2026-10-13 23:04     ` Jacob Keller
2026-10-14  0:59       ` Jacob Keller

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=d116cef5-9c93-4a04-9168-88bc378a5485@intel.com \
    --to=jacob.e.keller@intel.com \
    --cc=aleksandr.loktionov@intel.com \
    --cc=alexander.nowlin@intel.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=anthony.l.nguyen@intel.com \
    --cc=arkadiusz.kubalewski@intel.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=grzegorz.nitka@intel.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=maciej.machnikowski@intel.com \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pmenzel@molgen.mpg.de \
    --cc=poros@redhat.com \
    --cc=przemyslaw.korba@intel.com \
    --cc=richardcochran@gmail.com \
    --cc=sergey.temerkhanov@intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox