Commit 585fc83e authored by Chanwoo Choi's avatar Chanwoo Choi Committed by MyungJoo Ham

PM / devfreq: Fix devfreq_remove_device() to improve the sequence of resource free

This patch modify devfreq_remove_device() to improve the sequence of resource
free. If executing existing devfreq_remove_device(), this function always
executes _remove_devfreq() twice. In result, second _remove_devfreq() always
return error value. So, This patch resolves complicated function sequence
as following:

[Flow sequence before modification]
devfreq_remove_device()
   _remove_devfreq(devfreq, false)
      kfree(devfreq);  /* Free devfreq */
      if (!skip ...) { /* skip is false */
         device_unregister(&devfreq->dev)
         put_device(&devfreq->dev);
            ...
            dev->release()
               devfreq_dev_release()
                  _remove_devfreq(devfreq, true) <- Recall to free devfreq
                  /*
		   * Always return error without freeing resource because
		   * already _remove_devfreq() frees the memory of devfreq.
		   */
   }

[Flow sequence after modification]
devfreq_remove_device
   device_unregister(&devfreq->dev)
   put_device(&devfreq->dev);
      ..
      dev->release()
         devfreq_dev_release()
            _remove_devfreq()
               kfree(devfreq); /* Free devfreq */
Signed-off-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
[Merge conflict resolved by MyungJoo]
Signed-off-by: default avatarMyungJoo Ham <myungjoo.ham@samsung.com>
parent 26d51853
...@@ -394,7 +394,7 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, ...@@ -394,7 +394,7 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
* @devfreq: the devfreq struct * @devfreq: the devfreq struct
* @skip: skip calling device_unregister(). * @skip: skip calling device_unregister().
*/ */
static void _remove_devfreq(struct devfreq *devfreq, bool skip) static void _remove_devfreq(struct devfreq *devfreq)
{ {
mutex_lock(&devfreq_list_lock); mutex_lock(&devfreq_list_lock);
if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
...@@ -412,11 +412,6 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) ...@@ -412,11 +412,6 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
if (devfreq->profile->exit) if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent); devfreq->profile->exit(devfreq->dev.parent);
if (!skip && get_device(&devfreq->dev)) {
device_unregister(&devfreq->dev);
put_device(&devfreq->dev);
}
mutex_destroy(&devfreq->lock); mutex_destroy(&devfreq->lock);
kfree(devfreq); kfree(devfreq);
} }
...@@ -426,14 +421,12 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) ...@@ -426,14 +421,12 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
* @dev: the devfreq device * @dev: the devfreq device
* *
* This calls _remove_devfreq() if _remove_devfreq() is not called. * This calls _remove_devfreq() if _remove_devfreq() is not called.
* Note that devfreq_dev_release() could be called by _remove_devfreq() as
* well as by others unregistering the device.
*/ */
static void devfreq_dev_release(struct device *dev) static void devfreq_dev_release(struct device *dev)
{ {
struct devfreq *devfreq = to_devfreq(dev); struct devfreq *devfreq = to_devfreq(dev);
_remove_devfreq(devfreq, true); _remove_devfreq(devfreq);
} }
/** /**
...@@ -544,7 +537,8 @@ int devfreq_remove_device(struct devfreq *devfreq) ...@@ -544,7 +537,8 @@ int devfreq_remove_device(struct devfreq *devfreq)
if (!devfreq) if (!devfreq)
return -EINVAL; return -EINVAL;
_remove_devfreq(devfreq, false); device_unregister(&devfreq->dev);
put_device(&devfreq->dev);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment