[1/2] net/vhost: fix Vhost setup error path

Message ID 20200218143514.553307-2-maxime.coquelin@redhat.com (mailing list archive)
State Superseded, archived
Delegated to: Maxime Coquelin
Headers
Series Fix Vhost PMD setup |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-testing success Testing PASS
ci/Intel-compilation fail apply issues

Commit Message

Maxime Coquelin Feb. 18, 2020, 2:35 p.m. UTC
  If for some reason vhost_driver_setup() fails, the list
element for the device may be freed without being removed
from the internal list of devices.

This patch fixes all the error paths, by unregistering the
device from Vhost library it has been registered, remove
the device from the list, reset device vring_state pointer
from the global table and only free vring state if it had
been allocated.

Fixes: 3d01b759d267 ("net/vhost: delay driver setup")

Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
 drivers/net/vhost/rte_eth_vhost.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)
  

Comments

David Marchand Feb. 18, 2020, 4:15 p.m. UTC | #1
On Tue, Feb 18, 2020 at 3:35 PM Maxime Coquelin
<maxime.coquelin@redhat.com> wrote:
>
> If for some reason vhost_driver_setup() fails, the list
> element for the device may be freed without being removed
> from the internal list of devices.
>
> This patch fixes all the error paths, by unregistering the
> device from Vhost library it has been registered, remove
> the device from the list, reset device vring_state pointer
> from the global table and only free vring state if it had
> been allocated.
>
> Fixes: 3d01b759d267 ("net/vhost: delay driver setup")
>
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> ---
>  drivers/net/vhost/rte_eth_vhost.c | 21 ++++++++++++++-------
>  1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
> index 90263ae77c..c0056bc8bf 100644
> --- a/drivers/net/vhost/rte_eth_vhost.c
> +++ b/drivers/net/vhost/rte_eth_vhost.c
> @@ -878,12 +878,12 @@ vhost_driver_setup(struct rte_eth_dev *eth_dev)
>
>         list = rte_zmalloc_socket(name, sizeof(*list), 0, numa_node);
>         if (list == NULL)
> -               goto error;
> +               return -1;
>
>         vring_state = rte_zmalloc_socket(name, sizeof(*vring_state),
>                                          0, numa_node);
>         if (vring_state == NULL)
> -               goto error;
> +               goto free_list;
>
>         list->eth_dev = eth_dev;
>         pthread_mutex_lock(&internal_list_lock);
> @@ -894,30 +894,37 @@ vhost_driver_setup(struct rte_eth_dev *eth_dev)
>         vring_states[eth_dev->data->port_id] = vring_state;
>
>         if (rte_vhost_driver_register(internal->iface_name, internal->flags))
> -               goto error;
> +               goto list_remove;
>
>         if (internal->disable_flags) {
>                 if (rte_vhost_driver_disable_features(internal->iface_name,
>                                                       internal->disable_flags))
> -                       goto error;
> +                       goto drv_unreg;
>         }
>
>         if (rte_vhost_driver_callback_register(internal->iface_name,
>                                                &vhost_ops) < 0) {
>                 VHOST_LOG(ERR, "Can't register callbacks\n");
> -               goto error;
> +               goto drv_unreg;
>         }
>
>         if (rte_vhost_driver_start(internal->iface_name) < 0) {
>                 VHOST_LOG(ERR, "Failed to start driver for %s\n",
>                           internal->iface_name);
> -               goto error;
> +               goto drv_unreg;
>         }
>
>         return 0;
>
> -error:
> +drv_unreg:
> +       rte_vhost_driver_unregister(internal->iface_name);
> +list_remove:
> +       pthread_mutex_lock(&internal_list_lock);
> +       TAILQ_REMOVE(&internal_list, list, next);
> +       pthread_mutex_unlock(&internal_list_lock);
> +       vring_states[eth_dev->data->port_id] = NULL;

We allocate/store in vring_states after inserting list in &internal_list.
Probably nitpicking but I would expect the opposite order on cleanup.


>         rte_free(vring_state);
> +free_list:
>         rte_free(list);
>
>         return -1;
> --
> 2.24.1
>

In any case,
Reviewed-by: David Marchand <david.marchand@redhat.com>



--
David Marchand
  
