i40evf: protect VLAN filter list
authorMitch Williams <mitch.a.williams@intel.com>
Tue, 31 Mar 2015 07:45:05 +0000 (00:45 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 3 Apr 2015 10:54:31 +0000 (03:54 -0700)
The MAC filter list is protected by a critical task bit, and the VLAN
list should be protected as well. This prevents list corruption if the
watchdog happens to run at the same time as a VLAN filter is being added
or deleted.

Change-ID: Ia4867cebbbb046a1f38012771b288a634ca5882b
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Jim Young <james.m.young@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40evf/i40evf_main.c

index b08efafee1aee4c763fa111289ce4fe1736b5039..46aef2a45cbfa9a9efaa6518a6c982845ea14e30 100644 (file)
@@ -664,13 +664,21 @@ i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan)
 static struct
 i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
 {
-       struct i40evf_vlan_filter *f;
+       struct i40evf_vlan_filter *f = NULL;
+       int count = 50;
+
+       while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+                               &adapter->crit_section)) {
+               udelay(1);
+               if (--count == 0)
+                       goto out;
+       }
 
        f = i40evf_find_vlan(adapter, vlan);
        if (!f) {
                f = kzalloc(sizeof(*f), GFP_ATOMIC);
                if (!f)
-                       return NULL;
+                       goto clearout;
 
                f->vlan = vlan;
 
@@ -680,6 +688,9 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
                adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
        }
 
+clearout:
+       clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+out:
        return f;
 }
 
@@ -691,12 +702,21 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
 static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan)
 {
        struct i40evf_vlan_filter *f;
+       int count = 50;
+
+       while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+                               &adapter->crit_section)) {
+               udelay(1);
+               if (--count == 0)
+                       return;
+       }
 
        f = i40evf_find_vlan(adapter, vlan);
        if (f) {
                f->remove = true;
                adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
        }
+       clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
 }
 
 /**