datapath: Convert patch vport to use call_rcu() on destruction.
authorJesse Gross <jesse@nicira.com>
Sat, 4 Dec 2010 17:43:35 +0000 (09:43 -0800)
committerJesse Gross <jesse@nicira.com>
Fri, 10 Dec 2010 01:43:35 +0000 (17:43 -0800)
Since patch ports are virtual devices, we can potentially have many
of them in a datapath.  Currently we have a call to synchronize_rcu()
each time we destroy one, which can be expensive if we are deleting a
datapath with many ports.  This converts it to use call_rcu() instead,
which allows us to wait for only a single RCU grace period independent
of the number of ports.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/vport-patch.c

index b0ae3a070f6713c38c3761d1a65bc73653bda191..d49f83d364ae900862f7bb47828e9197f294b02b 100644 (file)
@@ -22,6 +22,8 @@ struct device_config {
 };
 
 struct patch_vport {
+       struct rcu_head rcu;
+
        char name[IFNAMSIZ];
 
        /* Protected by RTNL lock. */
@@ -158,19 +160,22 @@ static int patch_modify(struct vport *vport, struct odp_port *port)
        return err;
 }
 
+static void free_port_rcu(struct rcu_head *rcu)
+{
+       struct patch_vport *patch_vport = container_of(rcu,
+                                                     struct patch_vport, rcu);
+
+       kfree(patch_vport->devconf);
+       vport_free(vport_from_priv(patch_vport));
+}
+
 static int patch_destroy(struct vport *vport)
 {
        struct patch_vport *patch_vport = patch_vport_priv(vport);
 
        update_peers(patch_vport->name, NULL);
-       rcu_assign_pointer(patch_vport->peer, NULL);
-
        hlist_del(&patch_vport->hash_node);
-
-       synchronize_rcu();
-
-       kfree(patch_vport->devconf);
-       vport_free(vport);
+       call_rcu(&patch_vport->rcu, free_port_rcu);
 
        return 0;
 }