Re: [PATCHv4 14/48] thermal: core: move trips attributes to tz->device.groups

From: Zhang Rui
Date: Fri Jun 17 2016 - 04:45:11 EST


On ä, 2016-05-30 at 23:18 -0700, Eduardo Valentin wrote:
> Finally, move the last thermal zone sysfs attributes to
> tz->device.groups: trips attributes. This requires adding a
> attribute_group to thermal_zone_device, creating it dynamically, and
> then setting all trips attributes in it. The trips attribute is then
> added to the tz->device.groups.
>
> As the removal of all attributes are handled by device core, the
> device
> remove calls are not needed anymore.
>
> Cc: Zhang Rui <rui.zhang@xxxxxxxxx>
> Cc: linux-pm@xxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> Signed-off-by: Eduardo Valentin <edubezval@xxxxxxxxx>
> ---
> Âdrivers/thermal/thermal_core.c | 77 +++++++++++++++++++++-----------
> ----------
> Âinclude/linux/thermal.hÂÂÂÂÂÂÂÂ|ÂÂ2 ++
> Â2 files changed, 41 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> index ba4f7a9..0b60b04 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1188,8 +1188,9 @@ static const struct attribute_group
> *thermal_zone_attribute_groups[] = {
> Â */
> Âstatic int create_trip_attrs(struct thermal_zone_device *tz, int
> mask)
> Â{
> - int indx;
> Â int size = sizeof(struct thermal_attr) * tz->trips;
> + struct attribute **attrs;
> + int indx;
> Â
> Â tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> Â if (!tz->trip_type_attrs)
> @@ -1210,6 +1211,15 @@ static int create_trip_attrs(struct
> thermal_zone_device *tz, int mask)
> Â }
> Â }
> Â
> + attrs = kzalloc(sizeof(*attrs) * tz->trips * 3 + 1,
> GFP_KERNEL);
> + if (!attrs) {
> + kfree(tz->trip_type_attrs);
> + kfree(tz->trip_temp_attrs);
> + if (tz->ops->get_trip_hyst)
> + kfree(tz->trip_hyst_attrs);
> + return -ENOMEM;
> + }
> +
> Â for (indx = 0; indx < tz->trips; indx++) {
> Â /* create trip type attribute */
> Â snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> @@ -1220,9 +1230,7 @@ static int create_trip_attrs(struct
> thermal_zone_device *tz, int mask)
> Â tz-
> >trip_type_attrs[indx].name;
> Â tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> Â tz->trip_type_attrs[indx].attr.show =
> trip_point_type_show;
> -
> - device_create_file(&tz->device,
> - ÂÂÂ&tz->trip_type_attrs[indx].attr);
> + attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
> Â
> Â /* create trip temp attribute */
> Â snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> @@ -1239,9 +1247,7 @@ static int create_trip_attrs(struct
> thermal_zone_device *tz, int mask)
> Â tz->trip_temp_attrs[indx].attr.store =
> Â trip_point_t
> emp_store;
> Â }
> -
> - device_create_file(&tz->device,
> - ÂÂÂ&tz->trip_temp_attrs[indx].attr);
> + attrs[indx + tz->trips] = &tz-
> >trip_temp_attrs[indx].attr.attr;
> Â
> Â /* create Optional trip hyst attribute */
> Â if (!tz->ops->get_trip_hyst)
> @@ -1259,45 +1265,38 @@ static int create_trip_attrs(struct
> thermal_zone_device *tz, int mask)
> Â tz->trip_hyst_attrs[indx].attr.store =
> Â trip_point_hyst_store;
> Â }
> -
> - device_create_file(&tz->device,
> - ÂÂÂ&tz->trip_hyst_attrs[indx].attr);
> + attrs[indx + tz->trips * 2] =
> + &tz-
> >trip_hyst_attrs[indx].attr.attr;
> Â }
> - return 0;
> -}
> + attrs[tz->trips * 3] = NULL;

why bother clearing it explicitly? kzalloc already handles this, right?

> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> -{
> - int indx;
> + tz->trips_attribute_group.attrs = attrs;
> Â
> - for (indx = 0; indx < tz->trips; indx++) {
> - device_remove_file(&tz->device,
> - ÂÂÂ&tz->trip_type_attrs[indx].attr);
> - device_remove_file(&tz->device,
> - ÂÂÂ&tz->trip_temp_attrs[indx].attr);
> - if (tz->ops->get_trip_hyst)
> - device_remove_file(&tz->device,
> - ÂÂÂ&tz-
> >trip_hyst_attrs[indx].attr);
> - }
> - kfree(tz->trip_type_attrs);
> - kfree(tz->trip_temp_attrs);
> - kfree(tz->trip_hyst_attrs);
> + return 0;
> Â}
> Â
> -static int thermal_zone_create_device_groups(struct
> thermal_zone_device *tz)
> +static int thermal_zone_create_device_groups(struct
> thermal_zone_device *tz,
> + ÂÂÂÂÂint mask)
> Â{
> Â const struct attribute_group **groups;
> - int i, size;
> + int i, size, result;
> +
> + result = create_trip_attrs(tz, mask);
> + if (result)
> + return result;
> Â
> - size = ARRAY_SIZE(thermal_zone_attribute_groups) + 1;
> + /* we need one extra for trips and the NULL to terminate the
> array */
> + size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2;
> Â /* This also takes care of API requirement to be NULL
> terminated */
> Â groups = kcalloc(size, sizeof(*groups), GFP_KERNEL);
> Â if (!groups)
> Â return -ENOMEM;
> Â
> - for (i = 0; i < size - 1; i++)
> + for (i = 0; i < size - 2; i++)
> Â groups[i] = thermal_zone_attribute_groups[i];
> Â
> + groups[size - 2] = &tz->trips_attribute_group;
> +

Problem is that, previously, create_trip_attrs() does not handle the
case that tz->trips == 0 good enough, it happens to not bring big
problem.
tz->trip_type_attrs/tz->trip_temp_attrs/tz->trip_hyst_attrs is set
toÂZERO_SIZE_PTR when tz->trips equals 0, kfree() handles this.
But registering a sysfs group with one invalid attribute item is wrong.
And this causes oops in my machine when test_power driver, which has no
trip point, is unloaded. And maybe this is also the root cause of this
reportÂhttp://www.spinics.net/lists/kernel/msg2280260.html

Attached is an updated version, which creates trip attributes only if
tz->trips > 0, which solves the problem for me.