[dpdk-dev,v2] enic: fix seg fault when releasing queues

Message ID 1464230700-13341-1-git-send-email-johndale@cisco.com (mailing list archive)
State Superseded, archived
Delegated to: Bruce Richardson
Headers

Commit Message

John Daley (johndale) May 26, 2016, 2:45 a.m. UTC
  If device configuration failed due to a lack of resources, like if
there were more queues requested than available, the queue release
function is called with NULL pointers which were being dereferenced.

Skip releasing queues if they are NULL pointers. Also, if configuration
fails due to lack of resources, be more specific about which resources
are lacking.

Fixes: fefed3d1e62c ("enic: new driver")
Signed-off-by: John Daley <johndale@cisco.com>
---
v2: Log an error for all resource deficiencies not just the first one
found.

 drivers/net/enic/enic_main.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)
  

Comments

Bruce Richardson June 9, 2016, 4:08 p.m. UTC | #1
On Wed, May 25, 2016 at 07:45:00PM -0700, John Daley wrote:
> If device configuration failed due to a lack of resources, like if
> there were more queues requested than available, the queue release
> function is called with NULL pointers which were being dereferenced.
> 
> Skip releasing queues if they are NULL pointers. Also, if configuration
> fails due to lack of resources, be more specific about which resources
> are lacking.

The "also", and a a review of the code, indicates that the error message
changes should be a separate patch, as it's not related to the NULL check fix.
:-)


> 
> Fixes: fefed3d1e62c ("enic: new driver")
> Signed-off-by: John Daley <johndale@cisco.com>
> ---
> v2: Log an error for all resource deficiencies not just the first one
> found.
> 
>  drivers/net/enic/enic_main.c | 37 +++++++++++++++++++++++--------------
>  1 file changed, 23 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
> index 996f999..411d23c 100644
> --- a/drivers/net/enic/enic_main.c
> +++ b/drivers/net/enic/enic_main.c
> @@ -426,14 +426,16 @@ int enic_alloc_intr_resources(struct enic *enic)
>  
>  void enic_free_rq(void *rxq)
>  {
> -	struct vnic_rq *rq = (struct vnic_rq *)rxq;
> -	struct enic *enic = vnic_dev_priv(rq->vdev);
> +	if (rxq != NULL) {
> +		struct vnic_rq *rq = (struct vnic_rq *)rxq;
> +		struct enic *enic = vnic_dev_priv(rq->vdev);
>  
> -	enic_rxmbuf_queue_release(enic, rq);
> -	rte_free(rq->mbuf_ring);
> -	rq->mbuf_ring = NULL;
> -	vnic_rq_free(rq);
> -	vnic_cq_free(&enic->cq[rq->index]);
> +		enic_rxmbuf_queue_release(enic, rq);
> +		rte_free(rq->mbuf_ring);
> +		rq->mbuf_ring = NULL;
> +		vnic_rq_free(rq);
> +		vnic_cq_free(&enic->cq[rq->index]);
> +	}
>  }

Is it not just easier to put a check at the top for: 
	if (rq == NULL)
		return;

Rather than putting the whole body of the function inside an if statement? It
would certainly be a smaller diff.

/Bruce
  
John Daley (johndale) June 9, 2016, 6:56 p.m. UTC | #2
Patch broken into separate patches for fixing seg fault and improving
log messages.

John Daley (2):
  enic: fix seg fault when releasing queues
  enic: more specific out of resources error messages

 drivers/net/enic/enic_main.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)
  

Patch

diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 996f999..411d23c 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -426,14 +426,16 @@  int enic_alloc_intr_resources(struct enic *enic)
 
 void enic_free_rq(void *rxq)
 {
-	struct vnic_rq *rq = (struct vnic_rq *)rxq;
-	struct enic *enic = vnic_dev_priv(rq->vdev);
+	if (rxq != NULL) {
+		struct vnic_rq *rq = (struct vnic_rq *)rxq;
+		struct enic *enic = vnic_dev_priv(rq->vdev);
 
-	enic_rxmbuf_queue_release(enic, rq);
-	rte_free(rq->mbuf_ring);
-	rq->mbuf_ring = NULL;
-	vnic_rq_free(rq);
-	vnic_cq_free(&enic->cq[rq->index]);
+		enic_rxmbuf_queue_release(enic, rq);
+		rte_free(rq->mbuf_ring);
+		rq->mbuf_ring = NULL;
+		vnic_rq_free(rq);
+		vnic_cq_free(&enic->cq[rq->index]);
+	}
 }
 
 void enic_start_wq(struct enic *enic, uint16_t queue_idx)
@@ -816,22 +818,29 @@  static void enic_dev_deinit(struct enic *enic)
 int enic_set_vnic_res(struct enic *enic)
 {
 	struct rte_eth_dev *eth_dev = enic->rte_dev;
+	int rc = 0;
 
-	if ((enic->rq_count < eth_dev->data->nb_rx_queues) ||
-		(enic->wq_count < eth_dev->data->nb_tx_queues)) {
-		dev_err(dev, "Not enough resources configured, aborting\n");
-		return -1;
+	if (enic->rq_count < eth_dev->data->nb_rx_queues) {
+		dev_err(dev, "Not enough Receive queues. Requested:%u, Configured:%u\n",
+			eth_dev->data->nb_rx_queues, enic->rq_count);
+		rc = -1;
+	}
+	if (enic->wq_count < eth_dev->data->nb_tx_queues) {
+		dev_err(dev, "Not enough Transmit queues. Requested:%u, Configured:%u\n",
+			eth_dev->data->nb_tx_queues, enic->wq_count);
+		rc = -1;
 	}
 
 	enic->rq_count = eth_dev->data->nb_rx_queues;
 	enic->wq_count = eth_dev->data->nb_tx_queues;
 	if (enic->cq_count < (enic->rq_count + enic->wq_count)) {
-		dev_err(dev, "Not enough resources configured, aborting\n");
-		return -1;
+		dev_err(dev, "Not enough Completion queues. Required:%u, Configured:%u\n",
+			enic->rq_count + enic->wq_count, enic->cq_count);
+		rc = -1;
 	}
 
 	enic->cq_count = enic->rq_count + enic->wq_count;
-	return 0;
+	return rc;
 }
 
 static int enic_dev_init(struct enic *enic)