mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
iavf: wait for PF confirmation before removing VLAN filters
The VLAN filter DELETE path was asymmetric with the ADD path: ADD
waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE
immediately frees the filter struct after sending the DEL message
without waiting for the PF response.
This is problematic because:
- If the PF rejects the DEL, the filter remains in HW but the driver
has already freed the tracking structure, losing sync.
- Race conditions between DEL pending and other operations
(add, reset) cannot be properly resolved if the filter struct
is already gone.
Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric:
REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree
-> PF rejects -> ACTIVE
In iavf_del_vlans(), transition filters from REMOVE to REMOVING
instead of immediately freeing them. The new DEL completion handler
in iavf_virtchnl_completion() frees filters on success or reverts
them to ACTIVE on error.
Update iavf_add_vlan() to handle the REMOVING state: if a DEL is
pending and the user re-adds the same VLAN, queue it for ADD so
it gets re-programmed after the PF processes the DEL.
The !VLAN_FILTERING_ALLOWED early-exit path still frees filters
directly since no PF message is sent in that case.
Also update iavf_del_vlan() to skip filters already in REMOVING
state: DEL has been sent to PF and the completion handler will
free the filter when PF confirms. Without this guard, the sequence
DEL(pending) -> user-del -> second DEL could cause the PF to return
an error for the second DEL (filter already gone), causing the
completion handler to incorrectly revert a deleted filter back to
ACTIVE.
Fixes: 968996c070 ("iavf: Fix VLAN_V2 addition/rejection")
Signed-off-by: Petr Oros <poros@redhat.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
f2ce65b9b9
commit
bbcbe4ed70
|
|
@ -161,6 +161,7 @@ enum iavf_vlan_state_t {
|
|||
IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
|
||||
IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
|
||||
IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
|
||||
IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
|
||||
};
|
||||
|
||||
struct iavf_vlan_filter {
|
||||
|
|
|
|||
|
|
@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
|
|||
adapter->num_vlan_filters++;
|
||||
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
|
||||
} else if (f->state == IAVF_VLAN_REMOVE) {
|
||||
/* Re-add the filter since we cannot tell whether the
|
||||
* pending delete has already been processed by the PF.
|
||||
* A duplicate add is harmless.
|
||||
*/
|
||||
/* DEL not yet sent to PF, cancel it */
|
||||
f->state = IAVF_VLAN_ACTIVE;
|
||||
} else if (f->state == IAVF_VLAN_REMOVING) {
|
||||
/* DEL already sent to PF, re-add after completion */
|
||||
f->state = IAVF_VLAN_ADD;
|
||||
iavf_schedule_aq_request(adapter,
|
||||
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
|
||||
|
|
@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
|
|||
list_del(&f->list);
|
||||
kfree(f);
|
||||
adapter->num_vlan_filters--;
|
||||
} else {
|
||||
} else if (f->state != IAVF_VLAN_REMOVING) {
|
||||
f->state = IAVF_VLAN_REMOVE;
|
||||
iavf_schedule_aq_request(adapter,
|
||||
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
|
||||
}
|
||||
/* If REMOVING, DEL is already sent to PF; completion
|
||||
* handler will free the filter when PF confirms.
|
||||
*/
|
||||
}
|
||||
|
||||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
|
|
|
|||
|
|
@ -948,12 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
|
|||
|
||||
vvfl->vsi_id = adapter->vsi_res->vsi_id;
|
||||
vvfl->num_elements = count;
|
||||
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
|
||||
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
|
||||
if (f->state == IAVF_VLAN_REMOVE) {
|
||||
vvfl->vlan_id[i] = f->vlan.vid;
|
||||
list_del(&f->list);
|
||||
kfree(f);
|
||||
adapter->num_vlan_filters--;
|
||||
f->state = IAVF_VLAN_REMOVING;
|
||||
i++;
|
||||
if (i == count)
|
||||
break;
|
||||
|
|
@ -990,7 +988,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
|
|||
|
||||
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
|
||||
vvfl_v2->num_elements = count;
|
||||
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
|
||||
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
|
||||
if (f->state == IAVF_VLAN_REMOVE) {
|
||||
struct virtchnl_vlan_supported_caps *filtering_support =
|
||||
&adapter->vlan_v2_caps.filtering.filtering_support;
|
||||
|
|
@ -1005,9 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
|
|||
vlan->tci = f->vlan.vid;
|
||||
vlan->tpid = f->vlan.tpid;
|
||||
|
||||
list_del(&f->list);
|
||||
kfree(f);
|
||||
adapter->num_vlan_filters--;
|
||||
f->state = IAVF_VLAN_REMOVING;
|
||||
i++;
|
||||
if (i == count)
|
||||
break;
|
||||
|
|
@ -2370,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
|||
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
|
||||
wake_up(&adapter->vc_waitqueue);
|
||||
break;
|
||||
case VIRTCHNL_OP_DEL_VLAN:
|
||||
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
|
||||
iavf_stat_str(&adapter->hw, v_retval));
|
||||
break;
|
||||
case VIRTCHNL_OP_DEL_ETH_ADDR:
|
||||
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
|
||||
iavf_stat_str(&adapter->hw, v_retval));
|
||||
|
|
@ -2895,6 +2887,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
|||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
}
|
||||
break;
|
||||
case VIRTCHNL_OP_DEL_VLAN:
|
||||
case VIRTCHNL_OP_DEL_VLAN_V2: {
|
||||
struct iavf_vlan_filter *f, *ftmp;
|
||||
|
||||
spin_lock_bh(&adapter->mac_vlan_list_lock);
|
||||
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
|
||||
list) {
|
||||
if (f->state == IAVF_VLAN_REMOVING) {
|
||||
if (v_retval) {
|
||||
/* PF rejected DEL, keep filter */
|
||||
f->state = IAVF_VLAN_ACTIVE;
|
||||
} else {
|
||||
list_del(&f->list);
|
||||
kfree(f);
|
||||
adapter->num_vlan_filters--;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
}
|
||||
break;
|
||||
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
|
||||
/* PF enabled vlan strip on this VF.
|
||||
* Update netdev->features if needed to be in sync with ethtool.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user