hwmon_device_register_with_info registration API issue
Subsystems (2)
Hi Jean and al,
Thank you for your Kernel Recipes 2016 talk about the new hwmon registration API [1].
I'm trying to use the latest hwmon_device_register_with_info() API where hwmon core handles the sysfs attributes for me. However, I cannot use it with a NULL parent struct device *dev and non-NULL struct hwmon_chip_info *chip. My platform driver module_init() calls hwmon_device_register_with_info(). __hwmon_device_register() has a NULL pointer dereference error because it uses device managed memory allocation internally.
For example,
my_hwmon_dev = hwmon_device_register_with_info(NULL, "my_name", NULL, &my_hwmon_chip_info, NULL);
--> __hwmon_device_register(NULL, "my_name", NULL, &my_hwmon_chip_info, NULL); ----> hwdev->groups = devm_kcalloc(NULL, ngroups, sizeof(*groups), GFP_KERNEL);
I see that later in the function dev is checked for NULL in "hdev-
Quoted 1 line
of_node= dev ?dev->of_node: NULL;" but it cannot be NULL for
devm_kcalloc().
I tried the following 4.10.17 patch because I expected the hwmon attributes to be stored with the hwmon device directly and not the struct device *dev parent. However, none of my attributes are showing up in /sys/class/hwmon#/.
Is my approach wrong?
drivers/hwmon/hwmon.c +0 -0
@@ -560,6 +560,17 @@ __hwmon_device_register(struct device *dev, const
char *name, void *drvdata,
hdev = &hwdev->dev;
+ hwdev->name = name;
+ hdev->class = &hwmon_class;
+ hdev->parent = dev;
+ hdev->of_node = dev ? dev->of_node : NULL;
+ hwdev->chip = chip;
+ dev_set_drvdata(hdev, drvdata);
+ dev_set_name(hdev, HWMON_ID_FORMAT, id);
+ err = device_register(hdev);
+ if (err)
+ goto free_hwmon;
+
if (chip) {
struct attribute **attrs;
int ngroups = 2; /* terminating NULL plus &hwdev-
Quoted 1 line
groups */
@@ -568,14 +579,14 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
for (i = 0; groups[i]; i++) ngroups++;
- hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups),
+ hwdev->groups = devm_kcalloc(dev ? dev : hdev, ngroups, sizeof(*groups),
GFP_KERNEL);
if (!hwdev->groups) {
err = -ENOMEM;
goto free_hwmon;
}
- attrs = __hwmon_create_attrs(dev, drvdata, chip); + attrs = __hwmon_create_attrs(dev ? dev : hdev, drvdata, chip);
if (IS_ERR(attrs)) {
err = PTR_ERR(attrs);
goto free_hwmon;
@@ -595,17 +606,6 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hdev->groups = groups;
}
- hwdev->name = name;
- hdev->class = &hwmon_class;
- hdev->parent = dev;
- hdev->of_node = dev ? dev->of_node : NULL;
- hwdev->chip = chip;
- dev_set_drvdata(hdev, drvdata);
- dev_set_name(hdev, HWMON_ID_FORMAT, id);
- err = device_register(hdev);
- if (err)
- goto free_hwmon;
-
if (chip && chip->ops->read &&
chip->info[0]->type == hwmon_chip && (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) {
[1] https://kernel-recipes.org/en/2016/talks/new-hwmon-device-registra
tion-api/
Guenter Roeck
maintainerQuoted 23 lines · Lucas Magasweran
Hi Jean and al,
Thank you for your Kernel Recipes 2016 talk about the new hwmon registration API [1].
I'm trying to use the latest
hwmon_device_register_with_info()API where hwmon core handles the sysfs attributes for me. However, I cannot use it with a NULL parent struct device *dev and non-NULL structhwmon_chip_info*chip. My platform drivermodule_init()calls hwmon_device_register_with_info(). __hwmon_device_register() has a NULL pointer dereference error because it uses device managed memory allocation internally.For example,
my_hwmon_dev=hwmon_device_register_with_info(NULL, "my_name", NULL, &my_hwmon_chip_info, NULL);
--> __hwmon_device_register(NULL, "my_name", NULL,&my_hwmon_chip_info, NULL); ---->hwdev->groups=devm_kcalloc(NULL, ngroups, sizeof(*groups), GFP_KERNEL);
Quoted 9 lines
I see that later in the function dev is checked for NULL in "hdev-
Quoted 1 line
of_node= dev ?dev->of_node: NULL;" but it cannot be NULL for
devm_kcalloc().I tried the following 4.10.17 patch because I expected the hwmon attributes to be stored with the hwmon device directly and not the struct device *dev parent. However, none of my attributes are showing up in /sys/class/hwmon#/.
I assume you mean /sys/class/hwmon/hwmon#/.
Quoted 2 lines
Is my approach wrong?
Yes. Parent must not be NULL if chip is used. The use case of parent==NULL and chip!=NULL is not and will not be supported. Also, the only reason for supporting a NULL parent is that the thermal code uses it, and it is all but impossible to change the thermal code to provide a device pointer.
I would strongly suggest to modify your code and provide a parent (a pointer to either a platform or hardware device). Most likely that means to convert it to a platform device.
If you insist in not providing a parent, you'll have to use hwmon_device_register_with_groups(). Of course, that means you'll have to handle the attributes.
Guenter
PATCH 1/1 hwmon: (core) check parent dev != NULL when chip != NULL
Guenter, thank you for clarifying the usage of the registration API.
Here is a proposed patch that checks for NULL parent if chip is non-NULL to avoid the null pointer dereference when used incorrectly with an update to the documentation.
--
Lucas Magasweran (1):
hwmon: (core) check parent dev != NULL when chip != NULL
Documentation/hwmon/hwmon-kernel-api.txt | 3 ++- drivers/hwmon/hwmon.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-)
Signature · 1 line
2.7.4
PATCH 1/1 hwmon: (core) check parent dev != NULL when chip != NULL
hwmon_device_register_with_info() registration API requires a non-NULL parent device when chip is non-NULL.
This commit adds a check and documents this requirement.
--- Documentation/hwmon/hwmon-kernel-api.txt | 3 ++- drivers/hwmon/hwmon.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-)
Documentation/hwmon/hwmon-kernel-api.txt +2 -1
@@ -71,7 +71,8 @@ hwmon_device_register_with_info is the most comprehensive and preferred means to register a hardware monitoring device. It creates the standard sysfs attributes in the hardware monitoring core, letting the driver focus on reading from and writing to the chip instead of having to bother with sysfs attributes. -Its parameters are described in more detail below. +The parent device parameter cannot be NULL with non-NULL chip info. Its +parameters are described in more detail below. devm_hwmon_device_register_with_info is similar to hwmon_device_register_with_info. However, it is device managed, meaning the
drivers/hwmon/hwmon.c +3 -0
@@ -698,6 +698,9 @@ hwmon_device_register_with_info(struct device *dev, const char *name,if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))return ERR_PTR (-EINVAL ); +if (chip && !dev) +return ERR_PTR (-EINVAL ); +return __hwmon_device_register (dev, name, drvdata, chip, extra_groups); }EXPORT_SYMBOL_GPL (hwmon_device_register_with_info);
Signature · 1 line
2.7.4
Re: hwmon: (core) check parent dev != NULL when chip != NULL
Quoted 6 lines · Lucas Magasweran
hwmon_device_register_with_info()registration API requires a non-NULL parent device when chip is non-NULL.This commit adds a check and documents this requirement.
Signed-off-by Lucas Magasweran <[email protected]>
Applied to hwmon-next.
Thanks,
Guenter
Quoted 33 lines
--- Documentation/hwmon/hwmon-kernel-api.txt | 3 ++- drivers/hwmon/hwmon.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-)Documentation/hwmon/hwmon-kernel-api.txt +2
-1@@ -71,7 +71,8 @@ hwmon_device_register_with_info is the most comprehensive and preferred means to register a hardware monitoring device. It creates the standard sysfs attributes in the hardware monitoring core, letting the driver focus on reading from and writing to the chip instead of having to bother with sysfs attributes. -Its parameters are described in more detail below. +The parent device parameter cannot be NULL with non-NULL chip info. Its +parameters are described in more detail below. devm_hwmon_device_register_with_info is similar to hwmon_device_register_with_info. However, it is device managed, meaning thedrivers/hwmon/hwmon.c +3
-0@@ -698,6 +698,9 @@ hwmon_device_register_with_info(struct device *dev, const char *name,if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))return ERR_PTR (-EINVAL ); +if (chip && !dev) +return ERR_PTR (-EINVAL ); +return __hwmon_device_register (dev, name, drvdata, chip, extra_groups); }EXPORT_SYMBOL_GPL (hwmon_device_register_with_info);