From patchwork Tue Jan 7 01:40:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 22897 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id C6D5423A3F for ; Tue, 7 Jan 2014 01:40:25 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id at1sf97374446iec.3 for ; Mon, 06 Jan 2014 17:40:24 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=B8Ddt6OKnZPLLaj6X/A1/BYq+Ob7VVwSXsV5ohTaCu4=; b=PhtRISwMz4AGssIvt2J9gwPurr28PAvut0ina+OZ+RyiPdTygreX/CHkk+R5jv48zU mgOstYqX5p8Wa/JPXCfGXS0/y1rFqDAVhtwgyKwMeljxdRw20SscBHPuvPalt55LSPI/ ffWsThYTidAL5fBZOtiTQ1WtJ4E09UsEYFgOQrQHZQAy2GA+ZF5WptU3grSB+BSnb4cf ZSjg2mHJtSbb2dq9/EdEdgYCkhgJdAUqcdN5MUe9GNn+XB7FbwXJ6MtYRBvFj41QVcei WUQ+3YokjHJztzNoSdSnIh8ZrcxYOUmjHKjnmn88HlSGwp3/C1FUUzuB80umsVMhyaoy L7Gw== X-Gm-Message-State: ALoCoQmdPYtcg7l9qUDJzxf6s2WDQiSg8hHNpZTISQg8sQCxGhCuPfbBplB2+llS4QUzbYaoS7hu X-Received: by 10.50.12.68 with SMTP id w4mr11847473igb.0.1389058824722; Mon, 06 Jan 2014 17:40:24 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.127.175 with SMTP id nh15ls6175174qeb.9.gmail; Mon, 06 Jan 2014 17:40:24 -0800 (PST) X-Received: by 10.221.24.139 with SMTP id re11mr5619521vcb.20.1389058824575; Mon, 06 Jan 2014 17:40:24 -0800 (PST) Received: from mail-ve0-f169.google.com (mail-ve0-f169.google.com [209.85.128.169]) by mx.google.com with ESMTPS id kl1si8279888vdb.107.2014.01.06.17.40.24 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 06 Jan 2014 17:40:24 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.169 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.169; Received: by mail-ve0-f169.google.com with SMTP id c14so9883877vea.28 for ; Mon, 06 Jan 2014 17:40:24 -0800 (PST) X-Received: by 10.220.1.131 with SMTP id 3mr61649532vcf.4.1389058824441; Mon, 06 Jan 2014 17:40:24 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.59.13.131 with SMTP id ey3csp130007ved; Mon, 6 Jan 2014 17:40:23 -0800 (PST) X-Received: by 10.68.228.138 with SMTP id si10mr131971987pbc.13.1389058823069; Mon, 06 Jan 2014 17:40:23 -0800 (PST) Received: from mail-pb0-f42.google.com (mail-pb0-f42.google.com [209.85.160.42]) by mx.google.com with ESMTPS id ng9si27519112pbc.166.2014.01.06.17.40.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 06 Jan 2014 17:40:23 -0800 (PST) Received-SPF: neutral (google.com: 209.85.160.42 is neither permitted nor denied by best guess record for domain of viresh.kumar@linaro.org) client-ip=209.85.160.42; Received: by mail-pb0-f42.google.com with SMTP id uo5so19260575pbc.15 for ; Mon, 06 Jan 2014 17:40:22 -0800 (PST) X-Received: by 10.66.227.104 with SMTP id rz8mr1768309pac.74.1389058822503; Mon, 06 Jan 2014 17:40:22 -0800 (PST) Received: from localhost ([122.167.240.254]) by mx.google.com with ESMTPSA id by1sm131798890pbd.25.2014.01.06.17.40.18 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 06 Jan 2014 17:40:21 -0800 (PST) From: Viresh Kumar To: rjw@rjwysocki.net Cc: linaro-kernel@lists.linaro.org, patches@linaro.org, cpufreq@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Viresh Kumar Subject: [PATCH Resend 1/4] cpufreq: stats: handle cpufreq_unregister_driver() and suspend/resume properly Date: Tue, 7 Jan 2014 07:10:10 +0530 Message-Id: X-Mailer: git-send-email 1.7.12.rc2.18.g61b472e X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: viresh.kumar@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.169 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , There are several problems cpufreq stats in the way it handles cpufreq_unregister_driver() and suspend/resume.. - We must not loose data collected so far when suspend/resume happens and so stats directories must not be removed/allocated during these operations, Which is done currently. - cpufreq_stat has registered notifiers with both cpufreq and hotplug. It adds sysfs stats directory with a cpufreq notifier: CPUFREQ_NOTIFY and removes this directory with a notifier from hotplug core. In case cpufreq_unregister_driver() is called (on rmmod cpufreq driver), stats directories per cpu aren't removed as CPUs are still online. The only call cpufreq_stats gets is cpufreq_stats_update_policy_cpu for all CPUs except the last of each policy. And pointer to stat information is stored in the entry for last cpu in per-cpu cpufreq_stats_table. But policy structure would be freed inside cpufreq core and so that will result in memory leak inside cpufreq stats (as we are never freeing memory for stats). Now if we again insert the module cpufreq_register_driver() will be called and we will again allocate stats data and put it on for first cpu of every policy. In case we only have a single cpu per policy we will return with a error from cpufreq_stats_create_table() due to below code: if (per_cpu(cpufreq_stats_table, cpu)) return -EBUSY; And so probably cpufreq stats directory would show up anymore (as it was added inside last policies->kobj which doesn't exist anymore). I haven't tested it though. Also the values in stats files wouldn't be refreshed as we are using the earlier stats structure. - CPUFREQ_NOTIFY is called from cpufreq_set_policy() which is called for scenarios where we don't really want cpufreq_stat_notifier_policy() to get called. For example whenever we are changing anything related to a policy: min/max/current freq, etc.. cpufreq_set_policy() is called and so cpufreq stats is notified. Where we don't do any useful stuff other than simply returning with -EBUSY from cpufreq_stats_create_table(). And so this isn't the right notifier that cpufreq stats.. Due to all above reasons this patch does following changes: - Add new notifiers CPUFREQ_CREATE_POLICY and CPUFREQ_REMOVE_POLICY, which are only called when policy is created/destroyed. They aren't called for suspend/resume paths.. - Use these notifiers in cpufreq_stat_notifier_policy() to create/destory stats sysfs entries. And so cpufreq_unregister_driver() or suspend/resume shouldn't be a problem for cpufreq_stats. - Return early from cpufreq_stat_cpu_callback() for suspend/resume sequence, so that we don't free stats structure. Acked-and-tested-by: Nicolas Pitre Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 5 +++++ drivers/cpufreq/cpufreq_stats.c | 24 +++++++++++++++++------- include/linux/cpufreq.h | 2 ++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3509ca0..1afbe52 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -943,6 +943,9 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy) struct kobject *kobj; struct completion *cmp; + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_REMOVE_POLICY, policy); + down_read(&policy->rwsem); kobj = &policy->kobj; cmp = &policy->kobj_unregister; @@ -1148,6 +1151,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, ret = cpufreq_add_dev_interface(policy, dev); if (ret) goto err_out_unregister; + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_CREATE_POLICY, policy); } write_lock_irqsave(&cpufreq_driver_lock, flags); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 4cf0d28..0f71562 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -277,7 +277,7 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { - int ret; + int ret = 0; struct cpufreq_policy *policy = data; struct cpufreq_frequency_table *table; unsigned int cpu = policy->cpu; @@ -287,15 +287,21 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, return 0; } - if (val != CPUFREQ_NOTIFY) - return 0; table = cpufreq_frequency_get_table(cpu); if (!table) return 0; - ret = cpufreq_stats_create_table(policy, table); - if (ret) - return ret; - return 0; + + if (val == CPUFREQ_CREATE_POLICY) + ret = cpufreq_stats_create_table(policy, table); + else if (val == CPUFREQ_REMOVE_POLICY) { + /* This might already be freed by cpu hotplug notifier */ + if (per_cpu(cpufreq_stats_table, cpu)) { + cpufreq_stats_free_sysfs(cpu); + cpufreq_stats_free_table(cpu); + } + } + + return ret; } static int cpufreq_stat_notifier_trans(struct notifier_block *nb, @@ -340,6 +346,10 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; + /* Don't free/allocate stats during suspend/resume */ + if (action & CPU_TASKS_FROZEN) + return 0; + switch (action) { case CPU_DOWN_PREPARE: cpufreq_stats_free_sysfs(cpu); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index aaf800e..bb727eb 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -308,6 +308,8 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy) #define CPUFREQ_NOTIFY (2) #define CPUFREQ_START (3) #define CPUFREQ_UPDATE_POLICY_CPU (4) +#define CPUFREQ_CREATE_POLICY (5) +#define CPUFREQ_REMOVE_POLICY (6) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);