err_clean_pf destroys ptp->port.ps_lock before ice_ptp_cleanup_pf()
removes the port from adapter->ports.list and drains the outstanding
references, so while the mutex is being destroyed the port is still
reachable by every other PF on the adapter:

ice_ptp_settime64()
  ice_ptp_restart_all_phy()
    list_for_each_entry_rcu(port, &pf->adapter->ports.list, list_node)
      ice_ptp_port_phy_restart(port)
        mutex_lock(&ptp_port->ps_lock);

ice_ptp_setup_pf() publishes the port before ice_ptp_init_port() runs,
and a link event can set port.link_up at any point after that, so the
walk does not necessarily skip it.

Call ice_ptp_cleanup_pf() first and destroy the mutex once no other PF
can reach the port, matching the order already used by the
ICE_PTP_READY path in ice_ptp_release().

Release the Tx timestamp tracker here as well, so the label frees
everything the port owns. ice_ptp_init_port() allocates it through
ice_ptp_alloc_tx_tracker(), and any failure unwinding through
err_clean_pf after that point would otherwise leak tx->tstamps,
tx->in_use and tx->stale. The tx.init guard is needed because
err_clean_pf is also reached when ice_ptp_init_port() itself fails, and
ice_ptp_alloc_tx_tracker() leaves tx->lock uninitialized in that case.

Fixes: 23a5b9b12de9 ("ice: fix PTP cleanup on driver removal in error path")
Signed-off-by: Sergey Temerkhanov <[email protected]>
Reviewed-by: Aleksandr Loktionov <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_ptp.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c 
b/drivers/net/ethernet/intel/ice/ice_ptp.c
index a735dfa2b03e..5104ccc70d4c 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -3587,8 +3587,14 @@ void ice_ptp_init(struct ice_pf *pf)
        return;
 
 err_clean_pf:
-       mutex_destroy(&ptp->port.ps_lock);
+       /* Unlink the port before tearing down anything it still shares with
+        * the other PFs on the adapter: ice_ptp_restart_all_phy() can be
+        * walking adapter->ports.list and taking ps_lock until this returns.
+        */
        ice_ptp_cleanup_pf(pf);
+       if (ptp->port.tx.init)
+               ice_ptp_release_tx_tracker(pf, &ptp->port.tx);
+       mutex_destroy(&ptp->port.ps_lock);
 err_exit:
        /* If we registered a PTP clock, release it */
        if (pf->ptp.clock) {
-- 
2.53.0

Reply via email to