[ovs-dev] [ovs flow free panic v3] datapath: Fix kernel panic on ovs_flow_free

Jesse Gross jesse at nicira.com
Wed Jan 15 22:27:44 UTC 2014


On Wed, Jan 15, 2014 at 1:06 PM, Andy Zhou <azhou at nicira.com> wrote:
> diff --git a/datapath/datapath.c b/datapath/datapath.c
> index b42fd8b..6ae4ecf 100644
> --- a/datapath/datapath.c
> +++ b/datapath/datapath.c
> @@ -1305,10 +1306,13 @@ static void __dp_destroy(struct datapath *dp)
>         list_del_rcu(&dp->list_node);
>
>         /* OVSP_LOCAL is datapath internal port. We need to make sure that
> -        * all port in datapath are destroyed first before freeing datapath.
> -        */
> +        * all ports in datapath are destroyed first before freeing datapath.
> +        */
>         ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
>
> +       /* Remove all flows while holding ovs_mutex */
> +       ovs_flow_tbl_flush(&dp->table);
> +
>         call_rcu(&dp->rcu, destroy_dp_rcu);

It might be simpler to just destroy the table at this point -
otherwise we flush now and then destroy later in the RCU callback
(even though these operations are essentially the same thing).

> diff --git a/datapath/flow_table.c b/datapath/flow_table.c
> index 4232b82..3ebea78 100644
> --- a/datapath/flow_table.c
> +++ b/datapath/flow_table.c
> -static void __table_instance_destroy(struct table_instance *ti)
> +static void table_instance_free_flows(struct table_instance *ti, bool deferred)

I believe this is only called from table_instance_destroy() - maybe we
should just fold it in? It is somewhat of a discrete block of code but
in this case I think consolidating functions helps readability since
there are so many paths.

> -skip_flows:
> +static void __table_instance_destroy(struct table_instance *ti)
> +{
>         free_buckets(ti->buckets);
>         kfree(ti);
>  }
> @@ -262,7 +262,8 @@ static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
>  {
>         struct table_instance *ti = container_of(rcu, struct table_instance, rcu);
>
> -       __table_instance_destroy(ti);
> +       free_buckets(ti->buckets);
> +       kfree(ti);
>  }

Should we use the helper function here?

This is definitely very intricate code. I think the basic principle
here is that the only operation that should be performed in a deferred
block is freeing memory - nothing more complex should take advantage
of an existing RCU callback, which means that we have a series of
callbacks in parallel instead of a chain. I think this principle is
now respected everywhere.



More information about the dev mailing list