datapath: Fix VLAN-related kernel OOPS on XenServer.
authorBen Pfaff <blp@nicira.com>
Thu, 14 May 2009 18:20:10 +0000 (11:20 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 14 May 2009 18:20:10 +0000 (11:20 -0700)
In deleting internal ports (other than the local port) we were failing to
call dp_del_if_hook even though we had called dp_add_if_hook when we added
it.  This prevented the sysfs kobject from being released and caused the
wrong address to be passed to kfree.  The former could cause random
memory corruption; the latter may be benign since the address was still in
the same slab object.

datapath/datapath.c

index 25db7d4f302fd1b6e830c0dc9ebb49eb79b0c254..e3e50308e06442583b8850991d02d0d29429a578 100644 (file)
@@ -454,7 +454,7 @@ int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
        ASSERT_RTNL();
 
 #ifdef SUPPORT_SYSFS
-       if (!is_dp_dev(p->dev) && dp_del_if_hook)
+       if (p->port_no != ODPP_LOCAL && dp_del_if_hook)
                sysfs_remove_link(&p->dp->ifobj, p->dev->name);
 #endif
        dp_ifinfo_notify(RTM_DELLINK, p);
@@ -471,17 +471,17 @@ int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
        synchronize_rcu();
        free_snat(p);
 
-       if (!is_dp_dev(p->dev) && dp_del_if_hook) {
+       if (is_dp_dev(p->dev)) {
+               dp_dev_destroy(p->dev);
+               if (dp_devs) {
+                       struct dp_dev *dp_dev = dp_dev_priv(p->dev);
+                       list_add(&dp_dev->list, dp_devs);
+               }
+       }
+       if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
                dp_del_if_hook(p);
        } else {
                dev_put(p->dev);
-               if (is_dp_dev(p->dev)) {
-                       dp_dev_destroy(p->dev);
-                       if (dp_devs) {
-                               struct dp_dev *dp_dev = dp_dev_priv(p->dev);
-                               list_add(&dp_dev->list, dp_devs);
-                       }
-               }
                kfree(p);
        }