]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
drivers: misc: therm_est: Correct shutdown path
authorSri Krishna chowdary <schowdary@nvidia.com>
Fri, 2 Aug 2013 13:08:34 +0000 (18:38 +0530)
committerSrikar Srimath Tirumala <srikars@nvidia.com>
Fri, 6 May 2016 22:04:22 +0000 (15:04 -0700)
1. Do not wait for work completion

therm_est_work_func calls orderly_poweroff which waits for
therm_est_shutdown to return. But since it waits for
work function's completion, a dead lock occurs during shutdown.
Avoiding the same by not waiting for the work function's
return.

2. Also, free memory in therm_est_work_func

If we were to check est for shutdown completion, since
it is freed already in shutdown callback,
it may cause memory violation and hence result in crash.

Bug 1332127

Change-Id: I2807178f6b447d07d6ef1a1a9dcd8e4a543eab62
Signed-off-by: Sri Krishna chowdary <schowdary@nvidia.com>
Reviewed-on: http://git-master/r/257561
Reviewed-on: http://git-master/r/263833
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Tested-by: Diwakar Tundlam <dtundlam@nvidia.com>
drivers/misc/therm_est.c

index 650a8c676b0d0349ee6ab601e61c426ed4dfe99a..75f43785b6381e1eee602cb14534a8b5e15290c6 100644 (file)
@@ -265,6 +265,10 @@ static void therm_est_work_func(struct work_struct *work)
        if (est->thz && ((est->cur_temp < est->low_limit) ||
                        (est->cur_temp >= est->high_limit))) {
                thermal_zone_device_update(est->thz);
+               if (!(est->thz)) {
+                       kfree(est);
+                       return;
+               }
                therm_est_update_timer_trips(est);
                therm_est_update_limits(est);
        }
@@ -783,6 +787,7 @@ static int therm_est_remove(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(therm_est_nodes); i++)
                device_remove_file(&pdev->dev, &therm_est_nodes[i].dev_attr);
        thermal_zone_device_unregister(est->thz);
+       kfree(est->thz);
        destroy_workqueue(est->workqueue);
        kfree(est);
        return 0;
@@ -790,7 +795,21 @@ static int therm_est_remove(struct platform_device *pdev)
 
 static void therm_est_shutdown(struct platform_device *pdev)
 {
-       therm_est_remove(pdev);
+
+       struct therm_estimator *est = platform_get_drvdata(pdev);
+       int i;
+
+       cancel_delayed_work(&est->therm_est_work);
+       cancel_delayed_work_sync(&est->timer_trip_work);
+
+#ifdef CONFIG_PM
+       unregister_pm_notifier(&est->pm_nb);
+#endif
+       for (i = 0; i < ARRAY_SIZE(therm_est_nodes); i++)
+               device_remove_file(&pdev->dev, &therm_est_nodes[i].dev_attr);
+       thermal_zone_device_unregister(est->thz);
+       kfree(est->thz);
+       est->thz = NULL;
 }
 
 static struct platform_driver therm_est_driver = {