On Tue, Mar 25, 2014 at 2:35 PM, Jarno Rajahalme <jrajaha...@nicira.com> wrote: > Move most memory allocations away from the ovs_mutex critical > sections. vport allocations still happen while the lock is taken, as > changing that would require major refactoring. Also, vports are > created very rarely so it should not matter. > > Change ovs_dp_cmd_get() now only takes the rcu_read_lock(), rather > than ovs_lock(), as nothing need to be changed. This was done by > ovs_vport_cmd_get() already. > > Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> > --- > v5: Rebase. > > datapath/datapath.c | 223 > ++++++++++++++++++++++++++------------------------- > 1 file changed, 112 insertions(+), 111 deletions(-) > > diff --git a/datapath/datapath.c b/datapath/datapath.c > index aa3f789..ca18879 100644 > --- a/datapath/datapath.c > +++ b/datapath/datapath.c > @@ -1271,23 +1271,9 @@ error: > return -EMSGSIZE; > } > > -/* Must be called with ovs_mutex. */ > -static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, > - struct genl_info *info, u8 cmd) > +static struct sk_buff *ovs_dp_cmd_alloc_info(struct genl_info *info) > { > - struct sk_buff *skb; > - int retval; > - > - skb = genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL); > - if (!skb) > - return ERR_PTR(-ENOMEM); > - > - retval = ovs_dp_cmd_fill_info(dp, skb, info->snd_portid, > info->snd_seq, 0, cmd); > - if (retval < 0) { > - kfree_skb(skb); > - return ERR_PTR(retval); > - } > - return skb; > + return genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL); > } > > /* Called with rcu_read_lock or ovs_mutex. */ > @@ -1340,12 +1326,14 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct > genl_info *info) > if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID]) > goto err; > > - ovs_lock(); > + reply = ovs_dp_cmd_alloc_info(info); > + if (!reply) > + return -ENOMEM; > > err = -ENOMEM; > dp = kzalloc(sizeof(*dp), GFP_KERNEL); > if (dp == NULL) > - goto err_unlock_ovs; > + goto err_free_reply; > > ovs_dp_set_net(dp, hold_net(sock_net(skb->sk))); > > @@ -1380,6 +1368,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct > genl_info *info) > > ovs_dp_change(dp, a); > > + /* So far only local changes have been made, now need the lock. */ > + ovs_lock(); > + > vport = new_vport(&parms); > if (IS_ERR(vport)) { > err = PTR_ERR(vport); > @@ -1398,10 +1389,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct > genl_info *info) > goto err_destroy_ports_array; > } > > - reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); > - err = PTR_ERR(reply); > - if (IS_ERR(reply)) > - goto err_destroy_local_port; > + err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, > + info->snd_seq, 0, OVS_DP_CMD_NEW); > + BUG_ON(err < 0); > > ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id); > list_add_tail_rcu(&dp->list_node, &ovs_net->dps); > @@ -1411,9 +1401,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct > genl_info *info) > ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); > return 0; > > -err_destroy_local_port: > - ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL)); > err_destroy_ports_array: > + ovs_unlock(); > kfree(dp->ports); > err_destroy_percpu: > free_percpu(dp->stats_percpu); > @@ -1422,8 +1411,8 @@ err_destroy_table: > err_free_dp: > release_net(ovs_dp_get_net(dp)); > kfree(dp); > -err_unlock_ovs: > - ovs_unlock(); > +err_free_reply: > + kfree_skb(reply); > err: > return err; > } > @@ -1461,25 +1450,29 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct > genl_info *info) > struct datapath *dp; > int err; > > + reply = ovs_dp_cmd_alloc_info(info); > + if (!reply) > + return -ENOMEM; > + > ovs_lock(); > dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); > err = PTR_ERR(dp); > if (IS_ERR(dp)) > - goto unlock; > + goto err_unlock_free; > > - reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_DEL); > - err = PTR_ERR(reply); > - if (IS_ERR(reply)) > - goto unlock; > + err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, > + info->snd_seq, 0, OVS_DP_CMD_DEL); > + BUG_ON(err < 0); > > __dp_destroy(dp); > - ovs_unlock(); > > + ovs_unlock(); > ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); > - > return 0; > -unlock: > + > +err_unlock_free: > ovs_unlock(); > + kfree_skb(reply); > return err; > } > > @@ -1489,29 +1482,29 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct > genl_info *info) > struct datapath *dp; > int err; > > + reply = ovs_dp_cmd_alloc_info(info); > + if (!reply) > + return -ENOMEM; > + > ovs_lock(); > dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); > err = PTR_ERR(dp); > if (IS_ERR(dp)) > - goto unlock; > + goto err_unlock_free; > > ovs_dp_change(dp, info->attrs); > > - reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); > - if (IS_ERR(reply)) { > - err = PTR_ERR(reply); > - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, > - ovs_dp_datapath_multicast_group.id, err); > - err = 0; > - goto unlock; > - } > + err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, > + info->snd_seq, 0, OVS_DP_CMD_NEW); > + BUG_ON(err < 0); > > ovs_unlock(); > ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); > - > return 0; > -unlock: > + > +err_unlock_free: > ovs_unlock(); > + kfree_skb(reply); > return err; > } > > @@ -1521,24 +1514,26 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct > genl_info *info) > struct datapath *dp; > int err; > > - ovs_lock(); > + reply = ovs_dp_cmd_alloc_info(info); > + if (!reply) > + return -ENOMEM; > + > + rcu_read_lock(); > dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs); > if (IS_ERR(dp)) { > err = PTR_ERR(dp); > - goto unlock; > - } > - > - reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW); > - if (IS_ERR(reply)) { > - err = PTR_ERR(reply); > - goto unlock; > + goto err_unlock_free; > } > + err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, > + info->snd_seq, 0, OVS_DP_CMD_NEW); > + BUG_ON(err < 0); > + rcu_read_unlock(); > > - ovs_unlock(); > return genlmsg_reply(reply, info); > > -unlock: > - ovs_unlock(); > +err_unlock_free: > + rcu_read_unlock(); > + kfree_skb(reply); > return err; > } > > @@ -1651,7 +1646,12 @@ error: > return err; > } > > -/* Called with ovs_mutex or RCU read lock. */ > +static struct sk_buff *ovs_vport_cmd_alloc(void) > +{ > + return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); > +} > + ovs_vport_cmd_alloc is not clear, may be we can use _info suffix?
> +/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ > struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid, > u32 seq, u8 cmd) > { > @@ -1713,33 +1713,35 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, > struct genl_info *info) > u32 port_no; > int err; > > - err = -EINVAL; > if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] || > !a[OVS_VPORT_ATTR_UPCALL_PID]) > - goto exit; > + return -EINVAL; > + > + port_no = a[OVS_VPORT_ATTR_PORT_NO] > + ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0; > + if (port_no >= DP_MAX_PORTS) > + return -EFBIG; > + > + reply = ovs_vport_cmd_alloc(); > + if (!reply) > + return -ENOMEM; > > ovs_lock(); > dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); > err = -ENODEV; > if (!dp) > - goto exit_unlock; > - > - if (a[OVS_VPORT_ATTR_PORT_NO]) { > - port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]); > - > - err = -EFBIG; > - if (port_no >= DP_MAX_PORTS) > - goto exit_unlock; > + goto exit_unlock_free; > > + if (port_no) { > vport = ovs_vport_ovsl(dp, port_no); > err = -EBUSY; > if (vport) > - goto exit_unlock; > + goto exit_unlock_free; > } else { > for (port_no = 1; ; port_no++) { > if (port_no >= DP_MAX_PORTS) { > err = -EFBIG; > - goto exit_unlock; > + goto exit_unlock_free; > } > vport = ovs_vport_ovsl(dp, port_no); > if (!vport) > @@ -1757,25 +1759,23 @@ 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)) > - goto exit_unlock; > + goto exit_unlock_free; > > err = 0; > if (a[OVS_VPORT_ATTR_STATS]) > ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS])); > > - reply = ovs_vport_cmd_build_info(vport, info->snd_portid, > info->snd_seq, > - OVS_VPORT_CMD_NEW); > - if (IS_ERR(reply)) { > - err = PTR_ERR(reply); > - ovs_dp_detach_port(vport); > - goto exit_unlock; > - } > + err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, > + info->snd_seq, 0, OVS_VPORT_CMD_NEW); > + BUG_ON(err < 0); > + ovs_unlock(); > > ovs_notify(reply, info, &ovs_dp_vport_multicast_group); > + return 0; > > -exit_unlock: > +exit_unlock_free: > ovs_unlock(); > -exit: > + kfree_skb(reply); > return err; > } > > @@ -1786,28 +1786,26 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, > struct genl_info *info) > struct vport *vport; > int err; > > + reply = ovs_vport_cmd_alloc(); > + if (!reply) > + return -ENOMEM; > + > ovs_lock(); > vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); > err = PTR_ERR(vport); > if (IS_ERR(vport)) > - goto exit_unlock; > + goto exit_unlock_free; > > if (a[OVS_VPORT_ATTR_TYPE] && > nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type) { > err = -EINVAL; > - goto exit_unlock; > - } > - > - reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); > - if (!reply) { > - err = -ENOMEM; > - goto exit_unlock; > + goto exit_unlock_free; > } > > if (a[OVS_VPORT_ATTR_OPTIONS]) { > err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]); > if (err) > - goto exit_free; > + goto exit_unlock_free; > } > > if (a[OVS_VPORT_ATTR_STATS]) > @@ -1819,15 +1817,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, > struct genl_info *info) > err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, > info->snd_seq, 0, OVS_VPORT_CMD_NEW); > BUG_ON(err < 0); > - > ovs_unlock(); > + > ovs_notify(reply, info, &ovs_dp_vport_multicast_group); > return 0; > > -exit_free: > - kfree_skb(reply); > -exit_unlock: > +exit_unlock_free: > ovs_unlock(); > + kfree_skb(reply); > return err; > } > > @@ -1838,30 +1835,33 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, > struct genl_info *info) > struct vport *vport; > int err; > > + reply = ovs_vport_cmd_alloc(); > + if (!reply) > + return -ENOMEM; > + > ovs_lock(); > vport = lookup_vport(sock_net(skb->sk), info->userhdr, a); > err = PTR_ERR(vport); > if (IS_ERR(vport)) > - goto exit_unlock; > + goto exit_unlock_free; > > if (vport->port_no == OVSP_LOCAL) { > err = -EINVAL; > - goto exit_unlock; > + goto exit_unlock_free; > } > > - reply = ovs_vport_cmd_build_info(vport, info->snd_portid, > - info->snd_seq, OVS_VPORT_CMD_DEL); > - err = PTR_ERR(reply); > - if (IS_ERR(reply)) > - goto exit_unlock; > - > - err = 0; > + err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, > + info->snd_seq, 0, OVS_VPORT_CMD_DEL); > + BUG_ON(err < 0); > ovs_dp_detach_port(vport); > + ovs_unlock(); > > ovs_notify(reply, info, &ovs_dp_vport_multicast_group); > + return 0; > > -exit_unlock: > +exit_unlock_free: > ovs_unlock(); > + kfree_skb(reply); > return err; > } > > @@ -1873,24 +1873,25 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, > struct genl_info *info) > struct vport *vport; > int err; > > + reply = ovs_vport_cmd_alloc(); > + if (!reply) > + return -ENOMEM; > + > rcu_read_lock(); > vport = lookup_vport(sock_net(skb->sk), ovs_header, a); > err = PTR_ERR(vport); > if (IS_ERR(vport)) > - goto exit_unlock; > - > - reply = ovs_vport_cmd_build_info(vport, info->snd_portid, > - info->snd_seq, OVS_VPORT_CMD_NEW); > - err = PTR_ERR(reply); > - if (IS_ERR(reply)) > - goto exit_unlock; > - > + goto exit_unlock_free; > + err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, > + info->snd_seq, 0, OVS_VPORT_CMD_NEW); > + BUG_ON(err < 0); > rcu_read_unlock(); > > return genlmsg_reply(reply, info); > > -exit_unlock: > +exit_unlock_free: > rcu_read_unlock(); > + kfree_skb(reply); > return err; > } > Acked-by: Pravin B Shelar <pshe...@nicira.com> > -- > 1.7.10.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev