unsigned long flags;
 
+       /*
+        * This protects access to the child_intfs list.
+        * To READ from child_intfs the RTNL or vlan_rwsem read side must be
+        * held.  To WRITE RTNL and the vlan_rwsem write side must be held (in
+        * that order) This lock exists because we have a few contexts where
+        * we need the child_intfs, but do not want to grab the RTNL.
+        */
        struct rw_semaphore vlan_rwsem;
        struct mutex mcast_mutex;
 
 
 
 static void ipoib_ndo_uninit(struct net_device *dev)
 {
-       struct ipoib_dev_priv *priv = ipoib_priv(dev), *cpriv, *tcpriv;
-       LIST_HEAD(head);
+       struct ipoib_dev_priv *priv = ipoib_priv(dev);
 
        ASSERT_RTNL();
 
-       /* Delete any child interfaces first */
-       list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
-               /* Stop GC on child */
-               cancel_delayed_work_sync(&cpriv->neigh_reap_task);
-               unregister_netdevice_queue(cpriv->dev, &head);
-       }
-       unregister_netdevice_many(&head);
+       /*
+        * ipoib_remove_one guarantees the children are removed before the
+        * parent, and that is the only place where a parent can be removed.
+        */
+       WARN_ON(!list_empty(&priv->child_intfs));
 
        ipoib_neigh_hash_uninit(dev);
 
 
 static void ipoib_remove_one(struct ib_device *device, void *client_data)
 {
-       struct ipoib_dev_priv *priv, *tmp;
+       struct ipoib_dev_priv *priv, *tmp, *cpriv, *tcpriv;
        struct list_head *dev_list = client_data;
 
        if (!dev_list)
                return;
 
        list_for_each_entry_safe(priv, tmp, dev_list, list) {
+               LIST_HEAD(head);
                ipoib_parent_unregister_pre(priv->dev);
 
-               unregister_netdev(priv->dev);
+               rtnl_lock();
+
+               list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs,
+                                        list)
+                       unregister_netdevice_queue(cpriv->dev, &head);
+               unregister_netdevice_queue(priv->dev, &head);
+               unregister_netdevice_many(&head);
+
+               rtnl_unlock();
        }
 
        kfree(dev_list);