diff mbox

suspend regression in 4.1-rc1

Message ID 20150518093150.GC21418@twins.programming.kicks-ass.net (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Peter Zijlstra May 18, 2015, 9:31 a.m. UTC
On Mon, May 18, 2015 at 11:03:37AM +0200, Michal Hocko wrote:
> This doesn't hang anymore. I've just had to move the mutex definition
> up to make it compile. So feel free to add my

I've also fixed a lock leak, see goto unlock :-)

> Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>

*blink* that actually fixed it..

That somewhat leaves me at a loss explaining how s2r was failing.

---
Subject: watchdog: Fix merge 'conflict'

Two watchdog changes that came through different trees had a non
conflicting conflict, that is, one changed the semantics of a variable
but no actual code conflict happened. So the merge appeared fine, but
the resulting code did not behave as expected.

Commit 195daf665a62 ("watchdog: enable the new user interface of the
watchdog mechanism") changes the semantics of watchdog_user_enabled,
which thereafter is only used by the functions introduced by
b3738d293233 ("watchdog: Add watchdog enable/disable all functions").

There further appears to be a distinct lack of serialization between
setting and using watchdog_enabled, so perhaps we should wrap the
{en,dis}able_all() things in watchdog_proc_mutex.

This patch fixes a s2r failure reported by Michal; which I cannot
readily explain. But this does make the code internally consistent
again.

Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 kernel/watchdog.c |   20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Ulrich Obergfell May 18, 2015, 10:56 a.m. UTC | #1
Peter,

please see my comments in-line.

Regards,

Uli

----- Original Message -----
From: "Peter Zijlstra" <peterz@infradead.org>
To: "Michal Hocko" <mhocko@suse.cz>
[...]
> On Mon, May 18, 2015 at 11:03:37AM +0200, Michal Hocko wrote:
>> This doesn't hang anymore. I've just had to move the mutex definition
>> up to make it compile. So feel free to add my
>
> I've also fixed a lock leak, see goto unlock :-)
>
>> Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
>
> *blink* that actually fixed it..
>
> That somewhat leaves me at a loss explaining how s2r was failing.
>
> ---
> Subject: watchdog: Fix merge 'conflict'
>
> Two watchdog changes that came through different trees had a non
> conflicting conflict, that is, one changed the semantics of a variable
> but no actual code conflict happened. So the merge appeared fine, but
> the resulting code did not behave as expected.
>
> Commit 195daf665a62 ("watchdog: enable the new user interface of the
> watchdog mechanism") changes the semantics of watchdog_user_enabled,
> which thereafter is only used by the functions introduced by
> b3738d293233 ("watchdog: Add watchdog enable/disable all functions").

Don and I already posted a patch in April to address this:

https://lkml.org/lkml/2015/4/22/306
http://ozlabs.org/~akpm/mmots/broken-out/watchdog-fix-watchdog_nmi_enable_all.patch

> There further appears to be a distinct lack of serialization between
> setting and using watchdog_enabled, so perhaps we should wrap the
> {en,dis}able_all() things in watchdog_proc_mutex.

As I understand it, the {en,dis}able_all() functions are only called early
at kernel startup, so I do not see how they could be racing with watchdog
code that is executed in the context of write() system calls to parameters
in /proc/sys/kernel. Please see also my earlier reply to Michal for further
details: http://marc.info/?l=linux-pm&m=143194387208250&w=2

Do we really need synchronization here?

> This patch fixes a s2r failure reported by Michal; which I cannot
> readily explain. But this does make the code internally consistent
> again.
>
> Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
>  kernel/watchdog.c |   20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/watchdog.c b/kernel/watchdog.c
> index 2316f50..506edcc5 100644
> --- a/kernel/watchdog.c
> +++ b/kernel/watchdog.c
> @@ -41,6 +41,8 @@
>  #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
>  #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
> 
> +static DEFINE_MUTEX(watchdog_proc_mutex);
> +
>  #ifdef CONFIG_HARDLOCKUP_DETECTOR
>  static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
>  #else
> @@ -608,26 +610,36 @@ void watchdog_nmi_enable_all(void)
>  {
>          int cpu;
> 
> -        if (!watchdog_user_enabled)
> -                return;
> +        mutex_lock(&watchdog_proc_mutex);
> +
> +        if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
> +                goto unlock;
> 
>          get_online_cpus();
>          for_each_online_cpu(cpu)
>                  watchdog_nmi_enable(cpu);
>          put_online_cpus();
> +
> +unlock:
> +        mutex_lock(&watchdog_proc_mutex);
>  }
> 
>  void watchdog_nmi_disable_all(void)
>  {
>          int cpu;
> 
> +        mutex_lock(&watchdog_proc_mutex);
> +
>          if (!watchdog_running)
> -                return;
> +                goto unlock;
> 
>          get_online_cpus();
>          for_each_online_cpu(cpu)
>                  watchdog_nmi_disable(cpu);
>          put_online_cpus();
> +
> +unlock:
> +        mutex_unlock(&watchdog_proc_mutex);
>  }
>  #else
>  static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
> @@ -744,8 +756,6 @@ static int proc_watchdog_update(void)
> 
>  }
> 
> -static DEFINE_MUTEX(watchdog_proc_mutex);
> -
>  /*
>   * common function for watchdog, nmi_watchdog and soft_watchdog parameter
>   *
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Peter Zijlstra May 18, 2015, 11:05 a.m. UTC | #2
On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
> > Subject: watchdog: Fix merge 'conflict'
> >
> > Two watchdog changes that came through different trees had a non
> > conflicting conflict, that is, one changed the semantics of a variable
> > but no actual code conflict happened. So the merge appeared fine, but
> > the resulting code did not behave as expected.
> >
> > Commit 195daf665a62 ("watchdog: enable the new user interface of the
> > watchdog mechanism") changes the semantics of watchdog_user_enabled,
> > which thereafter is only used by the functions introduced by
> > b3738d293233 ("watchdog: Add watchdog enable/disable all functions").
> 
> Don and I already posted a patch in April to address this:
> 
> https://lkml.org/lkml/2015/4/22/306
> http://ozlabs.org/~akpm/mmots/broken-out/watchdog-fix-watchdog_nmi_enable_all.patch

Yeah, but it seems to have gotten lost on its way to Linus.

> > There further appears to be a distinct lack of serialization between
> > setting and using watchdog_enabled, so perhaps we should wrap the
> > {en,dis}able_all() things in watchdog_proc_mutex.
> 
> As I understand it, the {en,dis}able_all() functions are only called early
> at kernel startup, so I do not see how they could be racing with watchdog
> code that is executed in the context of write() system calls to parameters
> in /proc/sys/kernel. Please see also my earlier reply to Michal for further
> details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
> 
> Do we really need synchronization here?

Same argument as in my previous email; its best to implement exposed
functions fully and correctly, irrespective of their usage sites.

It costs little extra and might safe a few hairs down the lined. None of
this is performance critical.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephane Eranian May 18, 2015, 12:13 p.m. UTC | #3
Hi,

On Mon, May 18, 2015 at 4:05 AM, Peter Zijlstra <peterz@infradead.org> wrote:
> On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
>> > Subject: watchdog: Fix merge 'conflict'
>> >
>> > Two watchdog changes that came through different trees had a non
>> > conflicting conflict, that is, one changed the semantics of a variable
>> > but no actual code conflict happened. So the merge appeared fine, but
>> > the resulting code did not behave as expected.
>> >
>> > Commit 195daf665a62 ("watchdog: enable the new user interface of the
>> > watchdog mechanism") changes the semantics of watchdog_user_enabled,
>> > which thereafter is only used by the functions introduced by
>> > b3738d293233 ("watchdog: Add watchdog enable/disable all functions").
>>
>> Don and I already posted a patch in April to address this:
>>
>> https://lkml.org/lkml/2015/4/22/306
>> http://ozlabs.org/~akpm/mmots/broken-out/watchdog-fix-watchdog_nmi_enable_all.patch
>
> Yeah, but it seems to have gotten lost on its way to Linus.
>
>> > There further appears to be a distinct lack of serialization between
>> > setting and using watchdog_enabled, so perhaps we should wrap the
>> > {en,dis}able_all() things in watchdog_proc_mutex.
>>
>> As I understand it, the {en,dis}able_all() functions are only called early
>> at kernel startup, so I do not see how they could be racing with watchdog
>> code that is executed in the context of write() system calls to parameters
>> in /proc/sys/kernel. Please see also my earlier reply to Michal for further
>> details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
>>
>> Do we really need synchronization here?
>
> Same argument as in my previous email; its best to implement exposed
> functions fully and correctly, irrespective of their usage sites.
>
> It costs little extra and might safe a few hairs down the lined. None of
> this is performance critical.

I cannot reproduce this problem on my T430s running tip.git at 4.1-rc3.

The thing about b37609c30e41 is that is introduces a deferred initcall
for perf_events. It adds an subsys_initcall after the default initialization
of perf_events The reason is that the fixup_ht_bug() needs to wait until
cpu topology is setup before proceeding. Thus by the time
watchdog_nmi_disable_all() is called from that function, the kernel
may be multi-cpu already. Thus, there may be a race.




commit b37609c30e41264c4df4acff78abfc894499a49b
Author: Stephane Eranian <eranian@google.com>
Date:   Mon Nov 17 20:07:04 2014 +0100
   perf/x86/intel: Make the HT bug workaround conditional on HT enabled
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Don Zickus May 18, 2015, 2:20 p.m. UTC | #4
On Mon, May 18, 2015 at 11:31:50AM +0200, Peter Zijlstra wrote:
> On Mon, May 18, 2015 at 11:03:37AM +0200, Michal Hocko wrote:
> > This doesn't hang anymore. I've just had to move the mutex definition
> > up to make it compile. So feel free to add my
> 
> I've also fixed a lock leak, see goto unlock :-)
> 
> > Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
> 
> *blink* that actually fixed it..
> 
> That somewhat leaves me at a loss explaining how s2r was failing.
> 
> ---
> Subject: watchdog: Fix merge 'conflict'
> 
> Two watchdog changes that came through different trees had a non
> conflicting conflict, that is, one changed the semantics of a variable
> but no actual code conflict happened. So the merge appeared fine, but
> the resulting code did not behave as expected.
> 
> Commit 195daf665a62 ("watchdog: enable the new user interface of the
> watchdog mechanism") changes the semantics of watchdog_user_enabled,
> which thereafter is only used by the functions introduced by
> b3738d293233 ("watchdog: Add watchdog enable/disable all functions").
> 
> There further appears to be a distinct lack of serialization between
> setting and using watchdog_enabled, so perhaps we should wrap the
> {en,dis}able_all() things in watchdog_proc_mutex.
> 
> This patch fixes a s2r failure reported by Michal; which I cannot
> readily explain. But this does make the code internally consistent
> again.

I agree with Peter's locking approach.  We need to do better locking the
variables here.  Poking around the code I see too many variables being
exposed sadly.

Thanks Peter!

Andrew, this patch can replace 'watchdog-fix-watchdog_nmi_enable_all.patch'
on your queue.

Acked-by: Don Zickus <dzickus@redhat.com>
> 
> Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
>  kernel/watchdog.c |   20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
> 
> diff --git a/kernel/watchdog.c b/kernel/watchdog.c
> index 2316f50..506edcc5 100644
> --- a/kernel/watchdog.c
> +++ b/kernel/watchdog.c
> @@ -41,6 +41,8 @@
>  #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
>  #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
>  
> +static DEFINE_MUTEX(watchdog_proc_mutex);
> +
>  #ifdef CONFIG_HARDLOCKUP_DETECTOR
>  static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
>  #else
> @@ -608,26 +610,36 @@ void watchdog_nmi_enable_all(void)
>  {
>  	int cpu;
>  
> -	if (!watchdog_user_enabled)
> -		return;
> +	mutex_lock(&watchdog_proc_mutex);
> +
> +	if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
> +		goto unlock;
>  
>  	get_online_cpus();
>  	for_each_online_cpu(cpu)
>  		watchdog_nmi_enable(cpu);
>  	put_online_cpus();
> +
> +unlock:
> +	mutex_lock(&watchdog_proc_mutex);
>  }
>  
>  void watchdog_nmi_disable_all(void)
>  {
>  	int cpu;
>  
> +	mutex_lock(&watchdog_proc_mutex);
> +
>  	if (!watchdog_running)
> -		return;
> +		goto unlock;
>  
>  	get_online_cpus();
>  	for_each_online_cpu(cpu)
>  		watchdog_nmi_disable(cpu);
>  	put_online_cpus();
> +
> +unlock:
> +	mutex_unlock(&watchdog_proc_mutex);
>  }
>  #else
>  static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
> @@ -744,8 +756,6 @@ static int proc_watchdog_update(void)
>  
>  }
>  
> -static DEFINE_MUTEX(watchdog_proc_mutex);
> -
>  /*
>   * common function for watchdog, nmi_watchdog and soft_watchdog parameter
>   *
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Don Zickus May 18, 2015, 2:26 p.m. UTC | #5
On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
> 
> > There further appears to be a distinct lack of serialization between
> > setting and using watchdog_enabled, so perhaps we should wrap the
> > {en,dis}able_all() things in watchdog_proc_mutex.
> 
> As I understand it, the {en,dis}able_all() functions are only called early
> at kernel startup, so I do not see how they could be racing with watchdog
> code that is executed in the context of write() system calls to parameters
> in /proc/sys/kernel. Please see also my earlier reply to Michal for further
> details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
> 
> Do we really need synchronization here?

As Peter said we have to focus on doing things correctly and not based on
what is currently.

During s2ram, I believe all the threads get parked and then unparked during
resume.  I am wondering if the race happens there, threads get unparked and
stomp on each other when watchdog_nmi_enable_all() is called.  (or vice
versa on the way down).  I think during boot the cpu bring up is slow enough
that the race doesn't happen, but s2ram is alot quicker.  My guess.

Cheers,
Don

> 
> > This patch fixes a s2r failure reported by Michal; which I cannot
> > readily explain. But this does make the code internally consistent
> > again.
> >
> > Reported-and-tested-by: Michal Hocko <mhocko@suse.cz>
> > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> > ---
> >  kernel/watchdog.c |   20 +++++++++++++++-----
> >  1 file changed, 15 insertions(+), 5 deletions(-)
> >
> > diff --git a/kernel/watchdog.c b/kernel/watchdog.c
> > index 2316f50..506edcc5 100644
> > --- a/kernel/watchdog.c
> > +++ b/kernel/watchdog.c
> > @@ -41,6 +41,8 @@
> >  #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
> >  #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
> > 
> > +static DEFINE_MUTEX(watchdog_proc_mutex);
> > +
> >  #ifdef CONFIG_HARDLOCKUP_DETECTOR
> >  static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
> >  #else
> > @@ -608,26 +610,36 @@ void watchdog_nmi_enable_all(void)
> >  {
> >          int cpu;
> > 
> > -        if (!watchdog_user_enabled)
> > -                return;
> > +        mutex_lock(&watchdog_proc_mutex);
> > +
> > +        if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
> > +                goto unlock;
> > 
> >          get_online_cpus();
> >          for_each_online_cpu(cpu)
> >                  watchdog_nmi_enable(cpu);
> >          put_online_cpus();
> > +
> > +unlock:
> > +        mutex_lock(&watchdog_proc_mutex);
> >  }
> > 
> >  void watchdog_nmi_disable_all(void)
> >  {
> >          int cpu;
> > 
> > +        mutex_lock(&watchdog_proc_mutex);
> > +
> >          if (!watchdog_running)
> > -                return;
> > +                goto unlock;
> > 
> >          get_online_cpus();
> >          for_each_online_cpu(cpu)
> >                  watchdog_nmi_disable(cpu);
> >          put_online_cpus();
> > +
> > +unlock:
> > +        mutex_unlock(&watchdog_proc_mutex);
> >  }
> >  #else
> >  static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
> > @@ -744,8 +756,6 @@ static int proc_watchdog_update(void)
> > 
> >  }
> > 
> > -static DEFINE_MUTEX(watchdog_proc_mutex);
> > -
> >  /*
> >   * common function for watchdog, nmi_watchdog and soft_watchdog parameter
> >   *
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Hocko May 18, 2015, 2:41 p.m. UTC | #6
On Mon 18-05-15 10:26:07, Don Zickus wrote:
> On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
> > 
> > > There further appears to be a distinct lack of serialization between
> > > setting and using watchdog_enabled, so perhaps we should wrap the
> > > {en,dis}able_all() things in watchdog_proc_mutex.
> > 
> > As I understand it, the {en,dis}able_all() functions are only called early
> > at kernel startup, so I do not see how they could be racing with watchdog
> > code that is executed in the context of write() system calls to parameters
> > in /proc/sys/kernel. Please see also my earlier reply to Michal for further
> > details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
> > 
> > Do we really need synchronization here?
> 
> As Peter said we have to focus on doing things correctly and not based on
> what is currently.
> 
> During s2ram, I believe all the threads get parked and then unparked during
> resume.  I am wondering if the race happens there, threads get unparked and
> stomp on each other when watchdog_nmi_enable_all() is called.

Wouldn't that cause an issue during freezer mode of pm_test? I can see
it much later in the processors mode.
Don Zickus May 18, 2015, 3:45 p.m. UTC | #7
On Mon, May 18, 2015 at 04:41:37PM +0200, Michal Hocko wrote:
> On Mon 18-05-15 10:26:07, Don Zickus wrote:
> > On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
> > > 
> > > > There further appears to be a distinct lack of serialization between
> > > > setting and using watchdog_enabled, so perhaps we should wrap the
> > > > {en,dis}able_all() things in watchdog_proc_mutex.
> > > 
> > > As I understand it, the {en,dis}able_all() functions are only called early
> > > at kernel startup, so I do not see how they could be racing with watchdog
> > > code that is executed in the context of write() system calls to parameters
> > > in /proc/sys/kernel. Please see also my earlier reply to Michal for further
> > > details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
> > > 
> > > Do we really need synchronization here?
> > 
> > As Peter said we have to focus on doing things correctly and not based on
> > what is currently.
> > 
> > During s2ram, I believe all the threads get parked and then unparked during
> > resume.  I am wondering if the race happens there, threads get unparked and
> > stomp on each other when watchdog_nmi_enable_all() is called.
> 
> Wouldn't that cause an issue during freezer mode of pm_test? I can see
> it much later in the processors mode.

I am not familiar with the freeze mode of pm_test.  But I believe the
race only happens with cpu0.  I would have thought cpu0 is slower to stop in
freezer mode than in s2ram.  Again, this was just my initial guess at the
race problem. :-(

Peter seems to have a patch (and Uli too) that addresses this problem, so
not sure how much time to focus on figuring this out.

Cheers,
Don
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Torvalds May 18, 2015, 5:10 p.m. UTC | #8
On Mon, May 18, 2015 at 2:31 AM, Peter Zijlstra <peterz@infradead.org> wrote:
> Subject: watchdog: Fix merge 'conflict'
>
> Two watchdog changes that came through different trees had a non
> conflicting conflict, that is, one changed the semantics of a variable
> but no actual code conflict happened. So the merge appeared fine, but
> the resulting code did not behave as expected.

Ok, I see that people are still discussing this, but I'll apply it
as-is since I want to get rc4 out the door, and I guess people can
tweak this if there's anything else we want to do longer-term.

             Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Hocko May 19, 2015, 5:20 p.m. UTC | #9
On Mon 18-05-15 11:45:31, Don Zickus wrote:
> On Mon, May 18, 2015 at 04:41:37PM +0200, Michal Hocko wrote:
> > On Mon 18-05-15 10:26:07, Don Zickus wrote:
> > > On Mon, May 18, 2015 at 06:56:46AM -0400, Ulrich Obergfell wrote:
> > > > 
> > > > > There further appears to be a distinct lack of serialization between
> > > > > setting and using watchdog_enabled, so perhaps we should wrap the
> > > > > {en,dis}able_all() things in watchdog_proc_mutex.
> > > > 
> > > > As I understand it, the {en,dis}able_all() functions are only called early
> > > > at kernel startup, so I do not see how they could be racing with watchdog
> > > > code that is executed in the context of write() system calls to parameters
> > > > in /proc/sys/kernel. Please see also my earlier reply to Michal for further
> > > > details: http://marc.info/?l=linux-pm&m=143194387208250&w=2
> > > > 
> > > > Do we really need synchronization here?
> > > 
> > > As Peter said we have to focus on doing things correctly and not based on
> > > what is currently.
> > > 
> > > During s2ram, I believe all the threads get parked and then unparked during
> > > resume.  I am wondering if the race happens there, threads get unparked and
> > > stomp on each other when watchdog_nmi_enable_all() is called.
> > 
> > Wouldn't that cause an issue during freezer mode of pm_test? I can see
> > it much later in the processors mode.
> 
> I am not familiar with the freeze mode of pm_test. 

AFAIU only suspend_prepare is called for this mode. This will trigger
pm_notifier_call_chain(PM_SUSPEND_PREPARE) and suspend_freeze_processes
which will freeze all the tasks (including kernel threads).

The hang happened with processors mode which means that everything up to
platform mode was OK. Which reduces the area to disable_nonboot_cpus.

I have tried to put some printks around to see where things go wrong but
then I found out that my netconsole doesn't dump them because the
network cards are long suspended. no_console_suspend apparently doesn't
affect netconsole and the laptop doesn't have regular serial console so
I just gave up.
diff mbox

Patch

diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 2316f50..506edcc5 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -41,6 +41,8 @@ 
 #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
 #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
 
+static DEFINE_MUTEX(watchdog_proc_mutex);
+
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 static unsigned long __read_mostly watchdog_enabled = SOFT_WATCHDOG_ENABLED|NMI_WATCHDOG_ENABLED;
 #else
@@ -608,26 +610,36 @@  void watchdog_nmi_enable_all(void)
 {
 	int cpu;
 
-	if (!watchdog_user_enabled)
-		return;
+	mutex_lock(&watchdog_proc_mutex);
+
+	if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
+		goto unlock;
 
 	get_online_cpus();
 	for_each_online_cpu(cpu)
 		watchdog_nmi_enable(cpu);
 	put_online_cpus();
+
+unlock:
+	mutex_lock(&watchdog_proc_mutex);
 }
 
 void watchdog_nmi_disable_all(void)
 {
 	int cpu;
 
+	mutex_lock(&watchdog_proc_mutex);
+
 	if (!watchdog_running)
-		return;
+		goto unlock;
 
 	get_online_cpus();
 	for_each_online_cpu(cpu)
 		watchdog_nmi_disable(cpu);
 	put_online_cpus();
+
+unlock:
+	mutex_unlock(&watchdog_proc_mutex);
 }
 #else
 static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
@@ -744,8 +756,6 @@  static int proc_watchdog_update(void)
 
 }
 
-static DEFINE_MUTEX(watchdog_proc_mutex);
-
 /*
  * common function for watchdog, nmi_watchdog and soft_watchdog parameter
  *