OSDN Git Service

drivers: thermal: Exit sysfs notify kthread when sensor unregisters
authorRam Chandrasekar <rkumbako@codeaurora.org>
Fri, 10 Feb 2017 21:58:30 +0000 (14:58 -0700)
committerRam Chandrasekar <rkumbako@codeaurora.org>
Wed, 15 Feb 2017 19:05:11 +0000 (12:05 -0700)
When a thermal zone unregisters, it initiates a blocking call
kthread_stop for the sysfs notify kthread to exit. But the sysfs notify
kthread is blocked on a completion event, which may not be triggered after
the sensor driver initiates a thermal zone unregister call. So, the
kthread_stop will be blocked forever.

As a part of thermal zone unregister, set a thermal zone unregister flag
and send a completion event before calling kthread_stop. Make the sysfs
notify kthread to be aware of thermal zone unregister flag and exit
after the completion event is triggered.

Change-Id: Icf045e0ad6e28135cd3a54c15d9923f095a286ff
Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
drivers/thermal/thermal_core.c
include/linux/thermal.h

index 2b49608..04cf31c 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (C) 2008 Intel Corp
  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
- *  Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  *
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -382,9 +382,11 @@ static __ref int sensor_sysfs_notify(void *data)
        struct sensor_info *sensor = (struct sensor_info *)data;
 
        while (!kthread_should_stop()) {
-               while (wait_for_completion_interruptible(
-                  &sensor->sysfs_notify_complete) != 0)
-                       ;
+               if (wait_for_completion_interruptible(
+                       &sensor->sysfs_notify_complete) != 0)
+                       continue;
+               if (sensor->deregister_active)
+                       return ret;
                reinit_completion(&sensor->sysfs_notify_complete);
                sysfs_notify(&sensor->tz->device.kobj, NULL,
                                        THERMAL_UEVENT_DATA);
@@ -580,6 +582,7 @@ int sensor_init(struct thermal_zone_device *tz)
        sensor->threshold_max = INT_MAX;
        sensor->max_idx = -1;
        sensor->min_idx = -1;
+       sensor->deregister_active = false;
        mutex_init(&sensor->lock);
        INIT_LIST_HEAD_RCU(&sensor->sensor_list);
        INIT_LIST_HEAD_RCU(&sensor->threshold_list);
@@ -2471,6 +2474,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
        thermal_remove_hwmon_sysfs(tz);
        flush_work(&tz->sensor.work);
+       tz->sensor.deregister_active = true;
+       complete(&tz->sensor.sysfs_notify_complete);
        kthread_stop(tz->sensor.sysfs_notify_thread);
        mutex_lock(&thermal_list_lock);
        list_del_rcu(&tz->sensor.sensor_list);
index b90f8f5..4d2cf47 100644 (file)
@@ -178,6 +178,7 @@ struct sensor_info {
        struct work_struct work;
        struct task_struct *sysfs_notify_thread;
        struct completion sysfs_notify_complete;
+       bool deregister_active;
 };
 
 /**