Re: [PATCH] x86: Avoid pr_cont() in show_opcodes()
From: Rasmus Villemoes
Date: Tue Jul 17 2018 - 05:01:21 EST
On 2018-07-07 15:54, Tetsuo Handa wrote:
> On 2018/07/07 20:12, Ingo Molnar wrote:
>>
>> * Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> wrote:
>>
>>> From: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
>>>
>>> Since syzbot is confused by concurrent printk() messages [1],
>>> this patch changes show_opcodes() to use snprintf().
>>>
>>> When we start adding prefix to each line of printk() output,
>>> we will be able to handle concurrent printk() messages.
>>>
>>> [1] https://syzkaller.appspot.com/text?tag=CrashReport&x=139d342c400000
>>
>> Does this change the output?
>>
>> - If yes, could you show the before/after output in the changelog,
>>
>> - If not (i.e. if only the number of printk calls is changed, the output is the
>> same), could you say so in the changelog?
>
> This patch will not change the output unless multiple threads concurrently
> call printk(). The purpose of this patch is to help parsing kernel messages
> when multiple threads are concurrently calling printk() for multiple times
> (e.g. backtrace) by reducing pr_cont()/KERN_CONT usage.
>
>>
>> Also, 3*OPCODE_BUFSIZE+2+1 is 195 bytes - isn't that a bit too much on-stack
>> footprint?
>
> Then, we can reduce it by OPCODE_BUFSIZE bytes by unionizing opcodes[] and buf[].
Why not this instead? Less stack use, less code, no intermediary
snprintfs, no pr_cont...
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 666a284116ac..c881e8a757d9 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -93,26 +93,16 @@ static void printk_stack_address(unsigned long
address, int reliable,
*/
void show_opcodes(u8 *rip, const char *loglvl)
{
- unsigned int code_prologue = OPCODE_BUFSIZE * 2 / 3;
+ unsigned int prologue = OPCODE_BUFSIZE * 2 / 3;
u8 opcodes[OPCODE_BUFSIZE];
- u8 *ip;
- int i;
- printk("%sCode: ", loglvl);
-
- ip = (u8 *)rip - code_prologue;
- if (probe_kernel_read(opcodes, ip, OPCODE_BUFSIZE)) {
- pr_cont("Bad RIP value.\n");
+ if (probe_kernel_read(opcodes, rip - prologue, OPCODE_BUFSIZE)) {
+ printk("%sCode: Bad RIP value.\n", loglvl);
return;
}
-
- for (i = 0; i < OPCODE_BUFSIZE; i++, ip++) {
- if (ip == rip)
- pr_cont("<%02x> ", opcodes[i]);
- else
- pr_cont("%02x ", opcodes[i]);
- }
- pr_cont("\n");
+ printk("%sCode: %*ph <%02x> %*ph\n", loglvl,
+ prologue, &opcodes[0], opcodes[prologue],
+ OPCODE_BUFSIZE - prologue - 1, &opcodes[prologue + 1]);
}
void show_ip(struct pt_regs *regs, const char *loglvl)
Not compile-tested, probably whitespace-damaged, but you get the idea.
Rasmus