diff mbox

[rdma-next,V1,03/17] IB/core: Release allocated memory in cache setup failure

Message ID 1478184265-9620-4-git-send-email-leon@kernel.org (mailing list archive)
State Accepted
Headers show

Commit Message

Leon Romanovsky Nov. 3, 2016, 2:44 p.m. UTC
The failure in ib_cache_setup_one function during
ib_register_device will leave leaked allocated memory.

Fixes: 03db3a2d81e6 ("IB/core: Add RoCE GID table management")
Signed-off-by: Leon Romanovsky <leon@kernel.org>
---
 drivers/infiniband/core/cache.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

Comments

Ira Weiny Dec. 16, 2016, 3:42 a.m. UTC | #1
On Thu, Nov 03, 2016 at 04:44:11PM +0200, Leon Romanovsky wrote:
> The failure in ib_cache_setup_one function during
> ib_register_device will leave leaked allocated memory.
> 
> Fixes: 03db3a2d81e6 ("IB/core: Add RoCE GID table management")
> Signed-off-by: Leon Romanovsky <leon@kernel.org>

> ---
>  drivers/infiniband/core/cache.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
> index 1a2984c..ae04826 100644
> --- a/drivers/infiniband/core/cache.c
> +++ b/drivers/infiniband/core/cache.c
> @@ -770,12 +770,8 @@ static int _gid_table_setup_one(struct ib_device *ib_dev)
>  	int err = 0;
>  
>  	table = kcalloc(ib_dev->phys_port_cnt, sizeof(*table), GFP_KERNEL);
> -
> -	if (!table) {
> -		pr_warn("failed to allocate ib gid cache for %s\n",
> -			ib_dev->name);
> +	if (!table)
>  		return -ENOMEM;
> -	}

NIT: I think this would be worth separating out.

>  
>  	for (port = 0; port < ib_dev->phys_port_cnt; port++) {
>  		u8 rdma_port = port + rdma_start_port(ib_dev);
> @@ -1170,14 +1166,13 @@ int ib_cache_setup_one(struct ib_device *device)
>  					  GFP_KERNEL);
>  	if (!device->cache.pkey_cache ||
>  	    !device->cache.lmc_cache) {
> -		pr_warn("Couldn't allocate cache for %s\n", device->name);
> -		return -ENOMEM;
> +		err = -ENOMEM;
> +		goto free;
>  	}
>  
>  	err = gid_table_setup_one(device);
>  	if (err)
> -		/* Allocated memory will be cleaned in the release function */
> -		return err;
> +		goto free;
>  
>  	for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p)
>  		ib_cache_update(device, p + rdma_start_port(device));
> @@ -1192,6 +1187,9 @@ int ib_cache_setup_one(struct ib_device *device)
>  
>  err:
>  	gid_table_cleanup_one(device);
> +free:
> +	kfree(device->cache.pkey_cache);
> +	kfree(device->cache.lmc_cache);


Despite the fact that another thread said this is supposed to be ok because
ib_cache_release_one free's these I much prefer what you have done here.

However, don't you need to NULL these out so that ib_cache_release_one can
safely call kfree again?

Ira

>  	return err;
>  }
>  
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe Dec. 16, 2016, 4:27 a.m. UTC | #2
On Thu, Dec 15, 2016 at 10:42:19PM -0500, ira.weiny wrote:
> >  err:
> >  	gid_table_cleanup_one(device);
> > +free:
> > +	kfree(device->cache.pkey_cache);
> > +	kfree(device->cache.lmc_cache);
> 
> Despite the fact that another thread said this is supposed to be ok because
> ib_cache_release_one free's these I much prefer what you have done here.
> 
> However, don't you need to NULL these out so that ib_cache_release_one can
> safely call kfree again?

Yes.

I feel deja vue here, like I've pointed this out before and the
resolution was to just rely on the release function so we don't have
bugs like this.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Leon Romanovsky Dec. 18, 2016, 7:41 a.m. UTC | #3
On Thu, Dec 15, 2016 at 09:27:43PM -0700, Jason Gunthorpe wrote:
> On Thu, Dec 15, 2016 at 10:42:19PM -0500, ira.weiny wrote:
> > >  err:
> > >  	gid_table_cleanup_one(device);
> > > +free:
> > > +	kfree(device->cache.pkey_cache);
> > > +	kfree(device->cache.lmc_cache);
> >
> > Despite the fact that another thread said this is supposed to be ok because
> > ib_cache_release_one free's these I much prefer what you have done here.
> >
> > However, don't you need to NULL these out so that ib_cache_release_one can
> > safely call kfree again?
>
> Yes.
>
> I feel deja vue here, like I've pointed this out before and the
> resolution was to just rely on the release function so we don't have
> bugs like this.

I'm sure that I missed it, can you point me to that discussion?
Thanks

>
> Jason
diff mbox

Patch

diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 1a2984c..ae04826 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -770,12 +770,8 @@  static int _gid_table_setup_one(struct ib_device *ib_dev)
 	int err = 0;
 
 	table = kcalloc(ib_dev->phys_port_cnt, sizeof(*table), GFP_KERNEL);
-
-	if (!table) {
-		pr_warn("failed to allocate ib gid cache for %s\n",
-			ib_dev->name);
+	if (!table)
 		return -ENOMEM;
-	}
 
 	for (port = 0; port < ib_dev->phys_port_cnt; port++) {
 		u8 rdma_port = port + rdma_start_port(ib_dev);
@@ -1170,14 +1166,13 @@  int ib_cache_setup_one(struct ib_device *device)
 					  GFP_KERNEL);
 	if (!device->cache.pkey_cache ||
 	    !device->cache.lmc_cache) {
-		pr_warn("Couldn't allocate cache for %s\n", device->name);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto free;
 	}
 
 	err = gid_table_setup_one(device);
 	if (err)
-		/* Allocated memory will be cleaned in the release function */
-		return err;
+		goto free;
 
 	for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p)
 		ib_cache_update(device, p + rdma_start_port(device));
@@ -1192,6 +1187,9 @@  int ib_cache_setup_one(struct ib_device *device)
 
 err:
 	gid_table_cleanup_one(device);
+free:
+	kfree(device->cache.pkey_cache);
+	kfree(device->cache.lmc_cache);
 	return err;
 }