]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
netfront accelerator: Cleanup vif_state on device removal.
authorKeir Fraser <keir@xensource.com>
Wed, 3 Oct 2007 14:02:54 +0000 (15:02 +0100)
committerKeir Fraser <keir@xensource.com>
Wed, 3 Oct 2007 14:02:54 +0000 (15:02 +0100)
Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
drivers/xen/netfront/accel.c

index 0d82f679bb5e725778681f08995e7812331f4efa..bb45143aa1194b0366a10582b3151ce748c9af92 100644 (file)
@@ -499,6 +499,30 @@ void netfront_accelerator_ready(const char *frontend,
 EXPORT_SYMBOL_GPL(netfront_accelerator_ready);
 
 
+/* 
+ * Remove the hooks from a single vif state.
+ */
+static void 
+accelerator_remove_single_hook(struct netfront_accelerator *accelerator,
+                              struct netfront_accel_vif_state *vif_state)
+{
+       /* Make sure there are no data path operations going on */
+       netif_poll_disable(vif_state->np->netdev);
+       netif_tx_lock_bh(vif_state->np->netdev);
+
+       /* 
+        * Remove the hooks, but leave the vif_state on the
+        * accelerator's list as that signifies this vif is
+        * interested in using that accelerator if it becomes
+        * available again
+        */
+       vif_state->hooks = NULL;
+       
+       netif_tx_unlock_bh(vif_state->np->netdev);
+       netif_poll_enable(vif_state->np->netdev);                      
+}
+
+
 /* 
  * Safely remove the accelerator function hooks from a netfront state.
  */
@@ -513,20 +537,7 @@ static void accelerator_remove_hooks(struct netfront_accelerator *accelerator,
        list_for_each_entry_safe(vif_state, tmp,
                                 &accelerator->vif_states,
                                 link) {
-               /* Make sure there are no data path operations going on */
-               netif_poll_disable(vif_state->np->netdev);
-               netif_tx_lock_bh(vif_state->np->netdev);
-
-               /* 
-                * Remove the hooks, but leave the vif_state on the
-                * accelerator's list as that signifies this vif is
-                * interested in using that accelerator if it becomes
-                * available again
-                */
-               vif_state->hooks = NULL;
-               
-               netif_tx_unlock_bh(vif_state->np->netdev);
-               netif_poll_enable(vif_state->np->netdev);
+               accelerator_remove_single_hook(accelerator, vif_state);
 
                /* 
                 * Remove the reference taken when the vif_state hooks
@@ -623,6 +634,8 @@ int netfront_check_accelerator_queue_busy(struct net_device *dev,
 int netfront_accelerator_call_remove(struct netfront_info *np,
                                     struct xenbus_device *dev)
 {
+       struct netfront_accelerator *accelerator = np->accelerator;
+       struct netfront_accel_vif_state *tmp_vif_state;
        struct netfront_accel_hooks *hooks;
        unsigned flags;
        int rc = 0;
@@ -633,23 +646,53 @@ int netfront_accelerator_call_remove(struct netfront_info *np,
         * call to prevent the accelerator being able to modify the
         * hooks in the middle (by, for example, unloading)
         */ 
-       if (np->accel_vif_state.hooks) {
-               spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); 
-               hooks = np->accel_vif_state.hooks;
-               if (hooks) {
-                       kref_get(&np->accel_vif_state.vif_kref);
-                       spin_unlock_irqrestore
-                               (&np->accelerator->vif_states_lock, flags);
-
-                       rc = np->accel_vif_state.hooks->remove(dev);
+       spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); 
+       hooks = np->accel_vif_state.hooks;
 
-                       kref_put(&np->accel_vif_state.vif_kref,
-                                vif_kref_release);
-               } else {
-                       spin_unlock_irqrestore
-                               (&np->accelerator->vif_states_lock, flags);
+       /*
+        * Remove this vif_state from the accelerator's list 
+        */
+       list_for_each_entry(tmp_vif_state, &accelerator->vif_states, link) {
+               if (tmp_vif_state == &np->accel_vif_state) {
+                       list_del(&np->accel_vif_state.link);
+                       break;
                }
        }
+          
+       if (hooks) {
+               kref_get(&np->accel_vif_state.vif_kref);
+               spin_unlock_irqrestore
+                       (&np->accelerator->vif_states_lock, flags);
+               
+               rc = np->accel_vif_state.hooks->remove(dev);
+               
+               kref_put(&np->accel_vif_state.vif_kref,
+                        vif_kref_release);
+               
+               spin_lock_irqsave(&np->accelerator->vif_states_lock,
+                                 flags);
+
+               /* 
+                * Try and do the opposite of accelerator_probe_new_vif
+                * to ensure there's no state pointing back at the 
+                * netdev 
+                */
+               accelerator_remove_single_hook(accelerator, 
+                                              &np->accel_vif_state);
+                               
+               /* 
+                * Remove the reference taken when the vif_state hooks
+                * were set, must be called without lock held
+                */
+               spin_unlock_irqrestore(&accelerator->vif_states_lock,
+                                      flags);
+               kref_put(&np->accel_vif_state.vif_kref,
+                        vif_kref_release);
+       } else {
+               spin_unlock_irqrestore(&np->accelerator->vif_states_lock,
+                                      flags); 
+       }
+
        return rc;
 }