Re: [ovs-dev] netdev-dpdk: Fix deadlock in destroy_device().
On 08/08/2016 01:02, "Kavanagh, Mark B"wrote: >> >>Minor comment inline. >> >>Acked-by: Ilya Maximets >> > >Other than the comment mentioned by Ilya, this LGTM also - thanks again for >resolving, Daniele. > >Acked-by: mark.b.kavan...@intel.com Thanks for the reviews, I applied this to master > >>On 05.08.2016 23:57, Daniele Di Proietto wrote: >>> netdev_dpdk_vhost_destruct() calls rte_vhost_driver_unregister(), which >>> can trigger the destroy_device() callback. destroy_device() will try to >>> take two mutexes already held by netdev_dpdk_vhost_destruct(), causing a >>> deadlock. >>> >>> This problem can be solved by dropping the mutexes before calling >>> rte_vhost_driver_unregister(). The netdev_dpdk_vhost_destruct() and >>> construct() call are already serialized by netdev_mutex. >>> >>> This commit also makes clear that dev->vhost_id is constant and can be >>> accessed without taking any mutexes in the lifetime of the devices. >>> >>> Fixes: 8d38823bdf8b("netdev-dpdk: fix memory leak") >>> Reported-by: Ilya Maximets >>> Signed-off-by: Daniele Di Proietto >>> --- >>> lib/netdev-dpdk.c | 34 -- >>> 1 file changed, 24 insertions(+), 10 deletions(-) >>> >>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c >>> index f37ec1c..98bff62 100644 >>> --- a/lib/netdev-dpdk.c >>> +++ b/lib/netdev-dpdk.c >>> @@ -355,8 +355,10 @@ struct netdev_dpdk { >>> /* True if vHost device is 'up' and has been reconfigured at least >>> once */ >>> bool vhost_reconfigured; >>> >>> -/* Identifier used to distinguish vhost devices from each other */ >>> -char vhost_id[PATH_MAX]; >>> +/* Identifier used to distinguish vhost devices from each other. It >>> does >>> + * not change during the lifetime of a struct netdev_dpdk. It can be >>> read >>> + * without holding any mutex. */ >>> +const char vhost_id[PATH_MAX]; >>> >>> /* In dpdk_list. */ >>> struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex); >>> @@ -846,7 +848,8 @@ netdev_dpdk_vhost_cuse_construct(struct netdev *netdev) >>> } >>> >>> ovs_mutex_lock(_mutex); >>> -strncpy(dev->vhost_id, netdev->name, sizeof(dev->vhost_id)); >>> +strncpy(CONST_CAST(char *, dev->vhost_id), netdev->name, >>> +sizeof dev->vhost_id); >>> err = vhost_construct_helper(netdev); >>> ovs_mutex_unlock(_mutex); >>> return err; >>> @@ -878,7 +881,7 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev) >>> /* Take the name of the vhost-user port and append it to the location >>> where >>> * the socket is to be created, then register the socket. >>> */ >>> -snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s", >>> +snprintf(CONST_CAST(char *,dev->vhost_id), sizeof(dev->vhost_id), >>> "%s/%s", >> >>Space between arguments of 'CONST_CAST()' and parenthesized operand of >>'sizeof'. Fixed, thanks >> >>> vhost_sock_dir, name); >>> >>> err = rte_vhost_driver_register(dev->vhost_id, flags); >>> @@ -938,6 +941,17 @@ netdev_dpdk_destruct(struct netdev *netdev) >>> ovs_mutex_unlock(_mutex); >>> } >>> >>> +/* rte_vhost_driver_unregister() can call back destroy_device(), which will >>> + * try to acquire 'dpdk_mutex' and possibly 'dev->mutex'. To avoid a >>> + * deadlock, none of the mutexes must be held while calling this function. >>> */ >>> +static int >>> +dpdk_vhost_driver_unregister(struct netdev_dpdk *dev) >>> +OVS_EXCLUDED(dpdk_mutex) >>> +OVS_EXCLUDED(dev->mutex) >>> +{ >>> +return rte_vhost_driver_unregister(dev->vhost_id); >>> +} >>> + >>> static void >>> netdev_dpdk_vhost_destruct(struct netdev *netdev) >>> { >>> @@ -955,12 +969,6 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) >>> dev->vhost_id); >>> } >>> >>> -if (rte_vhost_driver_unregister(dev->vhost_id)) { >>> -VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); >>> -} else { >>> -fatal_signal_remove_file_to_unlink(dev->vhost_id); >>> -} >>> - >>> free(ovsrcu_get_protected(struct ingress_policer *, >>>>ingress_policer)); >>> >>> @@ -970,6 +978,12 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) >>> >>> ovs_mutex_unlock(>mutex); >>> ovs_mutex_unlock(_mutex); >>> + >>> +if (dpdk_vhost_driver_unregister(dev)) { >>> +VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); >>> +} else { >>> +fatal_signal_remove_file_to_unlink(dev->vhost_id); >>> +} >>> } >>> >>> static void >>> >>___ >>dev mailing list >>dev@openvswitch.org >>http://openvswitch.org/mailman/listinfo/dev ___ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev
Re: [ovs-dev] netdev-dpdk: Fix deadlock in destroy_device().
> >Minor comment inline. > >Acked-by: Ilya Maximets> Other than the comment mentioned by Ilya, this LGTM also - thanks again for resolving, Daniele. Acked-by: mark.b.kavan...@intel.com >On 05.08.2016 23:57, Daniele Di Proietto wrote: >> netdev_dpdk_vhost_destruct() calls rte_vhost_driver_unregister(), which >> can trigger the destroy_device() callback. destroy_device() will try to >> take two mutexes already held by netdev_dpdk_vhost_destruct(), causing a >> deadlock. >> >> This problem can be solved by dropping the mutexes before calling >> rte_vhost_driver_unregister(). The netdev_dpdk_vhost_destruct() and >> construct() call are already serialized by netdev_mutex. >> >> This commit also makes clear that dev->vhost_id is constant and can be >> accessed without taking any mutexes in the lifetime of the devices. >> >> Fixes: 8d38823bdf8b("netdev-dpdk: fix memory leak") >> Reported-by: Ilya Maximets >> Signed-off-by: Daniele Di Proietto >> --- >> lib/netdev-dpdk.c | 34 -- >> 1 file changed, 24 insertions(+), 10 deletions(-) >> >> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c >> index f37ec1c..98bff62 100644 >> --- a/lib/netdev-dpdk.c >> +++ b/lib/netdev-dpdk.c >> @@ -355,8 +355,10 @@ struct netdev_dpdk { >> /* True if vHost device is 'up' and has been reconfigured at least once >> */ >> bool vhost_reconfigured; >> >> -/* Identifier used to distinguish vhost devices from each other */ >> -char vhost_id[PATH_MAX]; >> +/* Identifier used to distinguish vhost devices from each other. It >> does >> + * not change during the lifetime of a struct netdev_dpdk. It can be >> read >> + * without holding any mutex. */ >> +const char vhost_id[PATH_MAX]; >> >> /* In dpdk_list. */ >> struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex); >> @@ -846,7 +848,8 @@ netdev_dpdk_vhost_cuse_construct(struct netdev *netdev) >> } >> >> ovs_mutex_lock(_mutex); >> -strncpy(dev->vhost_id, netdev->name, sizeof(dev->vhost_id)); >> +strncpy(CONST_CAST(char *, dev->vhost_id), netdev->name, >> +sizeof dev->vhost_id); >> err = vhost_construct_helper(netdev); >> ovs_mutex_unlock(_mutex); >> return err; >> @@ -878,7 +881,7 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev) >> /* Take the name of the vhost-user port and append it to the location >> where >> * the socket is to be created, then register the socket. >> */ >> -snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s", >> +snprintf(CONST_CAST(char *,dev->vhost_id), sizeof(dev->vhost_id), >> "%s/%s", > >Space between arguments of 'CONST_CAST()' and parenthesized operand of >'sizeof'. > >> vhost_sock_dir, name); >> >> err = rte_vhost_driver_register(dev->vhost_id, flags); >> @@ -938,6 +941,17 @@ netdev_dpdk_destruct(struct netdev *netdev) >> ovs_mutex_unlock(_mutex); >> } >> >> +/* rte_vhost_driver_unregister() can call back destroy_device(), which will >> + * try to acquire 'dpdk_mutex' and possibly 'dev->mutex'. To avoid a >> + * deadlock, none of the mutexes must be held while calling this function. >> */ >> +static int >> +dpdk_vhost_driver_unregister(struct netdev_dpdk *dev) >> +OVS_EXCLUDED(dpdk_mutex) >> +OVS_EXCLUDED(dev->mutex) >> +{ >> +return rte_vhost_driver_unregister(dev->vhost_id); >> +} >> + >> static void >> netdev_dpdk_vhost_destruct(struct netdev *netdev) >> { >> @@ -955,12 +969,6 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) >> dev->vhost_id); >> } >> >> -if (rte_vhost_driver_unregister(dev->vhost_id)) { >> -VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); >> -} else { >> -fatal_signal_remove_file_to_unlink(dev->vhost_id); >> -} >> - >> free(ovsrcu_get_protected(struct ingress_policer *, >>>ingress_policer)); >> >> @@ -970,6 +978,12 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) >> >> ovs_mutex_unlock(>mutex); >> ovs_mutex_unlock(_mutex); >> + >> +if (dpdk_vhost_driver_unregister(dev)) { >> +VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); >> +} else { >> +fatal_signal_remove_file_to_unlink(dev->vhost_id); >> +} >> } >> >> static void >> >___ >dev mailing list >dev@openvswitch.org >http://openvswitch.org/mailman/listinfo/dev ___ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev
Re: [ovs-dev] netdev-dpdk: Fix deadlock in destroy_device().
Minor comment inline. Acked-by: Ilya MaximetsOn 05.08.2016 23:57, Daniele Di Proietto wrote: > netdev_dpdk_vhost_destruct() calls rte_vhost_driver_unregister(), which > can trigger the destroy_device() callback. destroy_device() will try to > take two mutexes already held by netdev_dpdk_vhost_destruct(), causing a > deadlock. > > This problem can be solved by dropping the mutexes before calling > rte_vhost_driver_unregister(). The netdev_dpdk_vhost_destruct() and > construct() call are already serialized by netdev_mutex. > > This commit also makes clear that dev->vhost_id is constant and can be > accessed without taking any mutexes in the lifetime of the devices. > > Fixes: 8d38823bdf8b("netdev-dpdk: fix memory leak") > Reported-by: Ilya Maximets > Signed-off-by: Daniele Di Proietto > --- > lib/netdev-dpdk.c | 34 -- > 1 file changed, 24 insertions(+), 10 deletions(-) > > diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c > index f37ec1c..98bff62 100644 > --- a/lib/netdev-dpdk.c > +++ b/lib/netdev-dpdk.c > @@ -355,8 +355,10 @@ struct netdev_dpdk { > /* True if vHost device is 'up' and has been reconfigured at least once > */ > bool vhost_reconfigured; > > -/* Identifier used to distinguish vhost devices from each other */ > -char vhost_id[PATH_MAX]; > +/* Identifier used to distinguish vhost devices from each other. It does > + * not change during the lifetime of a struct netdev_dpdk. It can be > read > + * without holding any mutex. */ > +const char vhost_id[PATH_MAX]; > > /* In dpdk_list. */ > struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex); > @@ -846,7 +848,8 @@ netdev_dpdk_vhost_cuse_construct(struct netdev *netdev) > } > > ovs_mutex_lock(_mutex); > -strncpy(dev->vhost_id, netdev->name, sizeof(dev->vhost_id)); > +strncpy(CONST_CAST(char *, dev->vhost_id), netdev->name, > +sizeof dev->vhost_id); > err = vhost_construct_helper(netdev); > ovs_mutex_unlock(_mutex); > return err; > @@ -878,7 +881,7 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev) > /* Take the name of the vhost-user port and append it to the location > where > * the socket is to be created, then register the socket. > */ > -snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s", > +snprintf(CONST_CAST(char *,dev->vhost_id), sizeof(dev->vhost_id), > "%s/%s", Space between arguments of 'CONST_CAST()' and parenthesized operand of 'sizeof'. > vhost_sock_dir, name); > > err = rte_vhost_driver_register(dev->vhost_id, flags); > @@ -938,6 +941,17 @@ netdev_dpdk_destruct(struct netdev *netdev) > ovs_mutex_unlock(_mutex); > } > > +/* rte_vhost_driver_unregister() can call back destroy_device(), which will > + * try to acquire 'dpdk_mutex' and possibly 'dev->mutex'. To avoid a > + * deadlock, none of the mutexes must be held while calling this function. */ > +static int > +dpdk_vhost_driver_unregister(struct netdev_dpdk *dev) > +OVS_EXCLUDED(dpdk_mutex) > +OVS_EXCLUDED(dev->mutex) > +{ > +return rte_vhost_driver_unregister(dev->vhost_id); > +} > + > static void > netdev_dpdk_vhost_destruct(struct netdev *netdev) > { > @@ -955,12 +969,6 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) > dev->vhost_id); > } > > -if (rte_vhost_driver_unregister(dev->vhost_id)) { > -VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); > -} else { > -fatal_signal_remove_file_to_unlink(dev->vhost_id); > -} > - > free(ovsrcu_get_protected(struct ingress_policer *, >>ingress_policer)); > > @@ -970,6 +978,12 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) > > ovs_mutex_unlock(>mutex); > ovs_mutex_unlock(_mutex); > + > +if (dpdk_vhost_driver_unregister(dev)) { > +VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id); > +} else { > +fatal_signal_remove_file_to_unlink(dev->vhost_id); > +} > } > > static void > ___ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev