openvswitch: Move table destroy to dp-rcu callback.
[cascardo/linux.git] / net / openvswitch / datapath.c
index e6d7255..a532a9c 100644 (file)
@@ -59,6 +59,7 @@
 #include "vport-netdev.h"
 
 int ovs_net_id __read_mostly;
+EXPORT_SYMBOL(ovs_net_id);
 
 static struct genl_family dp_packet_genl_family;
 static struct genl_family dp_flow_genl_family;
@@ -130,6 +131,7 @@ int lockdep_ovsl_is_held(void)
        else
                return 1;
 }
+EXPORT_SYMBOL(lockdep_ovsl_is_held);
 #endif
 
 static struct vport *new_vport(const struct vport_parms *);
@@ -185,6 +187,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
 {
        struct datapath *dp = container_of(rcu, struct datapath, rcu);
 
+       ovs_flow_tbl_destroy(&dp->table);
        free_percpu(dp->stats_percpu);
        release_net(ovs_dp_get_net(dp));
        kfree(dp->ports);
@@ -558,7 +561,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
                goto err_flow_free;
 
        err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS],
-                                  &flow->key, 0, &acts);
+                                  &flow->key, &acts);
        if (err)
                goto err_flow_free;
 
@@ -844,7 +847,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_kfree_flow;
 
        error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
-                                    0, &acts);
+                                    &acts);
        if (error) {
                OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
                goto err_kfree_acts;
@@ -951,7 +954,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
                return acts;
 
        ovs_flow_mask_key(&masked_key, key, mask);
-       error = ovs_nla_copy_actions(a, &masked_key, 0, &acts);
+       error = ovs_nla_copy_actions(a, &masked_key, &acts);
        if (error) {
                OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
                kfree(acts);
@@ -1442,7 +1445,7 @@ err_destroy_ports_array:
 err_destroy_percpu:
        free_percpu(dp->stats_percpu);
 err_destroy_table:
-       ovs_flow_tbl_destroy(&dp->table, false);
+       ovs_flow_tbl_destroy(&dp->table);
 err_free_dp:
        release_net(ovs_dp_get_net(dp));
        kfree(dp);
@@ -1474,8 +1477,6 @@ static void __dp_destroy(struct datapath *dp)
        ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
 
        /* RCU destroy the flow table */
-       ovs_flow_tbl_destroy(&dp->table, true);
-
        call_rcu(&dp->rcu, destroy_dp_rcu);
 }
 
@@ -1764,6 +1765,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
                return -ENOMEM;
 
        ovs_lock();
+restart:
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        err = -ENODEV;
        if (!dp)
@@ -1795,8 +1797,11 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        vport = new_vport(&parms);
        err = PTR_ERR(vport);
-       if (IS_ERR(vport))
+       if (IS_ERR(vport)) {
+               if (err == -EAGAIN)
+                       goto restart;
                goto exit_unlock_free;
+       }
 
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_NEW);
@@ -2112,12 +2117,18 @@ static int __init dp_init(void)
        if (err)
                goto error_netns_exit;
 
+       err = ovs_netdev_init();
+       if (err)
+               goto error_unreg_notifier;
+
        err = dp_register_genl();
        if (err < 0)
-               goto error_unreg_notifier;
+               goto error_unreg_netdev;
 
        return 0;
 
+error_unreg_netdev:
+       ovs_netdev_exit();
 error_unreg_notifier:
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
 error_netns_exit:
@@ -2137,6 +2148,7 @@ error:
 static void dp_cleanup(void)
 {
        dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
+       ovs_netdev_exit();
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
        unregister_pernet_device(&ovs_net_ops);
        rcu_barrier();