Maxime Coquelin Feb. 18, 2020, 4:25 p.m. UTC | #2
On 2/18/20 5:15 PM, David Marchand wrote:
> On Tue, Feb 18, 2020 at 3:35 PM Maxime Coquelin
> <maxime.coquelin@redhat.com> wrote:
>>
>> If for some reason vhost_driver_setup() fails, the list
>> element for the device may be freed without being removed
>> from the internal list of devices.
>>
>> This patch fixes all the error paths, by unregistering the
>> device from Vhost library it has been registered, remove
>> the device from the list, reset device vring_state pointer
>> from the global table and only free vring state if it had
>> been allocated.
>>
>> Fixes: 3d01b759d267 ("net/vhost: delay driver setup")
>>
>> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
>> ---
>>  drivers/net/vhost/rte_eth_vhost.c | 21 ++++++++++++++-------
>>  1 file changed, 14 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
>> index 90263ae77c..c0056bc8bf 100644
>> --- a/drivers/net/vhost/rte_eth_vhost.c
>> +++ b/drivers/net/vhost/rte_eth_vhost.c
>> @@ -878,12 +878,12 @@ vhost_driver_setup(struct rte_eth_dev *eth_dev)
>>
>>         list = rte_zmalloc_socket(name, sizeof(*list), 0, numa_node);
>>         if (list == NULL)
>> -               goto error;
>> +               return -1;
>>
>>         vring_state = rte_zmalloc_socket(name, sizeof(*vring_state),
>>                                          0, numa_node);
>>         if (vring_state == NULL)
>> -               goto error;
>> +               goto free_list;
>>
>>         list->eth_dev = eth_dev;
>>         pthread_mutex_lock(&internal_list_lock);
>> @@ -894,30 +894,37 @@ vhost_driver_setup(struct rte_eth_dev *eth_dev)
>>         vring_states[eth_dev->data->port_id] = vring_state;
>>
>>         if (rte_vhost_driver_register(internal->iface_name, internal->flags))
>> -               goto error;
>> +               goto list_remove;
>>
>>         if (internal->disable_flags) {
>>                 if (rte_vhost_driver_disable_features(internal->iface_name,
>>                                                       internal->disable_flags))
>> -                       goto error;
>> +                       goto drv_unreg;
>>         }
>>
>>         if (rte_vhost_driver_callback_register(internal->iface_name,
>>                                                &vhost_ops) < 0) {
>>                 VHOST_LOG(ERR, "Can't register callbacks\n");
>> -               goto error;
>> +               goto drv_unreg;
>>         }
>>
>>         if (rte_vhost_driver_start(internal->iface_name) < 0) {
>>                 VHOST_LOG(ERR, "Failed to start driver for %s\n",
>>                           internal->iface_name);
>> -               goto error;
>> +               goto drv_unreg;
>>         }
>>
>>         return 0;
>>
>> -error:
>> +drv_unreg:
>> +       rte_vhost_driver_unregister(internal->iface_name);
>> +list_remove:
>> +       pthread_mutex_lock(&internal_list_lock);
>> +       TAILQ_REMOVE(&internal_list, list, next);
>> +       pthread_mutex_unlock(&internal_list_lock);
>> +       vring_states[eth_dev->data->port_id] = NULL;
> 
> We allocate/store in vring_states after inserting list in &internal_list.
> Probably nitpicking but I would expect the opposite order on cleanup.

No nitpicking, it is a good practice to cleanup in opposite order.
I will post a v2.

> 
>>         rte_free(vring_state);
>> +free_list:
>>         rte_free(list);
>>
>>         return -1;
>> --
>> 2.24.1
>>
> 
> In any case,
> Reviewed-by: David Marchand <david.marchand@redhat.com>
> 

Thanks!
Maxime

> 
> --
> David Marchand
>
  

Patch

diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 90263ae77c..c0056bc8bf 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -878,12 +878,12 @@  vhost_driver_setup(struct rte_eth_dev *eth_dev)
 
 	list = rte_zmalloc_socket(name, sizeof(*list), 0, numa_node);
 	if (list == NULL)
-		goto error;
+		return -1;
 
 	vring_state = rte_zmalloc_socket(name, sizeof(*vring_state),
 					 0, numa_node);
 	if (vring_state == NULL)
-		goto error;
+		goto free_list;
 
 	list->eth_dev = eth_dev;
 	pthread_mutex_lock(&internal_list_lock);
@@ -894,30 +894,37 @@  vhost_driver_setup(struct rte_eth_dev *eth_dev)
 	vring_states[eth_dev->data->port_id] = vring_state;
 
 	if (rte_vhost_driver_register(internal->iface_name, internal->flags))
-		goto error;
+		goto list_remove;
 
 	if (internal->disable_flags) {
 		if (rte_vhost_driver_disable_features(internal->iface_name,
 						      internal->disable_flags))
-			goto error;
+			goto drv_unreg;
 	}
 
 	if (rte_vhost_driver_callback_register(internal->iface_name,
 					       &vhost_ops) < 0) {
 		VHOST_LOG(ERR, "Can't register callbacks\n");
-		goto error;
+		goto drv_unreg;
 	}
 
 	if (rte_vhost_driver_start(internal->iface_name) < 0) {
 		VHOST_LOG(ERR, "Failed to start driver for %s\n",
 			  internal->iface_name);
-		goto error;
+		goto drv_unreg;
 	}
 
 	return 0;
 
-error:
+drv_unreg:
+	rte_vhost_driver_unregister(internal->iface_name);
+list_remove:
+	pthread_mutex_lock(&internal_list_lock);
+	TAILQ_REMOVE(&internal_list, list, next);
+	pthread_mutex_unlock(&internal_list_lock);
+	vring_states[eth_dev->data->port_id] = NULL;
 	rte_free(vring_state);
+free_list:
 	rte_free(list);
 
 	return -1;