[v5,5/5] eal: simplify parameters of hotplug functions

Message ID 20181003231046.26772-6-thomas@monjalon.net (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series eal: simplify devargs and hotplug functions |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Thomas Monjalon Oct. 3, 2018, 11:10 p.m. UTC
  All information about a device to probe can be grouped
in a common string, which is what we usually call devargs.
An application should not have to parse this string before
calling the EAL probe function.
And the syntax could evolve to be more complex and support
matching multiple devices in one string.
That's why the bus name and device name should be removed from
rte_eal_hotplug_add().
Instead of changing this function, a simpler one is added
and used in the old one, which may be deprecated later.

When removing a device, we already know its rte_device handle
which can be directly passed as parameter of rte_eal_hotplug_remove().
If the rte_device is not known, it can be retrieved with the devargs,
by iterating in the device list (future RTE_DEV_FOREACH()).
Similarly to the probing case, a new function is added
and used in the old one, which may be deprecated later.
The new function is used in failsafe, because the replacement is easy.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
Reviewed-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
 drivers/net/failsafe/failsafe_eal.c     |  3 +-
 drivers/net/failsafe/failsafe_ether.c   |  3 +-
 lib/librte_eal/common/eal_common_dev.c  | 80 ++++++++++++++++---------
 lib/librte_eal/common/include/rte_dev.h | 30 +++++++++-
 lib/librte_eal/rte_eal_version.map      |  2 +
 5 files changed, 83 insertions(+), 35 deletions(-)
  

Comments

Gaëtan Rivet Oct. 4, 2018, 9:44 a.m. UTC | #1
I much prefer this API,

I have one remark inline however.

On Thu, Oct 04, 2018 at 01:10:46AM +0200, Thomas Monjalon wrote:
> All information about a device to probe can be grouped
> in a common string, which is what we usually call devargs.
> An application should not have to parse this string before
> calling the EAL probe function.
> And the syntax could evolve to be more complex and support
> matching multiple devices in one string.
> That's why the bus name and device name should be removed from
> rte_eal_hotplug_add().
> Instead of changing this function, a simpler one is added
> and used in the old one, which may be deprecated later.
> 
> When removing a device, we already know its rte_device handle
> which can be directly passed as parameter of rte_eal_hotplug_remove().
> If the rte_device is not known, it can be retrieved with the devargs,
> by iterating in the device list (future RTE_DEV_FOREACH()).
> Similarly to the probing case, a new function is added
> and used in the old one, which may be deprecated later.
> The new function is used in failsafe, because the replacement is easy.
> 
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> Reviewed-by: Andrew Rybchenko <arybchenko@solarflare.com>

With the following remark being taken care of,

Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>

> ---
>  drivers/net/failsafe/failsafe_eal.c     |  3 +-
>  drivers/net/failsafe/failsafe_ether.c   |  3 +-
>  lib/librte_eal/common/eal_common_dev.c  | 80 ++++++++++++++++---------
>  lib/librte_eal/common/include/rte_dev.h | 30 +++++++++-
>  lib/librte_eal/rte_eal_version.map      |  2 +
>  5 files changed, 83 insertions(+), 35 deletions(-)
> 

<snip>

> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> index ce6d145fb..5dcc1403f 100644
> --- a/lib/librte_eal/common/eal_common_dev.c
> +++ b/lib/librte_eal/common/eal_common_dev.c
> @@ -129,46 +129,61 @@ int rte_eal_dev_detach(struct rte_device *dev)
>  
>  int
>  rte_eal_hotplug_add(const char *busname, const char *devname,
> -		    const char *devargs)
> +		    const char *drvargs)
>  {
> -	struct rte_bus *bus;
> -	struct rte_device *dev;
> -	struct rte_devargs *da;
>  	int ret;
> +	char *devargs = NULL;
> +	int size, length = -1;
>  
> -	bus = rte_bus_find_by_name(busname);
> -	if (bus == NULL) {
> -		RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
> -		return -ENOENT;
> -	}
> +	do { /* 2 iterations: first is to know string length */
> +		size = length + 1;
> +		length = snprintf(devargs, size, "%s:%s,%s", busname, devname, drvargs);
> +		if (length >= size)
> +			devargs = malloc(length + 1);
> +		if (devargs == NULL)
> +			return -ENOMEM;
> +	} while (size == 0);

I don't see a good reason for writing it this way.
You use an additional state (size) and complicate something that is
pretty straightforward. To make sure no error was written here, I had to
do step-by-step careful reading, this should not be required by clean
code.

You should remove this loop, which then allow removing size, and forces using
simple code-flow.

>  
> -	if (bus->plug == NULL) {
> -		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
> -			bus->name);
> -		return -ENOTSUP;
> -	}
> +	ret = rte_dev_probe(devargs);
> +
> +	free(devargs);
> +	return ret;
> +}
> +
> +int __rte_experimental
> +rte_dev_probe(const char *devargs)
> +{
> +	struct rte_device *dev;
> +	struct rte_devargs *da;
> +	int ret;
>  
>  	da = calloc(1, sizeof(*da));
>  	if (da == NULL)
>  		return -ENOMEM;
>  
> -	ret = rte_devargs_parsef(da, "%s:%s,%s",
> -				 busname, devname, devargs);
> +	ret = rte_devargs_parse(da, devargs);
>  	if (ret)
>  		goto err_devarg;
>  
> +	if (da->bus->plug == NULL) {
> +		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
> +			da->bus->name);
> +		ret = -ENOTSUP;
> +		goto err_devarg;
> +	}
> +
>  	ret = rte_devargs_insert(da);
>  	if (ret)
>  		goto err_devarg;
>  
> -	ret = bus->scan();
> +	ret = da->bus->scan();
>  	if (ret)
>  		goto err_devarg;
>  
> -	dev = bus->find_device(NULL, cmp_dev_name, devname);
> +	dev = da->bus->find_device(NULL, cmp_dev_name, da->name);
>  	if (dev == NULL) {
>  		RTE_LOG(ERR, EAL, "Cannot find device (%s)\n",
> -			devname);
> +			da->name);
>  		ret = -ENODEV;
>  		goto err_devarg;
>  	}

<snip>
  
Thomas Monjalon Oct. 4, 2018, 11:46 a.m. UTC | #2
04/10/2018 11:44, Gaëtan Rivet:
> On Thu, Oct 04, 2018 at 01:10:46AM +0200, Thomas Monjalon wrote:
> > --- a/lib/librte_eal/common/eal_common_dev.c
> > +++ b/lib/librte_eal/common/eal_common_dev.c
> > @@ -129,46 +129,61 @@ int rte_eal_dev_detach(struct rte_device *dev)
> >  
> >  int
> >  rte_eal_hotplug_add(const char *busname, const char *devname,
> > -		    const char *devargs)
> > +		    const char *drvargs)
> >  {
> > -	struct rte_bus *bus;
> > -	struct rte_device *dev;
> > -	struct rte_devargs *da;
> >  	int ret;
> > +	char *devargs = NULL;
> > +	int size, length = -1;
> >  
> > -	bus = rte_bus_find_by_name(busname);
> > -	if (bus == NULL) {
> > -		RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
> > -		return -ENOENT;
> > -	}
> > +	do { /* 2 iterations: first is to know string length */
> > +		size = length + 1;
> > +		length = snprintf(devargs, size, "%s:%s,%s", busname, devname, drvargs);
> > +		if (length >= size)
> > +			devargs = malloc(length + 1);
> > +		if (devargs == NULL)
> > +			return -ENOMEM;
> > +	} while (size == 0);
> 
> I don't see a good reason for writing it this way.
> You use an additional state (size) and complicate something that is
> pretty straightforward. To make sure no error was written here, I had to
> do step-by-step careful reading, this should not be required by clean
> code.
> 
> You should remove this loop, which then allow removing size, and forces using
> simple code-flow.

The only reason for this loop is to avoid duplicating the snprintf format
in two calls.

It could be replaced by this:

	length = snprintf(devargs, 0, "%s:%s,%s", busname, devname, drvargs);
	if (length < 0)
		return -EINVAL;
	devargs = malloc(length + 1);
	if (devargs == NULL)
		return -ENOMEM;
	snprintf(devargs, length + 1, "%s:%s,%s", busname, devname, drvargs);

Any preference?
  
Gaëtan Rivet Oct. 4, 2018, 11:51 a.m. UTC | #3
On Thu, Oct 04, 2018 at 01:46:54PM +0200, Thomas Monjalon wrote:
> 04/10/2018 11:44, Gaëtan Rivet:
> > On Thu, Oct 04, 2018 at 01:10:46AM +0200, Thomas Monjalon wrote:
> > > --- a/lib/librte_eal/common/eal_common_dev.c
> > > +++ b/lib/librte_eal/common/eal_common_dev.c
> > > @@ -129,46 +129,61 @@ int rte_eal_dev_detach(struct rte_device *dev)
> > >  
> > >  int
> > >  rte_eal_hotplug_add(const char *busname, const char *devname,
> > > -		    const char *devargs)
> > > +		    const char *drvargs)
> > >  {
> > > -	struct rte_bus *bus;
> > > -	struct rte_device *dev;
> > > -	struct rte_devargs *da;
> > >  	int ret;
> > > +	char *devargs = NULL;
> > > +	int size, length = -1;
> > >  
> > > -	bus = rte_bus_find_by_name(busname);
> > > -	if (bus == NULL) {
> > > -		RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
> > > -		return -ENOENT;
> > > -	}
> > > +	do { /* 2 iterations: first is to know string length */
> > > +		size = length + 1;
> > > +		length = snprintf(devargs, size, "%s:%s,%s", busname, devname, drvargs);
> > > +		if (length >= size)
> > > +			devargs = malloc(length + 1);
> > > +		if (devargs == NULL)
> > > +			return -ENOMEM;
> > > +	} while (size == 0);
> > 
> > I don't see a good reason for writing it this way.
> > You use an additional state (size) and complicate something that is
> > pretty straightforward. To make sure no error was written here, I had to
> > do step-by-step careful reading, this should not be required by clean
> > code.
> > 
> > You should remove this loop, which then allow removing size, and forces using
> > simple code-flow.
> 
> The only reason for this loop is to avoid duplicating the snprintf format
> in two calls.
> 
> It could be replaced by this:
> 
> 	length = snprintf(devargs, 0, "%s:%s,%s", busname, devname, drvargs);
> 	if (length < 0)
> 		return -EINVAL;
> 	devargs = malloc(length + 1);
> 	if (devargs == NULL)
> 		return -ENOMEM;
> 	snprintf(devargs, length + 1, "%s:%s,%s", busname, devname, drvargs);
> 
> Any preference?
> 
> 

Yes, the second is cleaner IMO.
  

Patch

diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index ce1633f13..8a888b1ff 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -144,8 +144,7 @@  fs_bus_uninit(struct rte_eth_dev *dev)
 	int ret = 0;
 
 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
-		sdev_ret = rte_eal_hotplug_remove(sdev->bus->name,
-							sdev->dev->name);
+		sdev_ret = rte_dev_remove(sdev->dev);
 		if (sdev_ret) {
 			ERROR("Failed to remove requested device %s (err: %d)",
 			      sdev->dev->name, sdev_ret);
diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 51c96f78b..f2512c430 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -282,8 +282,7 @@  fs_dev_remove(struct sub_device *sdev)
 		sdev->state = DEV_PROBED;
 		/* fallthrough */
 	case DEV_PROBED:
-		ret = rte_eal_hotplug_remove(sdev->bus->name,
-					     sdev->dev->name);
+		ret = rte_dev_remove(sdev->dev);
 		if (ret) {
 			ERROR("Bus detach failed for sub_device %u",
 			      SUB_ID(sdev));
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index ce6d145fb..5dcc1403f 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -129,46 +129,61 @@  int rte_eal_dev_detach(struct rte_device *dev)
 
 int
 rte_eal_hotplug_add(const char *busname, const char *devname,
-		    const char *devargs)
+		    const char *drvargs)
 {
-	struct rte_bus *bus;
-	struct rte_device *dev;
-	struct rte_devargs *da;
 	int ret;
+	char *devargs = NULL;
+	int size, length = -1;
 
-	bus = rte_bus_find_by_name(busname);
-	if (bus == NULL) {
-		RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
-		return -ENOENT;
-	}
+	do { /* 2 iterations: first is to know string length */
+		size = length + 1;
+		length = snprintf(devargs, size, "%s:%s,%s", busname, devname, drvargs);
+		if (length >= size)
+			devargs = malloc(length + 1);
+		if (devargs == NULL)
+			return -ENOMEM;
+	} while (size == 0);
 
-	if (bus->plug == NULL) {
-		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
-			bus->name);
-		return -ENOTSUP;
-	}
+	ret = rte_dev_probe(devargs);
+
+	free(devargs);
+	return ret;
+}
+
+int __rte_experimental
+rte_dev_probe(const char *devargs)
+{
+	struct rte_device *dev;
+	struct rte_devargs *da;
+	int ret;
 
 	da = calloc(1, sizeof(*da));
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parsef(da, "%s:%s,%s",
-				 busname, devname, devargs);
+	ret = rte_devargs_parse(da, devargs);
 	if (ret)
 		goto err_devarg;
 
+	if (da->bus->plug == NULL) {
+		RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
+			da->bus->name);
+		ret = -ENOTSUP;
+		goto err_devarg;
+	}
+
 	ret = rte_devargs_insert(da);
 	if (ret)
 		goto err_devarg;
 
-	ret = bus->scan();
+	ret = da->bus->scan();
 	if (ret)
 		goto err_devarg;
 
-	dev = bus->find_device(NULL, cmp_dev_name, devname);
+	dev = da->bus->find_device(NULL, cmp_dev_name, da->name);
 	if (dev == NULL) {
 		RTE_LOG(ERR, EAL, "Cannot find device (%s)\n",
-			devname);
+			da->name);
 		ret = -ENODEV;
 		goto err_devarg;
 	}
@@ -178,7 +193,7 @@  rte_eal_hotplug_add(const char *busname, const char *devname,
 		return -EEXIST;
 	}
 
-	ret = bus->plug(dev);
+	ret = dev->bus->plug(dev);
 	if (ret) {
 		RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n",
 			dev->name);
@@ -197,9 +212,8 @@  rte_eal_hotplug_add(const char *busname, const char *devname,
 int
 rte_eal_hotplug_remove(const char *busname, const char *devname)
 {
-	struct rte_bus *bus;
 	struct rte_device *dev;
-	int ret;
+	struct rte_bus *bus;
 
 	bus = rte_bus_find_by_name(busname);
 	if (bus == NULL) {
@@ -207,24 +221,32 @@  rte_eal_hotplug_remove(const char *busname, const char *devname)
 		return -ENOENT;
 	}
 
-	if (bus->unplug == NULL) {
-		RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n",
-			bus->name);
-		return -ENOTSUP;
-	}
-
 	dev = bus->find_device(NULL, cmp_dev_name, devname);
 	if (dev == NULL) {
 		RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", devname);
 		return -EINVAL;
 	}
 
+	return rte_dev_remove(dev);
+}
+
+int __rte_experimental
+rte_dev_remove(struct rte_device *dev)
+{
+	int ret;
+
 	if (dev->driver == NULL) {
 		RTE_LOG(ERR, EAL, "Device is already unplugged\n");
 		return -ENOENT;
 	}
 
-	ret = bus->unplug(dev);
+	if (dev->bus->unplug == NULL) {
+		RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n",
+			dev->bus->name);
+		return -ENOTSUP;
+	}
+
+	ret = dev->bus->unplug(dev);
 	if (ret)
 		RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n",
 			dev->name);
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index d6c5d48a9..036180ff3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -197,13 +197,26 @@  int rte_eal_dev_detach(struct rte_device *dev);
  * @param devname
  *   The device name. Based on this device name, eal will identify a driver
  *   capable of handling it and pass it to the driver probing function.
- * @param devargs
+ * @param drvargs
  *   Device arguments to be passed to the driver.
  * @return
  *   0 on success, negative on error.
  */
 int rte_eal_hotplug_add(const char *busname, const char *devname,
-			const char *devargs);
+			const char *drvargs);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Add matching devices.
+ *
+ * @param devargs
+ *   Device arguments including bus, class and driver properties.
+ * @return
+ *   0 on success, negative on error.
+ */
+int __rte_experimental rte_dev_probe(const char *devargs);
 
 /**
  * Hotplug remove a given device from a specific bus.
@@ -217,6 +230,19 @@  int rte_eal_hotplug_add(const char *busname, const char *devname,
  */
 int rte_eal_hotplug_remove(const char *busname, const char *devname);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Remove one device.
+ *
+ * @param dev
+ *   Data structure of the device to remove.
+ * @return
+ *   0 on success, negative on error.
+ */
+int __rte_experimental rte_dev_remove(struct rte_device *dev);
+
 /**
  * Device comparison function.
  *
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 6bff37f4b..2ea7a870a 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -281,6 +281,8 @@  EXPERIMENTAL {
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
 	rte_dev_iterator_next;
+	rte_dev_probe;
+	rte_dev_remove;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;