net: hns3: fix aRFS FD rules leftover after add a user FD rule
authorGuojia Liao <liaoguojia@huawei.com>
Tue, 28 Jul 2020 02:16:51 +0000 (10:16 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 28 Jul 2020 19:54:48 +0000 (12:54 -0700)
When user had created a FD rule, all the aRFS rules should be clear up.
HNS3 process flow as below:
1.get spin lock of fd_ruls_list
2.clear up all aRFS rules
3.release lock
4.get spin lock of fd_ruls_list
5.creat a rules
6.release lock;

There is a short period of time between step 3 and step 4, which would
creatting some new aRFS FD rules if driver was receiving packet.
So refactor the fd_rule_lock to fix it.

Fixes: 441228875706 ("net: hns3: refine the flow director handle")
Signed-off-by: Guojia Liao <liaoguojia@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

index bb4a632..cee84e7 100644 (file)
@@ -5806,9 +5806,9 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
        /* to avoid rule conflict, when user configure rule by ethtool,
         * we need to clear all arfs rules
         */
+       spin_lock_bh(&hdev->fd_rule_lock);
        hclge_clear_arfs_rules(handle);
 
-       spin_lock_bh(&hdev->fd_rule_lock);
        ret = hclge_fd_config_rule(hdev, rule);
 
        spin_unlock_bh(&hdev->fd_rule_lock);
@@ -5851,6 +5851,7 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
        return ret;
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
                                     bool clear_list)
 {
@@ -5863,7 +5864,6 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
        if (!hnae3_dev_fd_supported(hdev))
                return;
 
-       spin_lock_bh(&hdev->fd_rule_lock);
        for_each_set_bit(location, hdev->fd_bmap,
                         hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
                hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
@@ -5880,8 +5880,6 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
                bitmap_zero(hdev->fd_bmap,
                            hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
        }
-
-       spin_unlock_bh(&hdev->fd_rule_lock);
 }
 
 static int hclge_restore_fd_entries(struct hnae3_handle *handle)
@@ -6263,7 +6261,7 @@ static int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
                                      u16 flow_id, struct flow_keys *fkeys)
 {
        struct hclge_vport *vport = hclge_get_vport(handle);
-       struct hclge_fd_rule_tuples new_tuples;
+       struct hclge_fd_rule_tuples new_tuples = {};
        struct hclge_dev *hdev = vport->back;
        struct hclge_fd_rule *rule;
        u16 tmp_queue_id;
@@ -6273,19 +6271,17 @@ static int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
        if (!hnae3_dev_fd_supported(hdev))
                return -EOPNOTSUPP;
 
-       memset(&new_tuples, 0, sizeof(new_tuples));
-       hclge_fd_get_flow_tuples(fkeys, &new_tuples);
-
-       spin_lock_bh(&hdev->fd_rule_lock);
-
        /* when there is already fd rule existed add by user,
         * arfs should not work
         */
+       spin_lock_bh(&hdev->fd_rule_lock);
        if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE) {
                spin_unlock_bh(&hdev->fd_rule_lock);
                return -EOPNOTSUPP;
        }
 
+       hclge_fd_get_flow_tuples(fkeys, &new_tuples);
+
        /* check is there flow director filter existed for this flow,
         * if not, create a new filter for it;
         * if filter exist with different queue id, modify the filter;
@@ -6368,6 +6364,7 @@ static void hclge_rfs_filter_expire(struct hclge_dev *hdev)
 #endif
 }
 
+/* make sure being called after lock up with fd_rule_lock */
 static void hclge_clear_arfs_rules(struct hnae3_handle *handle)
 {
 #ifdef CONFIG_RFS_ACCEL
@@ -6420,10 +6417,14 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
 
        hdev->fd_en = enable;
        clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE;
-       if (!enable)
+
+       if (!enable) {
+               spin_lock_bh(&hdev->fd_rule_lock);
                hclge_del_all_fd_entries(handle, clear);
-       else
+               spin_unlock_bh(&hdev->fd_rule_lock);
+       } else {
                hclge_restore_fd_entries(handle);
+       }
 }
 
 static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
@@ -6886,8 +6887,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
        int i;
 
        set_bit(HCLGE_STATE_DOWN, &hdev->state);
-
+       spin_lock_bh(&hdev->fd_rule_lock);
        hclge_clear_arfs_rules(handle);
+       spin_unlock_bh(&hdev->fd_rule_lock);
 
        /* If it is not PF reset, the firmware will disable the MAC,
         * so it only need to stop phy here.