[v1,2/3] net/ring: fix eth_dev device pointer on allocation

Message ID 8aab6e5eb6d8d4769cd4e47a32403c836a13b5ef.1588705694.git.grive@u256.net (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series failsafe & ring fixes |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation fail Compilation issues

Commit Message

Gaëtan Rivet May 5, 2020, 7:10 p.m. UTC
  When a net_ring device is allocated, its device pointer is not set
before calling rte_eth_dev_probing_finish, which is incorrect.

The following:
  commit: 96cb19521147 ("net/ring: use EAL APIs in PMD specific API")
  commit: a6992e961050 ("net/ring: set ethernet device field")

already attempted to fix this issue in 17.08, which was fine at the
time. Adding the hook rte_eth_dev_probing_finish() however created this
bug, as the eth_dev exposed when this hook is executed is expected to be
complete.

Remove the prior attempts to fix the issue in rte_pmd_ring_probe() and
write the pointer properly in do_eth_dev_ring_create().

Cc: stable@dpdk.org
Fixes: fbe90cdd776c ("ethdev: add probing finish function")
Cc: ferruh.yigit@intel.com
Cc: thomas@monjalon.net
Signed-off-by: Gaetan Rivet <grive@u256.net>
---
 drivers/net/ring/rte_eth_ring.c | 36 ++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)
  

Comments

Ferruh Yigit May 6, 2020, 11:48 a.m. UTC | #1
On 5/5/2020 8:10 PM, Gaetan Rivet wrote:
> When a net_ring device is allocated, its device pointer is not set
> before calling rte_eth_dev_probing_finish, which is incorrect.
> 
> The following:
>   commit: 96cb19521147 ("net/ring: use EAL APIs in PMD specific API")
>   commit: a6992e961050 ("net/ring: set ethernet device field")
> 
> already attempted to fix this issue in 17.08, which was fine at the
> time. Adding the hook rte_eth_dev_probing_finish() however created this
> bug, as the eth_dev exposed when this hook is executed is expected to be
> complete.
> 
> Remove the prior attempts to fix the issue in rte_pmd_ring_probe() and
> write the pointer properly in do_eth_dev_ring_create().
> 
> Cc: stable@dpdk.org
> Fixes: fbe90cdd776c ("ethdev: add probing finish function")
> Cc: ferruh.yigit@intel.com
> Cc: thomas@monjalon.net
> Signed-off-by: Gaetan Rivet <grive@u256.net>

<...>

> @@ -325,10 +346,17 @@ do_eth_dev_ring_create(const char *name,
>  	data->kdrv = RTE_KDRV_NONE;
>  	data->numa_node = numa_node;
>  
> -	/* finally assign rx and tx ops */
> +	/* assign rx and tx ops */
>  	eth_dev->rx_pkt_burst = eth_ring_rx;
>  	eth_dev->tx_pkt_burst = eth_ring_tx;
>  
> +	/* finally set the rte_device pointer in eth_dev. */
> +	eth_dev->device = ring_device_from_name(name);
> +	if (eth_dev->device == NULL) {
> +		rte_errno = ENODEV;
> +		goto error;
> +	}
> +
>  	rte_eth_dev_probing_finish(eth_dev);
>  	*eth_dev_p = eth_dev;

Why not move the 'rte_eth_dev_probing_finish()' to the 'rte_pmd_ring_probe()',
below where 'eth_dev->device' set?
  
Gaëtan Rivet May 6, 2020, 12:33 p.m. UTC | #2
On 06/05/20 12:48 +0100, Ferruh Yigit wrote:
> On 5/5/2020 8:10 PM, Gaetan Rivet wrote:
> > When a net_ring device is allocated, its device pointer is not set
> > before calling rte_eth_dev_probing_finish, which is incorrect.
> > 
> > The following:
> >   commit: 96cb19521147 ("net/ring: use EAL APIs in PMD specific API")
> >   commit: a6992e961050 ("net/ring: set ethernet device field")
> > 
> > already attempted to fix this issue in 17.08, which was fine at the
> > time. Adding the hook rte_eth_dev_probing_finish() however created this
> > bug, as the eth_dev exposed when this hook is executed is expected to be
> > complete.
> > 
> > Remove the prior attempts to fix the issue in rte_pmd_ring_probe() and
> > write the pointer properly in do_eth_dev_ring_create().
> > 
> > Cc: stable@dpdk.org
> > Fixes: fbe90cdd776c ("ethdev: add probing finish function")
> > Cc: ferruh.yigit@intel.com
> > Cc: thomas@monjalon.net
> > Signed-off-by: Gaetan Rivet <grive@u256.net>
> 
> <...>
> 
> > @@ -325,10 +346,17 @@ do_eth_dev_ring_create(const char *name,
> >  	data->kdrv = RTE_KDRV_NONE;
> >  	data->numa_node = numa_node;
> >  
> > -	/* finally assign rx and tx ops */
> > +	/* assign rx and tx ops */
> >  	eth_dev->rx_pkt_burst = eth_ring_rx;
> >  	eth_dev->tx_pkt_burst = eth_ring_tx;
> >  
> > +	/* finally set the rte_device pointer in eth_dev. */
> > +	eth_dev->device = ring_device_from_name(name);
> > +	if (eth_dev->device == NULL) {
> > +		rte_errno = ENODEV;
> > +		goto error;
> > +	}
> > +
> >  	rte_eth_dev_probing_finish(eth_dev);
> >  	*eth_dev_p = eth_dev;
> 
> Why not move the 'rte_eth_dev_probing_finish()' to the 'rte_pmd_ring_probe()',
> below where 'eth_dev->device' set?

Hi Ferruh,

Sure it would work. The reason I did it this way is two-fold:

  * I disliked having two places where eth_dev->device was conditionally
    set. It makes it harder to read rte_pmd_ring_probe.

  * I was actually thinking, doing this patch, that we should modify
    rte_eth_dev_allocate() to take an rte_device as parameter, as all
    eth_dev are meant to be backed by an rte_device. Keeping this in
    mind, I meant to move writing the pointer closer to the
    rte_eth_dev_allocate() call.

But you are right that it is needlessly verbose, using
vdev_bus->find_device() to do this stuff. I'm ok with changing it as you
described if you prefer.
  
Ferruh Yigit May 6, 2020, 1:43 p.m. UTC | #3
On 5/6/2020 1:33 PM, Gaëtan Rivet wrote:
> On 06/05/20 12:48 +0100, Ferruh Yigit wrote:
>> On 5/5/2020 8:10 PM, Gaetan Rivet wrote:
>>> When a net_ring device is allocated, its device pointer is not set
>>> before calling rte_eth_dev_probing_finish, which is incorrect.
>>>
>>> The following:
>>>   commit: 96cb19521147 ("net/ring: use EAL APIs in PMD specific API")
>>>   commit: a6992e961050 ("net/ring: set ethernet device field")
>>>
>>> already attempted to fix this issue in 17.08, which was fine at the
>>> time. Adding the hook rte_eth_dev_probing_finish() however created this
>>> bug, as the eth_dev exposed when this hook is executed is expected to be
>>> complete.
>>>
>>> Remove the prior attempts to fix the issue in rte_pmd_ring_probe() and
>>> write the pointer properly in do_eth_dev_ring_create().
>>>
>>> Cc: stable@dpdk.org
>>> Fixes: fbe90cdd776c ("ethdev: add probing finish function")
>>> Cc: ferruh.yigit@intel.com
>>> Cc: thomas@monjalon.net
>>> Signed-off-by: Gaetan Rivet <grive@u256.net>
>>
>> <...>
>>
>>> @@ -325,10 +346,17 @@ do_eth_dev_ring_create(const char *name,
>>>  	data->kdrv = RTE_KDRV_NONE;
>>>  	data->numa_node = numa_node;
>>>  
>>> -	/* finally assign rx and tx ops */
>>> +	/* assign rx and tx ops */
>>>  	eth_dev->rx_pkt_burst = eth_ring_rx;
>>>  	eth_dev->tx_pkt_burst = eth_ring_tx;
>>>  
>>> +	/* finally set the rte_device pointer in eth_dev. */
>>> +	eth_dev->device = ring_device_from_name(name);
>>> +	if (eth_dev->device == NULL) {
>>> +		rte_errno = ENODEV;
>>> +		goto error;
>>> +	}
>>> +
>>>  	rte_eth_dev_probing_finish(eth_dev);
>>>  	*eth_dev_p = eth_dev;
>>
>> Why not move the 'rte_eth_dev_probing_finish()' to the 'rte_pmd_ring_probe()',
>> below where 'eth_dev->device' set?
> 
> Hi Ferruh,
> 
> Sure it would work. The reason I did it this way is two-fold:
> 
>   * I disliked having two places where eth_dev->device was conditionally
>     set. It makes it harder to read rte_pmd_ring_probe.

Agree, what about using a 'goto' to have the assignment and
'rte_eth_dev_probing_finish()' in a single place?
But check seems needed since creation may failed at that stage, if you think
better check can be done on 'ret' instead of 'eth_dev'...

> 
>   * I was actually thinking, doing this patch, that we should modify
>     rte_eth_dev_allocate() to take an rte_device as parameter, as all
>     eth_dev are meant to be backed by an rte_device. Keeping this in
>     mind, I meant to move writing the pointer closer to the
>     rte_eth_dev_allocate() call.

That is a bigger change, may affect many (if not all) PMDs, so I think this can
be considered when that change is available.

And although that change may fix the issues that 'eth_dev->device' is not set,
which we had a few times before, not sure it worth to change all PMDs and ethdev
API directly couple with rte_device, instead of PMD being the glue. Can be
discussed more on its own patch.

> 
> But you are right that it is needlessly verbose, using
> vdev_bus->find_device() to do this stuff. I'm ok with changing it as you
> described if you prefer.
> 

That was the concern, that is too much code to take a value which is already
available a few level up the stack.
  
Gaëtan Rivet May 6, 2020, 5:32 p.m. UTC | #4
On 06/05/20 14:43 +0100, Ferruh Yigit wrote:
> On 5/6/2020 1:33 PM, Gaëtan Rivet wrote:
> > On 06/05/20 12:48 +0100, Ferruh Yigit wrote:
> >> On 5/5/2020 8:10 PM, Gaetan Rivet wrote:
> >>> When a net_ring device is allocated, its device pointer is not set
> >>> before calling rte_eth_dev_probing_finish, which is incorrect.
> >>>
> >>> The following:
> >>>   commit: 96cb19521147 ("net/ring: use EAL APIs in PMD specific API")
> >>>   commit: a6992e961050 ("net/ring: set ethernet device field")
> >>>
> >>> already attempted to fix this issue in 17.08, which was fine at the
> >>> time. Adding the hook rte_eth_dev_probing_finish() however created this
> >>> bug, as the eth_dev exposed when this hook is executed is expected to be
> >>> complete.
> >>>
> >>> Remove the prior attempts to fix the issue in rte_pmd_ring_probe() and
> >>> write the pointer properly in do_eth_dev_ring_create().
> >>>
> >>> Cc: stable@dpdk.org
> >>> Fixes: fbe90cdd776c ("ethdev: add probing finish function")
> >>> Cc: ferruh.yigit@intel.com
> >>> Cc: thomas@monjalon.net
> >>> Signed-off-by: Gaetan Rivet <grive@u256.net>
> >>
> >> <...>
> >>
> >>> @@ -325,10 +346,17 @@ do_eth_dev_ring_create(const char *name,
> >>>  	data->kdrv = RTE_KDRV_NONE;
> >>>  	data->numa_node = numa_node;
> >>>  
> >>> -	/* finally assign rx and tx ops */
> >>> +	/* assign rx and tx ops */
> >>>  	eth_dev->rx_pkt_burst = eth_ring_rx;
> >>>  	eth_dev->tx_pkt_burst = eth_ring_tx;
> >>>  
> >>> +	/* finally set the rte_device pointer in eth_dev. */
> >>> +	eth_dev->device = ring_device_from_name(name);
> >>> +	if (eth_dev->device == NULL) {
> >>> +		rte_errno = ENODEV;
> >>> +		goto error;
> >>> +	}
> >>> +
> >>>  	rte_eth_dev_probing_finish(eth_dev);
> >>>  	*eth_dev_p = eth_dev;
> >>
> >> Why not move the 'rte_eth_dev_probing_finish()' to the 'rte_pmd_ring_probe()',
> >> below where 'eth_dev->device' set?
> > 
> > Hi Ferruh,
> > 
> > Sure it would work. The reason I did it this way is two-fold:
> > 
> >   * I disliked having two places where eth_dev->device was conditionally
> >     set. It makes it harder to read rte_pmd_ring_probe.
> 
> Agree, what about using a 'goto' to have the assignment and
> 'rte_eth_dev_probing_finish()' in a single place?
> But check seems needed since creation may failed at that stage, if you think
> better check can be done on 'ret' instead of 'eth_dev'...
> 
> > 
> >   * I was actually thinking, doing this patch, that we should modify
> >     rte_eth_dev_allocate() to take an rte_device as parameter, as all
> >     eth_dev are meant to be backed by an rte_device. Keeping this in
> >     mind, I meant to move writing the pointer closer to the
> >     rte_eth_dev_allocate() call.
> 
> That is a bigger change, may affect many (if not all) PMDs, so I think this can
> be considered when that change is available.
> 
> And although that change may fix the issues that 'eth_dev->device' is not set,
> which we had a few times before, not sure it worth to change all PMDs and ethdev
> API directly couple with rte_device, instead of PMD being the glue. Can be
> discussed more on its own patch.
> 
> > 
> > But you are right that it is needlessly verbose, using
> > vdev_bus->find_device() to do this stuff. I'm ok with changing it as you
> > described if you prefer.
> > 
> 
> That was the concern, that is too much code to take a value which is already
> available a few level up the stack.

Ok, future-proofing is a bad habit so let's not do it.

I'm not a fan of the goto for the 'happy path' though. Another simple
way would be to bring the vdev pointer with me as we go down the stack.

I will send a v2 shortly, if it's too ugly to move the pointer down I'll
use the goto, or if you tell me you'd prefer it.
  

Patch

diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index 41acbc513..ad27f9d89 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -244,6 +244,26 @@  static const struct eth_dev_ops ops = {
 	.mac_addr_add = eth_mac_addr_add,
 };
 
+static int
+dev_name_cmp(const struct rte_device *dev, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(dev->name, name);
+}
+
+static struct rte_device *
+ring_device_from_name(const char *name)
+{
+	struct rte_bus *vdev_bus;
+
+	vdev_bus = rte_bus_find_by_name("vdev");
+	if (vdev_bus == NULL)
+		return NULL;
+
+	return vdev_bus->find_device(NULL, dev_name_cmp, name);
+}
+
 static int
 do_eth_dev_ring_create(const char *name,
 		struct rte_ring * const rx_queues[],
@@ -294,6 +314,7 @@  do_eth_dev_ring_create(const char *name,
 	 * - store queue data in internals,
 	 * - store numa_node info in eth_dev_data
 	 * - point eth_dev_data to internals
+	 * - store EAL device in eth_dev,
 	 * - and point eth_dev structure to new eth_dev_data structure
 	 */
 
@@ -325,10 +346,17 @@  do_eth_dev_ring_create(const char *name,
 	data->kdrv = RTE_KDRV_NONE;
 	data->numa_node = numa_node;
 
-	/* finally assign rx and tx ops */
+	/* assign rx and tx ops */
 	eth_dev->rx_pkt_burst = eth_ring_rx;
 	eth_dev->tx_pkt_burst = eth_ring_tx;
 
+	/* finally set the rte_device pointer in eth_dev. */
+	eth_dev->device = ring_device_from_name(name);
+	if (eth_dev->device == NULL) {
+		rte_errno = ENODEV;
+		goto error;
+	}
+
 	rte_eth_dev_probing_finish(eth_dev);
 	*eth_dev_p = eth_dev;
 
@@ -584,9 +612,6 @@  rte_pmd_ring_probe(struct rte_vdev_device *dev)
 							  DEV_ATTACH, &eth_dev);
 			}
 
-			if (eth_dev)
-				eth_dev->device = &dev->device;
-
 			return ret;
 		}
 
@@ -644,9 +669,6 @@  rte_pmd_ring_probe(struct rte_vdev_device *dev)
 		}
 	}
 
-	if (eth_dev)
-		eth_dev->device = &dev->device;
-
 out_free:
 	rte_kvargs_free(kvlist);
 	rte_free(info);