2022-06-17 11:39:29

by Stephane Eranian

[permalink] [raw]
Subject: [RFC] pr_warn_once() issue in x86 MSR extable code

Hi,

Some changes to the way invalid MSR accesses are reported by the kernel is
causing some problems with messages printed on the console.

We have seen several cases of ex_handler_msr() printing invalid MSR
accesses once but
the callstack multiple times causing confusion on the console.

The last time the exception MSR code was modified (5.16) by PeterZ was:

d52a7344bdfa x86/msr: Remove .fixup usage:

if (!safe && wrmsr && pr_warn_once("unchecked MSR access error: ..."))
show_stack_regs(regs);

Note that this code pattern was also present, though in a different
form, before this commit.

The problem here is that another earlier commit (5.13):

a358f40600b3 once: implement DO_ONCE_LITE for non-fast-path "do once"
functionality

Modifies all the pr_*_once() calls to always return true claiming that
no caller is ever
checking the return value of the functions.

This is why we are seeing the callstack printed without the associated
printk() msg.

I believe that having the pr_*_once() functions return true the first
time they are called
is useful especially when extra information, such as callstack, must
be printed to help
track the origin of the problem.

The exception handling code seems to be the only place where the
return value is checked
for pr_warn_once(). A minimal change would be to create another
version of that function
that calls DO_ONCE() instead of DO_ONCE_LITE(), e.g., pr_warn_once_return().

I can post a patch to that effect if we all agree on the approach.

Thanks.


2022-06-17 15:18:23

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [RFC] pr_warn_once() issue in x86 MSR extable code

On Fri, Jun 17, 2022 at 02:08:52PM +0300, Stephane Eranian wrote:
> Hi,
>
> Some changes to the way invalid MSR accesses are reported by the kernel is
> causing some problems with messages printed on the console.
>
> We have seen several cases of ex_handler_msr() printing invalid MSR
> accesses once but
> the callstack multiple times causing confusion on the console.
>
> The last time the exception MSR code was modified (5.16) by PeterZ was:
>
> d52a7344bdfa x86/msr: Remove .fixup usage:
>
> if (!safe && wrmsr && pr_warn_once("unchecked MSR access error: ..."))
> show_stack_regs(regs);
>
> Note that this code pattern was also present, though in a different
> form, before this commit.
>
> The problem here is that another earlier commit (5.13):
>
> a358f40600b3 once: implement DO_ONCE_LITE for non-fast-path "do once"
> functionality
>
> Modifies all the pr_*_once() calls to always return true claiming that
> no caller is ever
> checking the return value of the functions.
>
> This is why we are seeing the callstack printed without the associated
> printk() msg.
>
> I believe that having the pr_*_once() functions return true the first
> time they are called
> is useful especially when extra information, such as callstack, must
> be printed to help
> track the origin of the problem.
>
> The exception handling code seems to be the only place where the
> return value is checked
> for pr_warn_once(). A minimal change would be to create another
> version of that function
> that calls DO_ONCE() instead of DO_ONCE_LITE(), e.g., pr_warn_once_return().
>
> I can post a patch to that effect if we all agree on the approach.
>
> Thanks.

How about something like this?

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index dba2197c05c3..331310c29349 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct exception_table_entry *fixup,
static bool ex_handler_msr(const struct exception_table_entry *fixup,
struct pt_regs *regs, bool wrmsr, bool safe, int reg)
{
- if (!safe && wrmsr &&
- pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, (unsigned int)regs->dx,
- (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && wrmsr)) {
+ pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, (unsigned int)regs->dx,
+ (unsigned int)regs->ax, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

- if (!safe && !wrmsr &&
- pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && !wrmsr)) {
+ pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

if (!wrmsr) {
/* Pretend that the read succeeded and returned 0. */
diff --git a/include/linux/once_lite.h b/include/linux/once_lite.h
index 861e606b820f..63c3bbcef694 100644
--- a/include/linux/once_lite.h
+++ b/include/linux/once_lite.h
@@ -9,15 +9,27 @@
*/
#define DO_ONCE_LITE(func, ...) \
DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
-#define DO_ONCE_LITE_IF(condition, func, ...) \
+
+#define __ONCE_LITE_IF(condition) \
({ \
static bool __section(".data.once") __already_done; \
- bool __ret_do_once = !!(condition); \
+ bool __ret_cond = !!(condition); \
+ bool __ret_once = false; \
\
if (unlikely(__ret_do_once && !__already_done)) { \
__already_done = true; \
- func(__VA_ARGS__); \
+ __ret_once = true; \
} \
+ unlikely(__ret_once); \
+ })
+
+#define DO_ONCE_LITE_IF(condition, func, ...) \
+ ({ \
+ bool __ret_do_once = !!(condition); \
+ \
+ if (__ONCE_LITE_IF(__ret_do_once)) \
+ func(__VA_ARGS__); \
+ \
unlikely(__ret_do_once); \
})

2022-06-22 18:10:49

by Stephane Eranian

[permalink] [raw]
Subject: Re: [RFC] pr_warn_once() issue in x86 MSR extable code

Hi Peter,

Thanks for taking a quick look at this.
I am currently OOO and I cannot test this proposed patch.
I am okay with your suggestion.

Thanks.

On Fri, Jun 17, 2022 at 4:52 PM Peter Zijlstra <[email protected]> wrote:
>
> On Fri, Jun 17, 2022 at 02:08:52PM +0300, Stephane Eranian wrote:
> > Hi,
> >
> > Some changes to the way invalid MSR accesses are reported by the kernel is
> > causing some problems with messages printed on the console.
> >
> > We have seen several cases of ex_handler_msr() printing invalid MSR
> > accesses once but
> > the callstack multiple times causing confusion on the console.
> >
> > The last time the exception MSR code was modified (5.16) by PeterZ was:
> >
> > d52a7344bdfa x86/msr: Remove .fixup usage:
> >
> > if (!safe && wrmsr && pr_warn_once("unchecked MSR access error: ..."))
> > show_stack_regs(regs);
> >
> > Note that this code pattern was also present, though in a different
> > form, before this commit.
> >
> > The problem here is that another earlier commit (5.13):
> >
> > a358f40600b3 once: implement DO_ONCE_LITE for non-fast-path "do once"
> > functionality
> >
> > Modifies all the pr_*_once() calls to always return true claiming that
> > no caller is ever
> > checking the return value of the functions.
> >
> > This is why we are seeing the callstack printed without the associated
> > printk() msg.
> >
> > I believe that having the pr_*_once() functions return true the first
> > time they are called
> > is useful especially when extra information, such as callstack, must
> > be printed to help
> > track the origin of the problem.
> >
> > The exception handling code seems to be the only place where the
> > return value is checked
> > for pr_warn_once(). A minimal change would be to create another
> > version of that function
> > that calls DO_ONCE() instead of DO_ONCE_LITE(), e.g., pr_warn_once_return().
> >
> > I can post a patch to that effect if we all agree on the approach.
> >
> > Thanks.
>
> How about something like this?
>
> diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> index dba2197c05c3..331310c29349 100644
> --- a/arch/x86/mm/extable.c
> +++ b/arch/x86/mm/extable.c
> @@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct exception_table_entry *fixup,
> static bool ex_handler_msr(const struct exception_table_entry *fixup,
> struct pt_regs *regs, bool wrmsr, bool safe, int reg)
> {
> - if (!safe && wrmsr &&
> - pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
> - (unsigned int)regs->cx, (unsigned int)regs->dx,
> - (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
> + if (__ONCE_LITE_IF(!safe && wrmsr)) {
> + pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
> + (unsigned int)regs->cx, (unsigned int)regs->dx,
> + (unsigned int)regs->ax, regs->ip, (void *)regs->ip);
> show_stack_regs(regs);
> + }
>
> - if (!safe && !wrmsr &&
> - pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
> - (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
> + if (__ONCE_LITE_IF(!safe && !wrmsr)) {
> + pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
> + (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
> show_stack_regs(regs);
> + }
>
> if (!wrmsr) {
> /* Pretend that the read succeeded and returned 0. */
> diff --git a/include/linux/once_lite.h b/include/linux/once_lite.h
> index 861e606b820f..63c3bbcef694 100644
> --- a/include/linux/once_lite.h
> +++ b/include/linux/once_lite.h
> @@ -9,15 +9,27 @@
> */
> #define DO_ONCE_LITE(func, ...) \
> DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
> -#define DO_ONCE_LITE_IF(condition, func, ...) \
> +
> +#define __ONCE_LITE_IF(condition) \
> ({ \
> static bool __section(".data.once") __already_done; \
> - bool __ret_do_once = !!(condition); \
> + bool __ret_cond = !!(condition); \
> + bool __ret_once = false; \
> \
> if (unlikely(__ret_do_once && !__already_done)) { \
> __already_done = true; \
> - func(__VA_ARGS__); \
> + __ret_once = true; \
> } \
> + unlikely(__ret_once); \
> + })
> +
> +#define DO_ONCE_LITE_IF(condition, func, ...) \
> + ({ \
> + bool __ret_do_once = !!(condition); \
> + \
> + if (__ONCE_LITE_IF(__ret_do_once)) \
> + func(__VA_ARGS__); \
> + \
> unlikely(__ret_do_once); \
> })
>

2022-07-20 12:56:05

by Stephane Eranian

[permalink] [raw]
Subject: Re: [RFC] pr_warn_once() issue in x86 MSR extable code

On Wed, Jun 22, 2022 at 8:51 PM Stephane Eranian <[email protected]> wrote:
>
> Hi Peter,
>
> Thanks for taking a quick look at this.
> I am currently OOO and I cannot test this proposed patch.
> I am okay with your suggestion.
>
> Thanks.
>
> On Fri, Jun 17, 2022 at 4:52 PM Peter Zijlstra <[email protected]> wrote:
> >
> > On Fri, Jun 17, 2022 at 02:08:52PM +0300, Stephane Eranian wrote:
> > > Hi,
> > >
> > > Some changes to the way invalid MSR accesses are reported by the kernel is
> > > causing some problems with messages printed on the console.
> > >
> > > We have seen several cases of ex_handler_msr() printing invalid MSR
> > > accesses once but
> > > the callstack multiple times causing confusion on the console.
> > >
> > > The last time the exception MSR code was modified (5.16) by PeterZ was:
> > >
> > > d52a7344bdfa x86/msr: Remove .fixup usage:
> > >
> > > if (!safe && wrmsr && pr_warn_once("unchecked MSR access error: ..."))
> > > show_stack_regs(regs);
> > >
> > > Note that this code pattern was also present, though in a different
> > > form, before this commit.
> > >
> > > The problem here is that another earlier commit (5.13):
> > >
> > > a358f40600b3 once: implement DO_ONCE_LITE for non-fast-path "do once"
> > > functionality
> > >
> > > Modifies all the pr_*_once() calls to always return true claiming that
> > > no caller is ever
> > > checking the return value of the functions.
> > >
> > > This is why we are seeing the callstack printed without the associated
> > > printk() msg.
> > >
> > > I believe that having the pr_*_once() functions return true the first
> > > time they are called
> > > is useful especially when extra information, such as callstack, must
> > > be printed to help
> > > track the origin of the problem.
> > >
> > > The exception handling code seems to be the only place where the
> > > return value is checked
> > > for pr_warn_once(). A minimal change would be to create another
> > > version of that function
> > > that calls DO_ONCE() instead of DO_ONCE_LITE(), e.g., pr_warn_once_return().
> > >
> > > I can post a patch to that effect if we all agree on the approach.
> > >
> > > Thanks.
> >
> > How about something like this?
> >
> > diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> > index dba2197c05c3..331310c29349 100644
> > --- a/arch/x86/mm/extable.c
> > +++ b/arch/x86/mm/extable.c
> > @@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct exception_table_entry *fixup,
> > static bool ex_handler_msr(const struct exception_table_entry *fixup,
> > struct pt_regs *regs, bool wrmsr, bool safe, int reg)
> > {
> > - if (!safe && wrmsr &&
> > - pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
> > - (unsigned int)regs->cx, (unsigned int)regs->dx,
> > - (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
> > + if (__ONCE_LITE_IF(!safe && wrmsr)) {
> > + pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
> > + (unsigned int)regs->cx, (unsigned int)regs->dx,
> > + (unsigned int)regs->ax, regs->ip, (void *)regs->ip);
> > show_stack_regs(regs);
> > + }
> >
> > - if (!safe && !wrmsr &&
> > - pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
> > - (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
> > + if (__ONCE_LITE_IF(!safe && !wrmsr)) {
> > + pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
> > + (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
> > show_stack_regs(regs);
> > + }
> >
> > if (!wrmsr) {
> > /* Pretend that the read succeeded and returned 0. */
> > diff --git a/include/linux/once_lite.h b/include/linux/once_lite.h
> > index 861e606b820f..63c3bbcef694 100644
> > --- a/include/linux/once_lite.h
> > +++ b/include/linux/once_lite.h
> > @@ -9,15 +9,27 @@
> > */
> > #define DO_ONCE_LITE(func, ...) \
> > DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
> > -#define DO_ONCE_LITE_IF(condition, func, ...) \
> > +
> > +#define __ONCE_LITE_IF(condition) \
> > ({ \
> > static bool __section(".data.once") __already_done; \
> > - bool __ret_do_once = !!(condition); \
> > + bool __ret_cond = !!(condition); \
> > + bool __ret_once = false; \
> > \
> > if (unlikely(__ret_do_once && !__already_done)) { \

You need to replace __ret_do_once with __ret_cond above and then it
compiles and works.
I have tested with a kernel module that reads and writes to an illegal MSR:

unchecked MSR access error: RDMSR from 0x1234567 at rIP:
0xffffffffc00ec138 (rdpmc_intel+0x28/0x21d0 [rdpmc_test])
Call Trace:
<TASK>
rdpmc_bench_store+0x53/0x80 [rdpmc_test]
kobj_attr_store+0xf/0x20
sysfs_kf_write+0x34/0x50
kernfs_fop_write_iter+0xfa/0x180
vfs_write+0x334/0x3d0
ksys_write+0x71/0xe0
__x64_sys_write+0x1b/0x20
do_syscall_64+0x44/0xa0
? exc_page_fault+0x6e/0x110
entry_SYSCALL_64_after_hwframe+0x63/0xcd


Tested-by: Stephane Eranian <[email protected]>

>
> > __already_done = true; \
> > - func(__VA_ARGS__); \
> > + __ret_once = true; \
> > } \
> > + unlikely(__ret_once); \
> > + })
> > +
> > +#define DO_ONCE_LITE_IF(condition, func, ...) \
> > + ({ \
> > + bool __ret_do_once = !!(condition); \
> > + \
> > + if (__ONCE_LITE_IF(__ret_do_once)) \
> > + func(__VA_ARGS__); \
> > + \
> > unlikely(__ret_do_once); \
> > })
> >

2022-07-20 14:05:45

by Peter Zijlstra

[permalink] [raw]
Subject: [PATCH] x86/extable: Fix ex_handler_msr() print condition

On Wed, Jul 20, 2022 at 03:48:56PM +0300, Stephane Eranian wrote:

> Tested-by: Stephane Eranian <[email protected]>

Thanks, I'll queue the below.

---
Subject: x86/extable: Fix ex_handler_msr() print condition
From: Peter Zijlstra <[email protected]>
Date: Fri, 17 Jun 2022 16:52:06 +0200

On Fri, Jun 17, 2022 at 02:08:52PM +0300, Stephane Eranian wrote:
> Some changes to the way invalid MSR accesses are reported by the
> kernel is causing some problems with messages printed on the
> console.
>
> We have seen several cases of ex_handler_msr() printing invalid MSR
> accesses once but the callstack multiple times causing confusion on
> the console.

> The problem here is that another earlier commit (5.13):
>
> a358f40600b3 ("once: implement DO_ONCE_LITE for non-fast-path "do once" functionality")
>
> Modifies all the pr_*_once() calls to always return true claiming
> that no caller is ever checking the return value of the functions.
>
> This is why we are seeing the callstack printed without the
> associated printk() msg.

Extract the ONCE_IF(cond) part into __ONCE_LTE_IF() and use that to
implement DO_ONCE_LITE_IF() and fix the extable code.

Fixes: a358f40600b3 ("once: implement DO_ONCE_LITE for non-fast-path "do once" functionality")
Reported-by: Stephane Eranian <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Tested-by: Stephane Eranian <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
---
arch/x86/mm/extable.c | 16 +++++++++-------
include/linux/once_lite.h | 20 ++++++++++++++++----
2 files changed, 25 insertions(+), 11 deletions(-)

--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct
static bool ex_handler_msr(const struct exception_table_entry *fixup,
struct pt_regs *regs, bool wrmsr, bool safe, int reg)
{
- if (!safe && wrmsr &&
- pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, (unsigned int)regs->dx,
- (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && wrmsr)) {
+ pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, (unsigned int)regs->dx,
+ (unsigned int)regs->ax, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

- if (!safe && !wrmsr &&
- pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && !wrmsr)) {
+ pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

if (!wrmsr) {
/* Pretend that the read succeeded and returned 0. */
--- a/include/linux/once_lite.h
+++ b/include/linux/once_lite.h
@@ -9,15 +9,27 @@
*/
#define DO_ONCE_LITE(func, ...) \
DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
-#define DO_ONCE_LITE_IF(condition, func, ...) \
+
+#define __ONCE_LITE_IF(condition) \
({ \
static bool __section(".data.once") __already_done; \
- bool __ret_do_once = !!(condition); \
+ bool __ret_cond = !!(condition); \
+ bool __ret_once = false; \
\
- if (unlikely(__ret_do_once && !__already_done)) { \
+ if (unlikely(__ret_cond && !__already_done)) { \
__already_done = true; \
- func(__VA_ARGS__); \
+ __ret_once = true; \
} \
+ unlikely(__ret_once); \
+ })
+
+#define DO_ONCE_LITE_IF(condition, func, ...) \
+ ({ \
+ bool __ret_do_once = !!(condition); \
+ \
+ if (__ONCE_LITE_IF(__ret_do_once)) \
+ func(__VA_ARGS__); \
+ \
unlikely(__ret_do_once); \
})

Subject: [tip: x86/core] x86/extable: Fix ex_handler_msr() print condition

The following commit has been merged into the x86/core branch of tip:

Commit-ID: a1a5482a2c6e38a3ebed32e571625c56a8cc41a6
Gitweb: https://git.kernel.org/tip/a1a5482a2c6e38a3ebed32e571625c56a8cc41a6
Author: Peter Zijlstra <[email protected]>
AuthorDate: Fri, 17 Jun 2022 16:52:06 +02:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Thu, 21 Jul 2022 10:39:42 +02:00

x86/extable: Fix ex_handler_msr() print condition

On Fri, Jun 17, 2022 at 02:08:52PM +0300, Stephane Eranian wrote:
> Some changes to the way invalid MSR accesses are reported by the
> kernel is causing some problems with messages printed on the
> console.
>
> We have seen several cases of ex_handler_msr() printing invalid MSR
> accesses once but the callstack multiple times causing confusion on
> the console.

> The problem here is that another earlier commit (5.13):
>
> a358f40600b3 ("once: implement DO_ONCE_LITE for non-fast-path "do once" functionality")
>
> Modifies all the pr_*_once() calls to always return true claiming
> that no caller is ever checking the return value of the functions.
>
> This is why we are seeing the callstack printed without the
> associated printk() msg.

Extract the ONCE_IF(cond) part into __ONCE_LTE_IF() and use that to
implement DO_ONCE_LITE_IF() and fix the extable code.

Fixes: a358f40600b3 ("once: implement DO_ONCE_LITE for non-fast-path "do once" functionality")
Reported-by: Stephane Eranian <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Tested-by: Stephane Eranian <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
---
arch/x86/mm/extable.c | 16 +++++++++-------
include/linux/once_lite.h | 20 ++++++++++++++++----
2 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index dba2197..331310c 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct exception_table_entry *fixup,
static bool ex_handler_msr(const struct exception_table_entry *fixup,
struct pt_regs *regs, bool wrmsr, bool safe, int reg)
{
- if (!safe && wrmsr &&
- pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, (unsigned int)regs->dx,
- (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && wrmsr)) {
+ pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, (unsigned int)regs->dx,
+ (unsigned int)regs->ax, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

- if (!safe && !wrmsr &&
- pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
- (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
+ if (__ONCE_LITE_IF(!safe && !wrmsr)) {
+ pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+ (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
show_stack_regs(regs);
+ }

if (!wrmsr) {
/* Pretend that the read succeeded and returned 0. */
diff --git a/include/linux/once_lite.h b/include/linux/once_lite.h
index 861e606..b7bce49 100644
--- a/include/linux/once_lite.h
+++ b/include/linux/once_lite.h
@@ -9,15 +9,27 @@
*/
#define DO_ONCE_LITE(func, ...) \
DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
-#define DO_ONCE_LITE_IF(condition, func, ...) \
+
+#define __ONCE_LITE_IF(condition) \
({ \
static bool __section(".data.once") __already_done; \
- bool __ret_do_once = !!(condition); \
+ bool __ret_cond = !!(condition); \
+ bool __ret_once = false; \
\
- if (unlikely(__ret_do_once && !__already_done)) { \
+ if (unlikely(__ret_cond && !__already_done)) { \
__already_done = true; \
- func(__VA_ARGS__); \
+ __ret_once = true; \
} \
+ unlikely(__ret_once); \
+ })
+
+#define DO_ONCE_LITE_IF(condition, func, ...) \
+ ({ \
+ bool __ret_do_once = !!(condition); \
+ \
+ if (__ONCE_LITE_IF(__ret_do_once)) \
+ func(__VA_ARGS__); \
+ \
unlikely(__ret_do_once); \
})