Skip to contentSkip to conversation

qlcnic: using too much stack

PATCH Superseded Dan Carpenter 4 participants 8 messages Aug 9, 2010 – Aug 10, 2010

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 qlcnic: using too much stack

qlcnic_pci_info structs are 128 bytes so an array of 8 uses 1024 bytes. That's a lot if you run with 4K stacks. I allocated them with kcalloc() instead.

drivers/net/qlcnic/qlcnic_main.c +21 -6
index 7f27e2a..da84229 100644
@@ -473,14 +473,20 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
 static int
 qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
-	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
 	int i, ret = 0, err;
 	u8 pfn;
 
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
 	adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
 				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
-	if (!adapter->npars)
-		return -ENOMEM;
+	if (!adapter->npars) {
+		err = -ENOMEM;
+		goto err_pci_info;
+	}
 
 	adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
 				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
@@ -508,6 +514,7 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
 		adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
 
+	kfree(pci_info);
 	return 0;
 
 err_eswitch:
@@ -516,6 +523,8 @@ err_eswitch:
 err_npars:
 	kfree(adapter->npars);
 	adapter->eswitch = NULL;
+err_pci_info:
+	kfree(pci_info);
 
 	return ret;
 }
@@ -3362,15 +3371,21 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
-	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
 	int i, ret;
 
 	if (size != sizeof(pci_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
 	ret = qlcnic_get_pci_info(adapter, pci_info);
-	if (ret)
+	if (ret) {
+		kfree(pci_info);
 		return ret;
+	}
 
 	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
 		pci_cfg[i].pci_func = pci_info[i].id;
@@ -3381,8 +3396,8 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
 	}
 	memcpy(buf, &pci_cfg, size);
+	kfree(pci_info);
 	return size;
-
 }
 static struct bin_attribute bin_attr_npar_config = {
 	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
#1 lore raw
Quoted 76 lines · Dan Carpenter

qlcnic_pci_info structs are 128 bytes so an array of 8 uses 1024 bytes. That's a lot if you run with 4K stacks. I allocated them with kcalloc() instead.

drivers/net/qlcnic/qlcnic_main.c +0 -0
index 7f27e2a..da84229 100644
@@ -473,14 +473,20 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)

static int
qlcnic_init_pci_info(struct qlcnic_adapter *adapter) {

drivers/net/qlcnic/qlcnic_main.c +1 -1
-	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
	int i, ret = 0, err;
	u8 pfn;
drivers/net/qlcnic/qlcnic_main.c +4 -0
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
	adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
drivers/net/qlcnic/qlcnic_main.c +4 -2
-	if (!adapter->npars)
-		return -ENOMEM;
+	if (!adapter->npars) {
+		err = -ENOMEM;
+		goto err_pci_info;
+	}
	adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
drivers/net/qlcnic/qlcnic_main.c +1 -0
@@ -508,6 +514,7 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
 		adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
 
+	kfree(pci_info);
 	return 0;
 

err_eswitch:

drivers/net/qlcnic/qlcnic_main.c +0 -0
@@ -516,6 +523,8 @@ err_eswitch:

err_npars:

	kfree(adapter->npars);
	adapter->eswitch = NULL;
drivers/net/qlcnic/qlcnic_main.c +2 -0
+err_pci_info:
+	kfree(pci_info);
	return ret;
}
drivers/net/qlcnic/qlcnic_main.c +8 -2
@@ -3362,15 +3371,21 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
-	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
 	int i, ret;
 
 	if (size != sizeof(pci_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
 	ret = qlcnic_get_pci_info(adapter, pci_info);
-	if (ret)
+	if (ret) {
+		kfree(pci_info);
 		return ret;
+	}
 
 	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
 		pci_cfg[i].pci_func = pci_info[i].id;

drivers/net/qlcnic/qlcnic_main.c qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj, · line 3403

Quoted 9 lines
drivers/net/qlcnic/qlcnic_main.c +1 -1
@@ -3381,8 +3396,8 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
 	}
 	memcpy(buf, &pci_cfg, size);
+	kfree(pci_info);
 	return size;
-
 }
 static struct bin_attribute bin_attr_npar_config = {
 	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},

It looks fine except that I'd use kzalloc instead of kcalloc above.

thanks,
-Anirban

#2 lore raw
Quoted 3 lines · Anirban Chakraborty

It looks fine except that I'd use kzalloc instead of kcalloc above.

It's no problem to do that, and I'm already respinning the patches but I'm confused. It looks like pci_info gets initialized correctly. What am I missing?

regards,
dan carpenter

Quoted 2 lines

thanks,
-Anirban

#3 lore raw
Quoted 8 lines · Dan Carpenter
Quoted 3 lines · Anirban Chakraborty

It looks fine except that I'd use kzalloc instead of kcalloc above.

It's no problem to do that, and I'm already respinning the patches but I'm confused. It looks like pci_info gets initialized correctly. What am I missing?

Your patch is fine except that the preferred way is to use kzalloc over kaclloc. kzalloc does not need that extra argument that you are passing to kcalloc.

-Anirban

#4 lore raw
Quoted 2 lines · Anirban Chakraborty

Your patch is fine except that the preferred way is to use kzalloc over kaclloc. kzalloc does not need that extra argument that you are passing to kcalloc.

You probably meant to write "my preferred way" as the kcalloc to "kzalloc with a multiply" ratio is pretty high.

It's actually about 2.5 to 1 in favor of kcalloc.

$ grep -rw --include=*.[ch] kcalloc * | wc -l
419
$ grep -rP --include=*.[ch] "\bkzalloc\s*\(\s*\w+\s*\*\s*\w+" * | \
  grep -vP "\bkzalloc\s*\(\s*sizeof\s+\*\s*\w+\s*," | wc -l
164

(the grep -vP avoids kzalloc(sizeof *p, GFP_foo)

Actually, there might be a reason to use kzalloc in that location to match the other similar use a few lines away, but I'd prefer that the other use be converted to kcalloc.

cheers, Joe

#5 lore raw
Quoted 17 lines · Joe Perches
Quoted 2 lines · Anirban Chakraborty

Your patch is fine except that the preferred way is to use kzalloc over kaclloc. kzalloc does not need that extra argument that you are passing to kcalloc.

You probably meant to write "my preferred way" as the kcalloc to "kzalloc with a multiply" ratio is pretty high.

It's actually about 2.5 to 1 in favor of kcalloc.

$ grep -rw --include=*.[ch] kcalloc * | wc -l
419
$ grep -rP --include=*.[ch] "\bkzalloc\s*\(\s*\w+\s*\*\s*\w+" * | \
 grep -vP "\bkzalloc\s*\(\s*sizeof\s+\*\s*\w+\s*," | wc -l
164
Quoted 6 lines

(the grep -vP avoids kzalloc(sizeof *p, GFP_foo)

Actually, there might be a reason to use kzalloc in that location to match the other similar use a few lines away, but I'd prefer that the other use be converted to kcalloc.

I was suggesting based on the following:
http://lwn.net/Articles/147014/

thanks,
Anirban

#6 lore raw
Quoted 9 lines · Anirban Chakraborty
Quoted 6 lines · Joe Perches
Quoted 2 lines · Anirban Chakraborty

Your patch is fine except that the preferred way is to use kzalloc over kaclloc. kzalloc does not need that extra argument that you are passing to kcalloc.

You probably meant to write "my preferred way"
as the kcalloc to "kzalloc with a multiply"
ratio is pretty high.

I was suggesting based on the following:
http://lwn.net/Articles/147014/

Note that article suggests kzalloc for allocating
a single zeroed object.

kcalloc is used for multiple zeroed objects and
protects against oversized allocations.

maintainer
#7 lore raw

From: Joe Perches <[email protected]>
Date: Mon, 09 Aug 2010 20:39:06 -0700

Quoted 8 lines · Anirban Chakraborty
Quoted 7 lines · Joe Perches
Quoted 6 lines · Anirban Chakraborty
Quoted 2 lines

Your patch is fine except that the preferred way is to use kzalloc over kaclloc. kzalloc does not need that extra argument that you are passing to kcalloc.

You probably meant to write "my preferred way"
as the kcalloc to "kzalloc with a multiply"
ratio is pretty high.

Quoted 8 lines
Quoted 2 lines

I was suggesting based on the following:
http://lwn.net/Articles/147014/

Note that article suggests kzalloc for allocating
a single zeroed object.

kcalloc is used for multiple zeroed objects and
protects against oversized allocations.

Agreed, kcalloc should be used here.