From: Viresh Kumar <viresh.kumar@linaro.org>
To: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>,
Linux PM list <linux-pm@vger.kernel.org>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 1/2] cpufreq: governor: Fix race in dbs_update_util_handler()
Date: Mon, 22 Feb 2016 18:34:07 +0530 [thread overview]
Message-ID: <20160222130407.GP28226@vireshk-i7> (raw)
In-Reply-To: <CAJZ5v0jNBWYhuFud7-P1J2cc0e7Ex2F+YYE5J_qq2bEweLe8jQ@mail.gmail.com>
On 22-02-16, 13:26, Rafael J. Wysocki wrote:
> On Mon, Feb 22, 2016 at 6:23 AM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > On 21-02-16, 03:14, Rafael J. Wysocki wrote:
> >> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>
> >> There is a scenarion that may lead to undesired results in
> >
> > scenario
> >
> >> dbs_update_util_handler(). Namely, if two CPUs sharing a policy
> >> enter the funtion at the same time, pass the sample delay check
> >> and then one of them is stalled until dbs_work_handler() (queued
> >> up by the other CPU) clears the work counter, it may update the
> >> work counter and queue up another work item prematurely.
> >>
> >> To prevent that from happening, use the observation that the CPU
> >> queuing up a work item in dbs_update_util_handler() updates the
> >> last sample time. This means that if another CPU was stalling after
> >> passing the sample delay check and now successfully updated the work
> >> counter as a result of the race described above, it will see the new
> >> value of the last sample time which is different from what it used in
> >> the sample delay check before. If that happens, the sample delay
> >> check passed previously is not valid any more, so the CPU should not
> >> continue, but leaving the funtion at that point might miss an
> >> opportunity to take the next sample, so simply clear the work
> >> counter and jump to the beginning of the function in that case.
> >>
> >> Fixes: f17cbb53783c (cpufreq: governor: Avoid atomic operations in hot paths)
> >> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> ---
> >> drivers/cpufreq/cpufreq_governor.c | 22 +++++++++++++++++-----
> >> 1 file changed, 17 insertions(+), 5 deletions(-)
> >>
> >> Index: linux-pm/drivers/cpufreq/cpufreq_governor.c
> >> ===================================================================
> >> --- linux-pm.orig/drivers/cpufreq/cpufreq_governor.c
> >> +++ linux-pm/drivers/cpufreq/cpufreq_governor.c
> >> @@ -341,8 +341,9 @@ static void dbs_update_util_handler(stru
> >> {
> >> struct cpu_dbs_info *cdbs = container_of(data, struct cpu_dbs_info, update_util);
> >> struct policy_dbs_info *policy_dbs = cdbs->policy_dbs;
> >> - u64 delta_ns;
> >> + u64 delta_ns, lst;
> >>
> >> + start:
> >> /*
> >> * The work may not be allowed to be queued up right now.
> >> * Possible reasons:
> >> @@ -357,7 +358,8 @@ static void dbs_update_util_handler(stru
> >> * of sample_delay_ns used in the computation may be stale.
> >> */
> >> smp_rmb();
> >> - delta_ns = time - policy_dbs->last_sample_time;
> >> + lst = ACCESS_ONCE(policy_dbs->last_sample_time);
> >
> > The comment on the top of ACCESS_ONCE() asks us to use READ_ONCE() if possible.
>
> I forgot about this one, thanks!
>
> >> + delta_ns = time - lst;
> >> if ((s64)delta_ns < policy_dbs->sample_delay_ns)
> >> return;
> >>
> >> @@ -366,9 +368,19 @@ static void dbs_update_util_handler(stru
> >> * at this point. Otherwise, we need to ensure that only one of the
> >> * CPUs sharing the policy will do that.
> >> */
> >> - if (policy_dbs->is_shared &&
> >> - !atomic_add_unless(&policy_dbs->work_count, 1, 1))
> >> - return;
> >> + if (policy_dbs->is_shared) {
> >> + if (!atomic_add_unless(&policy_dbs->work_count, 1, 1))
> >> + return;
> >> +
> >> + /*
> >> + * If another CPU updated last_sample_time in the meantime, we
> >> + * shouldn't be here, so clear the work counter and try again.
> >> + */
> >> + if (unlikely(lst != ACCESS_ONCE(policy_dbs->last_sample_time))) {
> >> + atomic_set(&policy_dbs->work_count, 0);
> >> + goto start;
> >> + }
> >
> > I think we should be doing this here:
> >
> > delta_ns = time - ACCESS_ONCE(policy_dbs->last_sample_time);
> > if ((s64)delta_ns < policy_dbs->sample_delay_ns) {
> > atomic_set(&policy_dbs->work_count, 0);
> > return;
> > }
> >
> > There is no point running the routine again, we already have ->work_count
> > incremented for us, lets do the check right now.
>
> No, we need to check work_in_progress too.
Then maybe move first half of this routine into a separate function
and call it from the beginning and here ?
--
viresh
next prev parent reply other threads:[~2016-02-22 13:04 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-21 2:10 [PATCH 0/2] cpufreq: governor: Fixups on top of recent changes Rafael J. Wysocki
2016-02-21 2:14 ` [PATCH 1/2] cpufreq: governor: Fix race in dbs_update_util_handler() Rafael J. Wysocki
2016-02-22 5:23 ` Viresh Kumar
2016-02-22 12:26 ` Rafael J. Wysocki
2016-02-22 13:04 ` Viresh Kumar [this message]
2016-02-22 13:30 ` Rafael J. Wysocki
2016-02-22 13:14 ` [PATCH v2 " Rafael J. Wysocki
2016-02-22 13:45 ` Viresh Kumar
2016-02-21 2:15 ` [PATCH 2/2] cpufreq: governor: Make gov_set_update_util() static Rafael J. Wysocki
2016-02-22 5:24 ` Viresh Kumar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160222130407.GP28226@vireshk-i7 \
--to=viresh.kumar@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=rafael@kernel.org \
--cc=rjw@rjwysocki.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).