diff options
author | Jesse Gross <jesse@nicira.com> | 2012-11-28 17:01:52 -0500 |
---|---|---|
committer | Jesse Gross <jesse@nicira.com> | 2012-11-28 17:04:34 -0500 |
commit | 92eb1d477145b2e7780b5002e856f70b8c3d74da (patch) | |
tree | dd9856ff7feb1dd9b10485c31c26fe4fa4d344c4 /net/openvswitch | |
parent | 39c7caebc94e851f58b84b54659156dd30522e8e (diff) |
openvswitch: Use RCU callback when detaching netdevices.
Currently, each time a device is detached from an OVS datapath
we call synchronize RCU before freeing associated data structures.
However, if a bridge is deleted (which detaches all ports) when
many devices are connected then there can be a long delay. This
switches to use call_rcu() to group the cost together.
Reported-by: Justin Pettit <jpettit@nicira.com>
Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/vport-netdev.c | 14 | ||||
-rw-r--r-- | net/openvswitch/vport-netdev.h | 3 |
2 files changed, 13 insertions, 4 deletions
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index a9033481fa5e..a9327e2e48ce 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c | |||
@@ -114,6 +114,15 @@ error: | |||
114 | return ERR_PTR(err); | 114 | return ERR_PTR(err); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void free_port_rcu(struct rcu_head *rcu) | ||
118 | { | ||
119 | struct netdev_vport *netdev_vport = container_of(rcu, | ||
120 | struct netdev_vport, rcu); | ||
121 | |||
122 | dev_put(netdev_vport->dev); | ||
123 | ovs_vport_free(vport_from_priv(netdev_vport)); | ||
124 | } | ||
125 | |||
117 | static void netdev_destroy(struct vport *vport) | 126 | static void netdev_destroy(struct vport *vport) |
118 | { | 127 | { |
119 | struct netdev_vport *netdev_vport = netdev_vport_priv(vport); | 128 | struct netdev_vport *netdev_vport = netdev_vport_priv(vport); |
@@ -122,10 +131,7 @@ static void netdev_destroy(struct vport *vport) | |||
122 | netdev_rx_handler_unregister(netdev_vport->dev); | 131 | netdev_rx_handler_unregister(netdev_vport->dev); |
123 | dev_set_promiscuity(netdev_vport->dev, -1); | 132 | dev_set_promiscuity(netdev_vport->dev, -1); |
124 | 133 | ||
125 | synchronize_rcu(); | 134 | call_rcu(&netdev_vport->rcu, free_port_rcu); |
126 | |||
127 | dev_put(netdev_vport->dev); | ||
128 | ovs_vport_free(vport); | ||
129 | } | 135 | } |
130 | 136 | ||
131 | const char *ovs_netdev_get_name(const struct vport *vport) | 137 | const char *ovs_netdev_get_name(const struct vport *vport) |
diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index f7072a25c604..6478079b3417 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h | |||
@@ -20,12 +20,15 @@ | |||
20 | #define VPORT_NETDEV_H 1 | 20 | #define VPORT_NETDEV_H 1 |
21 | 21 | ||
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/rcupdate.h> | ||
23 | 24 | ||
24 | #include "vport.h" | 25 | #include "vport.h" |
25 | 26 | ||
26 | struct vport *ovs_netdev_get_vport(struct net_device *dev); | 27 | struct vport *ovs_netdev_get_vport(struct net_device *dev); |
27 | 28 | ||
28 | struct netdev_vport { | 29 | struct netdev_vport { |
30 | struct rcu_head rcu; | ||
31 | |||
29 | struct net_device *dev; | 32 | struct net_device *dev; |
30 | }; | 33 | }; |
31 | 34 | ||