Re: [PATCH 2/7] devfreq: protect devfreq stats data with spinlock

From: Chanwoo Choi
Date: Wed Nov 13 2019 - 04:41:35 EST


Hi,

On 11/13/19 6:13 PM, Kamil Konieczny wrote:
> Protect access to devfreq transitions stats with spinlock.

You have to add the more detailed reason why spinlock is necessary.
And are there any issue without spinlock?

In my case, I used the devfreq sysfs entries on Tizen Platfrom
for a long time, there are no any issue without spinlock.

Regards,
Chanwoo Choi

>
> Signed-off-by: Kamil Konieczny <k.konieczny@xxxxxxxxxxx>
> ---
> drivers/devfreq/devfreq.c | 18 +++++++++++++++---
> include/linux/devfreq.h | 3 +++
> 2 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 1602cca20fc4..ac04b5baef70 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -163,10 +163,16 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> cur_time = get_jiffies_64();
>
> /* Immediately exit if previous_freq is not initialized yet. */
> - if (!devfreq->previous_freq)
> - goto out;
> + if (!devfreq->previous_freq) {
> + spin_lock(&devfreq->stats_lock);
> + devfreq->last_stat_updated = cur_time;
> + spin_unlock(&devfreq->stats_lock);
> + return 0;
> + }
>
> prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
> +
> + spin_lock(&devfreq->stats_lock);
> if (prev_lev < 0) {
> ret = prev_lev;
> goto out;
> @@ -174,7 +180,6 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>
> devfreq->time_in_state[prev_lev] +=
> cur_time - devfreq->last_stat_updated;
> -
> lev = devfreq_get_freq_level(devfreq, freq);
> if (lev < 0) {
> ret = lev;
> @@ -189,6 +194,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>
> out:
> devfreq->last_stat_updated = cur_time;
> + spin_unlock(&devfreq->stats_lock);
> return ret;
> }
> EXPORT_SYMBOL(devfreq_update_status);
> @@ -478,7 +484,9 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
> queue_delayed_work(devfreq_wq, &devfreq->work,
> msecs_to_jiffies(devfreq->profile->polling_ms));
>
> + spin_lock(&devfreq->stats_lock);
> devfreq->last_stat_updated = get_jiffies_64();
> + spin_unlock(&devfreq->stats_lock);
> devfreq->stop_polling = false;
>
> if (devfreq->profile->get_cur_freq &&
> @@ -707,6 +715,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
> }
>
> devfreq->last_stat_updated = get_jiffies_64();
> + spin_lock_init(&devfreq->stats_lock);
>
> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>
> @@ -1405,6 +1414,8 @@ static ssize_t trans_stat_show(struct device *dev,
>
> len = sprintf(buf, " From : To\n");
> len += sprintf(buf + len, " :");
> +
> + spin_lock(&devfreq->stats_lock);
> for (i = 0; i < max_state; i++)
> len += sprintf(buf + len, "%10lu",
> devfreq->profile->freq_table[i]);
> @@ -1429,6 +1440,7 @@ static ssize_t trans_stat_show(struct device *dev,
>
> len += sprintf(buf + len, "Total transition : %u\n",
> devfreq->total_trans);
> + spin_unlock(&devfreq->stats_lock);
> return len;
> }
> static DEVICE_ATTR_RO(trans_stat);
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index b81a86e47fb9..a344e0be99f3 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -135,6 +135,8 @@ struct devfreq_dev_profile {
> * @trans_table: Statistics of devfreq transitions
> * @time_in_state: Statistics of devfreq states
> * @last_stat_updated: The last time stat updated
> + * @stats_lock: Lock protecting trans_table, time_in_state, last_time
> + * and total_trans used for statistics
> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> *
> * This structure stores the devfreq information for a give device.
> @@ -176,6 +178,7 @@ struct devfreq {
> unsigned int *trans_table;
> u64 *time_in_state;
> unsigned long long last_stat_updated;
> + spinlock_t stats_lock;
>
> struct srcu_notifier_head transition_notifier_list;
> };
>