Zero adapter->ctrl_pf when the PF owning it is removed and wait for
pre-existing RCU readers before its storage can be released. Without
this the pointer outlives the control PF, so sibling PFs keep
dereferencing it after it has been torn down.
The preceding patches make this safe to do: readers already resolve the
pointer once per critical section, and the PTP paths already reject a
missing control PF instead of falling back to the caller's own register
space.
Fixes: e2193f9f9ec9 ("ice: enable timesync operation on 2xNAC E825 devices")
Fixes: e800654e85b5 ("ice: Use ice_adapter for PTP shared data instead of
auxdev")
Reported-by: Frederick Lawler <[email protected]>
Closes: https://lore.kernel.org/all/aIKWoZzEPoa1omlw@CMGLRV3/
Signed-off-by: Sergey Temerkhanov <[email protected]>
Reviewed-by: Arkadiusz Kubalewski <[email protected]>
Reviewed-by: Aleksandr Loktionov <[email protected]>
Tested-by: Frederick Lawler <[email protected]>
---
drivers/net/ethernet/intel/ice/ice_ptp.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c
b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 3ee29c0cd726..3ed37bbae161 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -3300,6 +3300,20 @@ static void ice_ptp_setup_adapter(struct ice_pf *pf)
rcu_assign_pointer(pf->adapter->ctrl_pf, pf);
}
+static void ice_ptp_cleanup_adapter(struct ice_pf *pf)
+{
+ guard(rwsem_write)(&pf->adapter->ctrl_pf_lock);
+
+ /* Zero out adapter->ctrl_pf pointer when the ctrl_pf itself
+ * is being removed to prevent any secondary PFs from accessing
+ * it after it is deleted.
+ */
+ if (ice_get_ctrl_pf(pf) == pf) {
+ rcu_assign_pointer(pf->adapter->ctrl_pf, NULL);
+ synchronize_rcu();
+ }
+}
+
static int ice_ptp_setup_pf(struct ice_pf *pf)
{
struct ice_ptp *ptp = &pf->ptp;
@@ -3656,6 +3670,7 @@ void ice_ptp_init(struct ice_pf *pf)
mutex_destroy(&ptp->port.ps_lock);
err_exit:
+ ice_ptp_cleanup_adapter(pf);
/* If we registered a PTP clock, release it */
if (pf->ptp.clock) {
ptp_clock_unregister(ptp->clock);
@@ -3683,6 +3698,7 @@ void ice_ptp_release(struct ice_pf *pf)
if (pf->ptp.state != ICE_PTP_READY) {
mutex_destroy(&pf->ptp.port.ps_lock);
ice_ptp_cleanup_pf(pf);
+ ice_ptp_cleanup_adapter(pf);
if (pf->ptp.clock) {
ptp_clock_unregister(pf->ptp.clock);
pf->ptp.clock = NULL;
@@ -3697,6 +3713,8 @@ void ice_ptp_release(struct ice_pf *pf)
ice_ptp_cleanup_pf(pf);
+ ice_ptp_cleanup_adapter(pf);
+
ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx);
ice_ptp_disable_all_extts(pf);
--
2.53.0