datapath: Speed up ioctl fast paths.
authorBen Pfaff <blp@nicira.com>
Mon, 16 Mar 2009 18:37:34 +0000 (11:37 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 16 Mar 2009 18:37:34 +0000 (11:37 -0700)
synchronize_rcu() was causing some common datapath ioctls to take up to
approx. 1 second (!) in some cases, which was killing our performance.
Use call_rcu() instead.

datapath/datapath.c

index e636c8ad0d79ba50f2c86776a76fd36cb979ee87..8b26d5a011f1c5c66b4df6ed6bae5ba261701de0 100644 (file)
@@ -794,8 +794,7 @@ static int set_flow_actions(struct datapath *dp, struct odp_flow __user *ufp)
                goto error_free_actions;
        old_acts = rcu_dereference(flow->sf_acts);
        rcu_assign_pointer(flow->sf_acts, new_acts);
-       synchronize_rcu();      /* XXX expensive! */
-       kfree(old_acts);
+       flow_deferred_free_acts(old_acts);
 
        return 0;
 
@@ -883,9 +882,13 @@ static int add_flow(struct datapath *dp, struct odp_flow __user *ufp)
                /* Replace 'old_flow' by 'flow'. */
                struct sw_flow *old_flow = *rcu_dereference(bucket);
                rcu_assign_pointer(*bucket, flow);
-               synchronize_rcu();      /* XXX expensive! */
+
+               /* XXX These statistics might lose a few packets, since other
+                * CPUs can be using this flow.  We used to synchronize_rcu()
+                * to make sure that we get completely accurate stats, but that
+                * blows our performance, badly. */
                error = put_stats(old_flow, ufp) ? -EFAULT : 0;
-               flow_free(old_flow);
+               flow_deferred_free(old_flow);
        }
 
        return error;
@@ -951,10 +954,14 @@ static int del_or_query_flow(struct datapath *dp,
                error = dp_table_delete(table, flow);
                if (error)
                        goto error;
+
+               /* XXX These statistics might lose a few packets, since other
+                * CPUs can be using this flow.  We used to synchronize_rcu()
+                * to make sure that we get completely accurate stats, but that
+                * blows our performance, badly. */
                dp->n_flows--;
-               synchronize_rcu();      /* XXX expensive! */
                error = answer_query(flow, ufp);
-               flow_free(flow);
+               flow_deferred_free(flow);
        } else {
                error = answer_query(flow, ufp);
        }