]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: hns3: fix concurrent setting vlan filter issue
authorJian Shen <shenjian15@huawei.com>
Tue, 22 Jul 2025 12:54:20 +0000 (20:54 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 24 Jul 2025 09:27:21 +0000 (11:27 +0200)
The vport->req_vlan_fltr_en may be changed concurrently by function
hclge_sync_vlan_fltr_state() called in periodic work task and
function hclge_enable_vport_vlan_filter() called by user configuration.
It may cause the user configuration inoperative. Fixes it by protect
the vport->req_vlan_fltr by vport_lock.

Fixes: 2ba306627f59 ("net: hns3: add support for modify VLAN filter state")
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Jijie Shao <shaojijie@huawei.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250722125423.1270673-2-shaojijie@huawei.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

index a7de67699a013c1d48c48081d847478f029f11bc..30bdec1acb57e96b2acb2edd5b1afc664e2ebc4b 100644 (file)
@@ -9576,33 +9576,36 @@ static bool hclge_need_enable_vport_vlan_filter(struct hclge_vport *vport)
        return false;
 }
 
-int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en)
+static int __hclge_enable_vport_vlan_filter(struct hclge_vport *vport,
+                                           bool request_en)
 {
-       struct hclge_dev *hdev = vport->back;
        bool need_en;
        int ret;
 
-       mutex_lock(&hdev->vport_lock);
-
-       vport->req_vlan_fltr_en = request_en;
-
        need_en = hclge_need_enable_vport_vlan_filter(vport);
-       if (need_en == vport->cur_vlan_fltr_en) {
-               mutex_unlock(&hdev->vport_lock);
+       if (need_en == vport->cur_vlan_fltr_en)
                return 0;
-       }
 
        ret = hclge_set_vport_vlan_filter(vport, need_en);
-       if (ret) {
-               mutex_unlock(&hdev->vport_lock);
+       if (ret)
                return ret;
-       }
 
        vport->cur_vlan_fltr_en = need_en;
 
+       return 0;
+}
+
+int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en)
+{
+       struct hclge_dev *hdev = vport->back;
+       int ret;
+
+       mutex_lock(&hdev->vport_lock);
+       vport->req_vlan_fltr_en = request_en;
+       ret = __hclge_enable_vport_vlan_filter(vport, request_en);
        mutex_unlock(&hdev->vport_lock);
 
-       return 0;
+       return ret;
 }
 
 static int hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
@@ -10623,16 +10626,19 @@ static void hclge_sync_vlan_fltr_state(struct hclge_dev *hdev)
                                        &vport->state))
                        continue;
 
-               ret = hclge_enable_vport_vlan_filter(vport,
-                                                    vport->req_vlan_fltr_en);
+               mutex_lock(&hdev->vport_lock);
+               ret = __hclge_enable_vport_vlan_filter(vport,
+                                                      vport->req_vlan_fltr_en);
                if (ret) {
                        dev_err(&hdev->pdev->dev,
                                "failed to sync vlan filter state for vport%u, ret = %d\n",
                                vport->vport_id, ret);
                        set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
                                &vport->state);
+                       mutex_unlock(&hdev->vport_lock);
                        return;
                }
+               mutex_unlock(&hdev->vport_lock);
        }
 }