2020-08-14 19:47:55

by Joe Perches

[permalink] [raw]
Subject: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

There is a print_vma_addr function used several places
that requires KERN_CONT use.

Add a %pv mechanism to avoid the need for KERN_CONT.

An example conversion is arch/x86/kernel/signal.c

from:
if (show_unhandled_signals && printk_ratelimit()) {
printk("%s"
"%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
me->comm, me->pid, where, frame,
regs->ip, regs->sp, regs->orig_ax);
print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n");
to:
printk("%s"
"%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx in %pv\n",
task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
me->comm, me->pid, where, frame,
regs->ip, regs->sp, regs->orig_ax, (void *)regs->ip);
---
lib/vsprintf.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c155769559ab..654402c43f8d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -995,6 +995,12 @@ static const struct printf_spec default_dec_spec = {
.precision = -1,
};

+static const struct printf_spec default_hex_spec = {
+ .base = 16,
+ .precision = -1,
+ .flags = SMALL,
+};
+
static const struct printf_spec default_dec02_spec = {
.base = 10,
.field_width = 2,
@@ -2089,6 +2095,50 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
return widen_string(buf, buf - buf_start, end, spec);
}

+static noinline_for_stack
+char *vma_addr(char *buf, char *end, void *ip,
+ struct printf_spec spec, const char *fmt)
+{
+#ifdef CONFIG_MMU
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+
+ /*
+ * we might be running from an atomic context so we cannot sleep
+ */
+ if (!mmap_read_trylock(mm))
+ return buf;
+
+ vma = find_vma(mm, (unsigned long)ip);
+ if (vma && vma->vm_file) {
+ char *p;
+ struct file *f = vma->vm_file;
+ char *page = (char *)__get_free_page(GFP_NOWAIT);
+
+ if (page) {
+ p = file_path(f, page, PAGE_SIZE);
+ if (IS_ERR(p))
+ p = "?";
+ buf = string(buf, end, kbasename(p), default_str_spec);
+ buf = string_nocheck(buf, end, "[", default_str_spec);
+ buf = pointer_string(buf, end,
+ (void *)vma->vm_start,
+ default_hex_spec);
+ buf = string_nocheck(buf, end, "+", default_str_spec);
+ buf = pointer_string(buf, end,
+ (void *)(vma->vm_end - vma->vm_start),
+ default_hex_spec);
+ buf = string_nocheck(buf, end, "]", default_str_spec);
+ free_page((unsigned long)page);
+ }
+ }
+ mmap_read_unlock(mm);
+#else
+ buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);
+#endif
+ return buf;
+}
+
/*
* Show a '%p' thing. A kernel extension is that the '%p' is followed
* by an extra set of alphanumeric characters that are extended format
@@ -2254,6 +2304,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
return uuid_string(buf, end, ptr, spec, fmt);
case 'V':
return va_format(buf, end, ptr, spec, fmt);
+ case 'v':
+ return vma_addr(buf, end, ptr, spec, fmt);
case 'K':
return restricted_pointer(buf, end, ptr, spec);
case 'N':



2020-08-14 21:00:43

by Steven Rostedt

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

On Fri, 14 Aug 2020 10:53:03 -0700
Joe Perches <[email protected]> wrote:

> There is a print_vma_addr function used several places
> that requires KERN_CONT use.
>
> Add a %pv mechanism to avoid the need for KERN_CONT.
>
> An example conversion is arch/x86/kernel/signal.c
>
> from:
> if (show_unhandled_signals && printk_ratelimit()) {
> printk("%s"
> "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
> task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
> me->comm, me->pid, where, frame,
> regs->ip, regs->sp, regs->orig_ax);
> print_vma_addr(KERN_CONT " in ", regs->ip);
> pr_cont("\n");
> to:
> printk("%s"
> "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx in %pv\n",
> task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
> me->comm, me->pid, where, frame,
> regs->ip, regs->sp, regs->orig_ax, (void *)regs->ip);
> ---
> lib/vsprintf.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index c155769559ab..654402c43f8d 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -995,6 +995,12 @@ static const struct printf_spec default_dec_spec = {
> .precision = -1,
> };
>
> +static const struct printf_spec default_hex_spec = {
> + .base = 16,
> + .precision = -1,
> + .flags = SMALL,
> +};
> +
> static const struct printf_spec default_dec02_spec = {
> .base = 10,
> .field_width = 2,
> @@ -2089,6 +2095,50 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
> return widen_string(buf, buf - buf_start, end, spec);
> }
>
> +static noinline_for_stack
> +char *vma_addr(char *buf, char *end, void *ip,
> + struct printf_spec spec, const char *fmt)
> +{
> +#ifdef CONFIG_MMU
> + struct mm_struct *mm = current->mm;
> + struct vm_area_struct *vma;
> +
> + /*
> + * we might be running from an atomic context so we cannot sleep
> + */
> + if (!mmap_read_trylock(mm))
> + return buf;
> +
> + vma = find_vma(mm, (unsigned long)ip);
> + if (vma && vma->vm_file) {
> + char *p;
> + struct file *f = vma->vm_file;
> + char *page = (char *)__get_free_page(GFP_NOWAIT);
> +
> + if (page) {
> + p = file_path(f, page, PAGE_SIZE);
> + if (IS_ERR(p))
> + p = "?";
> + buf = string(buf, end, kbasename(p), default_str_spec);
> + buf = string_nocheck(buf, end, "[", default_str_spec);
> + buf = pointer_string(buf, end,
> + (void *)vma->vm_start,
> + default_hex_spec);
> + buf = string_nocheck(buf, end, "+", default_str_spec);
> + buf = pointer_string(buf, end,
> + (void *)(vma->vm_end - vma->vm_start),
> + default_hex_spec);
> + buf = string_nocheck(buf, end, "]", default_str_spec);
> + free_page((unsigned long)page);
> + }
> + }
> + mmap_read_unlock(mm);
> +#else
> + buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);
> +#endif

I'm fine with all his, but I feel more comfortable if this patch
created a single copy of the code. Perhaps add:

diff --git a/mm/memory.c b/mm/memory.c
index 87ec87cdc1ff..795a4db4d83d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4771,32 +4771,7 @@ EXPORT_SYMBOL_GPL(access_process_vm);
*/
void print_vma_addr(char *prefix, unsigned long ip)
{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
-
- /*
- * we might be running from an atomic context so we cannot sleep
- */
- if (!mmap_read_trylock(mm))
- return;
-
- vma = find_vma(mm, ip);
- if (vma && vma->vm_file) {
- struct file *f = vma->vm_file;
- char *buf = (char *)__get_free_page(GFP_NOWAIT);
- if (buf) {
- char *p;
-
- p = file_path(f, buf, PAGE_SIZE);
- if (IS_ERR(p))
- p = "?";
- printk("%s%s[%lx+%lx]", prefix, kbasename(p),
- vma->vm_start,
- vma->vm_end - vma->vm_start);
- free_page((unsigned long)buf);
- }
- }
- mmap_read_unlock(mm);
+ printk("%s%pv", prefix, ip);
}

#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)


And of course this would need for documentation.

-- Steve



> + return buf;
> +}
> +
> /*
> * Show a '%p' thing. A kernel extension is that the '%p' is followed
> * by an extra set of alphanumeric characters that are extended format
> @@ -2254,6 +2304,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
> return uuid_string(buf, end, ptr, spec, fmt);
> case 'V':
> return va_format(buf, end, ptr, spec, fmt);
> + case 'v':
> + return vma_addr(buf, end, ptr, spec, fmt);
> case 'K':
> return restricted_pointer(buf, end, ptr, spec);
> case 'N':
>

2020-08-14 21:35:56

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

On Fri, 2020-08-14 at 14:38 -0400, Steven Rostedt wrote:
> On Fri, 14 Aug 2020 10:53:03 -0700
> Joe Perches <[email protected]> wrote:
> I'm fine with all his, but I feel more comfortable if this patch
> created a single copy of the code. Perhaps add:
[]
> diff --git a/mm/memory.c b/mm/memory.c
[]
> @@ -4771,32 +4771,7 @@ EXPORT_SYMBOL_GPL(access_process_vm);
> */
> void print_vma_addr(char *prefix, unsigned long ip)
> {
> - struct mm_struct *mm = current->mm;
> - struct vm_area_struct *vma;
> -
> - /*
> - * we might be running from an atomic context so we cannot sleep
> - */
> - if (!mmap_read_trylock(mm))
> - return;
> -
> - vma = find_vma(mm, ip);
> - if (vma && vma->vm_file) {
> - struct file *f = vma->vm_file;
> - char *buf = (char *)__get_free_page(GFP_NOWAIT);
> - if (buf) {
> - char *p;
> -
> - p = file_path(f, buf, PAGE_SIZE);
> - if (IS_ERR(p))
> - p = "?";
> - printk("%s%s[%lx+%lx]", prefix, kbasename(p),
> - vma->vm_start,
> - vma->vm_end - vma->vm_start);
> - free_page((unsigned long)buf);
> - }
> - }
> - mmap_read_unlock(mm);
> + printk("%s%pv", prefix, ip);
> }

I'd just convert all of them and remove this function instead.

Something like (uncompiled/untested):
---
arch/arc/kernel/troubleshoot.c | 2 +-
arch/arm64/kernel/traps.c | 16 +++++++------
arch/csky/kernel/traps.c | 11 ++++-----
arch/mips/mm/fault.c | 14 +++++------
arch/parisc/mm/fault.c | 15 +++++-------
arch/powerpc/kernel/traps.c | 8 ++-----
arch/riscv/kernel/traps.c | 11 ++++-----
arch/s390/mm/fault.c | 7 +++---
arch/sparc/mm/fault_32.c | 8 ++-----
arch/sparc/mm/fault_64.c | 8 ++-----
arch/um/kernel/trap.c | 13 ++++-------
arch/x86/kernel/signal.c | 6 ++---
arch/x86/kernel/traps.c | 6 ++---
arch/x86/mm/fault.c | 53 +++++++++++++++++++-----------------------
include/linux/mm.h | 7 ------
mm/memory.c | 33 --------------------------
16 files changed, 74 insertions(+), 144 deletions(-)

diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 28e8bf04b253..26ecd59f0057 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -86,7 +86,7 @@ static void show_faulting_vma(unsigned long address)
struct vm_area_struct *vma;
struct mm_struct *active_mm = current->active_mm;

- /* can't use print_vma_addr() yet as it doesn't check for
+ /* can't use %pv yet as it doesn't check for
* non-inclusive vma
*/
mmap_read_lock(active_mm);
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 13ebd5ca2070..294ed81f67d8 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -224,13 +224,15 @@ static void arm64_show_signal(int signo, const char *str)
!__ratelimit(&rs))
return;

- pr_info("%s[%d]: unhandled exception: ", tsk->comm, task_pid_nr(tsk));
- if (esr)
- pr_cont("%s, ESR 0x%08x, ", esr_get_class_string(esr), esr);
-
- pr_cont("%s", str);
- print_vma_addr(KERN_CONT " in ", regs->pc);
- pr_cont("\n");
+ if (esr) {
+ pr_info("%s[%d]: unhandled exception: %s, ESR 0x%08x, %s in %pv\n",
+ tsk->comm, task_pid_nr(tsk),
+ esr_get_class_string(esr), esr,
+ str, (void *)regs->pc);
+ } else {
+ pr_info("%s[%d]: unhandled exception: %s in %pv\n",
+ tsk->comm, task_pid_nr(tsk), str, (void *)regs->pc);
+ }
__show_regs(regs);
}

diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c
index 959a917c989d..bdf1577237df 100644
--- a/arch/csky/kernel/traps.c
+++ b/arch/csky/kernel/traps.c
@@ -118,12 +118,11 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
{
struct task_struct *tsk = current;

- if (show_unhandled_signals && unhandled_signal(tsk, signo)
- && printk_ratelimit()) {
- pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx",
- tsk->comm, task_pid_nr(tsk), signo, code, addr);
- print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
- pr_cont("\n");
+ if (show_unhandled_signals && unhandled_signal(tsk, signo) &&
+ printk_ratelimit()) {
+ pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx in %pv\n",
+ tsk->comm, task_pid_nr(tsk), signo, code, addr,
+ (void *)instruction_pointer(regs));
show_regs(regs);
}

diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 7c871b14e74a..cd87d11d57dc 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -204,14 +204,12 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
tsk->comm,
write ? "write access to" : "read access from",
field, address);
- pr_info("epc = %0*lx in", field,
- (unsigned long) regs->cp0_epc);
- print_vma_addr(KERN_CONT " ", regs->cp0_epc);
- pr_cont("\n");
- pr_info("ra = %0*lx in", field,
- (unsigned long) regs->regs[31]);
- print_vma_addr(KERN_CONT " ", regs->regs[31]);
- pr_cont("\n");
+ pr_info("epc = %0*lx in %pv\n",
+ field, (unsigned long)regs->cp0_epc,
+ (void *)(unsigned long)regs->cp0_epc);
+ pr_info("ra = %0*lx in %pv\n",
+ field, (unsigned long)regs->regs[31],
+ (void *)(unsigned long)regs->regs[31]);
}
current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
force_sig_fault(SIGSEGV, si_code, (void __user *)address);
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index 4bfe2da9fbe3..3d519fb80541 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -242,17 +242,14 @@ show_signal_msg(struct pt_regs *regs, unsigned long code,
if (!printk_ratelimit())
return;

- pr_warn("\n");
- pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx",
- tsk->comm, code, address);
- print_vma_addr(KERN_CONT " in ", regs->iaoq[0]);
-
- pr_cont("\ntrap #%lu: %s%c", code, trap_name(code),
- vma ? ',':'\n');
+ pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx in %pv\n",
+ tsk->comm, code, address, (void *)regs->iaoq[0]);

if (vma)
- pr_cont(" vm_start = 0x%08lx, vm_end = 0x%08lx\n",
- vma->vm_start, vma->vm_end);
+ pr_warn("trap #%lu: %s, vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+ code, trap_name(code), vma->vm_start, vma->vm_end);
+ else
+ pr_warn("trap #%lu: %s\n", code, trap_name(code));

show_regs(regs);
}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index d1ebe152f210..a21bad3c059b 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -321,13 +321,9 @@ static void show_signal_msg(int signr, struct pt_regs *regs, int code,
if (!__ratelimit(&rs))
return;

- pr_info("%s[%d]: %s (%d) at %lx nip %lx lr %lx code %x",
+ pr_info("%s[%d]: %s (%d) at %lx nip %lx lr %lx code %x in %pv\n",
current->comm, current->pid, signame(signr), signr,
- addr, regs->nip, regs->link, code);
-
- print_vma_addr(KERN_CONT " in ", regs->nip);
-
- pr_cont("\n");
+ addr, regs->nip, regs->link, code, (void *)regs->nip);

show_user_instructions(regs);
}
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index ad14f4466d92..c08d80b18e33 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -60,12 +60,11 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
{
struct task_struct *tsk = current;

- if (show_unhandled_signals && unhandled_signal(tsk, signo)
- && printk_ratelimit()) {
- pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT,
- tsk->comm, task_pid_nr(tsk), signo, code, addr);
- print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
- pr_cont("\n");
+ if (show_unhandled_signals && unhandled_signal(tsk, signo) &&
+ printk_ratelimit()) {
+ pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT " in %pv\n",
+ tsk->comm, task_pid_nr(tsk), signo, code, addr,
+ (void *)instruction_pointer(regs));
show_regs(regs);
}

diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 4c8c063bce5b..4726a440dfdd 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -217,10 +217,9 @@ void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault)
return;
if (!printk_ratelimit())
return;
- printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d ",
- regs->int_code & 0xffff, regs->int_code >> 17);
- print_vma_addr(KERN_CONT "in ", regs->psw.addr);
- printk(KERN_CONT "\n");
+ pr_alert("User process fault: interruption code %04x ilc:%d in %pv\n",
+ regs->int_code & 0xffff, regs->int_code >> 17,
+ (void *)regs->psw.addr);
if (is_mm_fault)
dump_fault_info(regs);
show_regs(regs);
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index 8071bfd72349..c527d77a84d6 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -112,15 +112,11 @@ show_signal_msg(struct pt_regs *regs, int sig, int code,
if (!printk_ratelimit())
return;

- printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x",
+ printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x in %pv\n",
task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, task_pid_nr(tsk), address,
(void *)regs->pc, (void *)regs->u_regs[UREG_I7],
- (void *)regs->u_regs[UREG_FP], code);
-
- print_vma_addr(KERN_CONT " in ", regs->pc);
-
- printk(KERN_CONT "\n");
+ (void *)regs->u_regs[UREG_FP], code, (void *)regs->pc);
}

static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs,
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index 0a6bcc85fba7..bbe39cb9560b 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -143,15 +143,11 @@ show_signal_msg(struct pt_regs *regs, int sig, int code,
if (!printk_ratelimit())
return;

- printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x",
+ printk("%s%s[%d]: segfault at %lx ip %px (rpc %px) sp %px error %x in %pv\n",
task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, task_pid_nr(tsk), address,
(void *)regs->tpc, (void *)regs->u_regs[UREG_I7],
- (void *)regs->u_regs[UREG_FP], code);
-
- print_vma_addr(KERN_CONT " in ", regs->tpc);
-
- printk(KERN_CONT "\n");
+ (void *)regs->u_regs[UREG_FP], code, (void *)regs->tpc);
}

static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index ad12f78bda7e..f7854e9bc06a 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -140,14 +140,11 @@ static void show_segv_info(struct uml_pt_regs *regs)
if (!printk_ratelimit())
return;

- printk("%s%s[%d]: segfault at %lx ip %px sp %px error %x",
- task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
- tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
- (void *)UPT_IP(regs), (void *)UPT_SP(regs),
- fi->error_code);
-
- print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
- printk(KERN_CONT "\n");
+ printk("%s%s[%d]: segfault at %lx ip %px sp %px error %x in %pv\n",
+ task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+ tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
+ (void *)UPT_IP(regs), (void *)UPT_SP(regs),
+ fi->error_code, (void *)UPT_IP(regs));
}

static void bad_segv(struct faultinfo fi, unsigned long ip)
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index d5fa494c2304..ae7b280f4971 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -845,12 +845,10 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)

if (show_unhandled_signals && printk_ratelimit()) {
printk("%s"
- "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+ "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx in %pv\n",
task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
me->comm, me->pid, where, frame,
- regs->ip, regs->sp, regs->orig_ax);
- print_vma_addr(KERN_CONT " in ", regs->ip);
- pr_cont("\n");
+ regs->ip, regs->sp, regs->orig_ax, (void *)regs->ip);
}

force_sig(SIGSEGV);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 1f66d2d1e998..426324f93929 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -139,11 +139,9 @@ static void show_signal(struct task_struct *tsk, int signr,
{
if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
printk_ratelimit()) {
- pr_info("%s[%d] %s%s ip:%lx sp:%lx error:%lx",
+ pr_info("%s[%d] %s%s ip:%lx sp:%lx error:%lx in %pv\n",
tsk->comm, task_pid_nr(tsk), type, desc,
- regs->ip, regs->sp, error_code);
- print_vma_addr(KERN_CONT " in ", regs->ip);
- pr_cont("\n");
+ regs->ip, regs->sp, error_code, (void *)regs->ip);
}
}

diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 35f1498e9832..01e9b0f12092 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -246,20 +246,22 @@ static void dump_pagetable(unsigned long address)
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
+ char buffer[128] = '\0';
+ char *p = buffer;
+ char *end = buffer + sizeof(buffer) - 1;

#ifdef CONFIG_X86_PAE
- pr_info("*pdpt = %016Lx ", pgd_val(*pgd));
+ p += scnprintf(p, end - p, "%s*pdpt = %016llx",
+ p == buffer ? "" : " ", pgd_val(*pgd));
if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd))
goto out;
-#define pr_pde pr_cont
-#else
-#define pr_pde pr_info
#endif
p4d = p4d_offset(pgd, address);
pud = pud_offset(p4d, address);
pmd = pmd_offset(pud, address);
- pr_pde("*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd));
-#undef pr_pde
+ p += scnprintf(p, end - p, "%s*pde = %0*llx",
+ p == buffer ? "" : " ",
+ sizeof(*pmd) * 2, (u64)pmd_val(*pmd));

/*
* We must not directly access the pte in the highpte
@@ -271,20 +273,12 @@ static void dump_pagetable(unsigned long address)
goto out;

pte = pte_offset_kernel(pmd, address);
- pr_cont("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte));
+ p += snprintf(p, end - p, "%s*pte = %0*llx",
+ p == buffer ? "" : " ",
+ sizeof(*pte) * 2, (u64)pte_val(*pte));
out:
- pr_cont("\n");
+ pr_info("%s\n", buffer);
}
-
-#else /* CONFIG_X86_64: */
-
-#ifdef CONFIG_CPU_SUP_AMD
-static const char errata93_warning[] =
-KERN_ERR
-"******* Your BIOS seems to not contain a fix for K8 errata #93\n"
-"******* Working around it, but it may cause SEGVs or burn power.\n"
-"******* Please consider a BIOS update.\n"
-"******* Disabling USB legacy in the BIOS may also help.\n";
#endif

/*
@@ -388,7 +382,11 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
address |= 0xffffffffUL << 32;
if ((address >= (u64)_stext && address <= (u64)_etext) ||
(address >= MODULES_VADDR && address <= MODULES_END)) {
- printk_once(errata93_warning);
+ pr_err_once(
+"******* Your BIOS seems to not contain a fix for K8 errata #93\n"
+"******* Working around it, but it may cause SEGVs or burn power.\n"
+"******* Please consider a BIOS update.\n"
+"******* Disabling USB legacy in the BIOS may also help.\n");
regs->ip = address;
return 1;
}
@@ -545,8 +543,8 @@ pgtable_bad(struct pt_regs *regs, unsigned long error_code,
tsk = current;
sig = SIGKILL;

- printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
- tsk->comm, address);
+ pr_alert("%s: Corrupted page table at address %lx\n",
+ tsk->comm, address);
dump_pagetable(address);

if (__die("Bad pagetable", regs, error_code))
@@ -688,7 +686,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
show_fault_oops(regs, error_code, address);

if (task_stack_end_corrupted(tsk))
- printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
+ pr_emerg("Thread overran stack, or stack corrupted\n");

sig = SIGKILL;
if (__die("Oops", regs, error_code))
@@ -716,13 +714,10 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
if (!printk_ratelimit())
return;

- printk("%s%s[%d]: segfault at %lx ip %px sp %px error %lx",
- loglvl, tsk->comm, task_pid_nr(tsk), address,
- (void *)regs->ip, (void *)regs->sp, error_code);
-
- print_vma_addr(KERN_CONT " in ", regs->ip);
-
- printk(KERN_CONT "\n");
+ printk("%s%s[%d]: segfault at %lx ip %px sp %px error %lx in %pv\n",
+ loglvl, tsk->comm, task_pid_nr(tsk), address,
+ (void *)regs->ip, (void *)regs->sp, error_code,
+ (void *)regs->ip);

show_opcodes(regs, loglvl);
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 8ab941cf73f4..b04cd8a59c8b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2951,13 +2951,6 @@ extern int randomize_va_space;
#endif

const char * arch_vma_name(struct vm_area_struct *vma);
-#ifdef CONFIG_MMU
-void print_vma_addr(char *prefix, unsigned long rip);
-#else
-static inline void print_vma_addr(char *prefix, unsigned long rip)
-{
-}
-#endif

void *sparse_buffer_alloc(unsigned long size);
struct page * __populate_section_memmap(unsigned long pfn,
diff --git a/mm/memory.c b/mm/memory.c
index 747594f5225d..3df7a4a2b79c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4836,39 +4836,6 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr,
}
EXPORT_SYMBOL_GPL(access_process_vm);

-/*
- * Print the name of a VMA.
- */
-void print_vma_addr(char *prefix, unsigned long ip)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
-
- /*
- * we might be running from an atomic context so we cannot sleep
- */
- if (!mmap_read_trylock(mm))
- return;
-
- vma = find_vma(mm, ip);
- if (vma && vma->vm_file) {
- struct file *f = vma->vm_file;
- char *buf = (char *)__get_free_page(GFP_NOWAIT);
- if (buf) {
- char *p;
-
- p = file_path(f, buf, PAGE_SIZE);
- if (IS_ERR(p))
- p = "?";
- printk("%s%s[%lx+%lx]", prefix, kbasename(p),
- vma->vm_start,
- vma->vm_end - vma->vm_start);
- free_page((unsigned long)buf);
- }
- }
- mmap_read_unlock(mm);
-}
-
#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
void __might_fault(const char *file, int line)
{


2020-08-15 21:56:07

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

Cc-ing John

On (20/08/14 10:53), Joe Perches wrote:
[..]

In general, the idea looks nice.

> +static noinline_for_stack
> +char *vma_addr(char *buf, char *end, void *ip,
> + struct printf_spec spec, const char *fmt)
> +{
> +#ifdef CONFIG_MMU
> + struct mm_struct *mm = current->mm;
> + struct vm_area_struct *vma;
> +
> + /*
> + * we might be running from an atomic context so we cannot sleep
> + */
> + if (!mmap_read_trylock(mm))
> + return buf;
> +
> + vma = find_vma(mm, (unsigned long)ip);
> + if (vma && vma->vm_file) {
> + char *p;
> + struct file *f = vma->vm_file;
> + char *page = (char *)__get_free_page(GFP_NOWAIT);

Hmm, this is huge. For the time being this is going to introduce lock
inversion chains:

PRINTK -> printk_locks -> MM -> mm_locks

vs
MM -> mm_locks -> PRINTK -> printk_locks

Another thing to mention is

PRINTK -> printk_locks -> MM (WANR_ON/etc) -> PRINTK

we are in printk_safe, currently, but that's going to change.

We might not be ready to take this as of now, but things can change
once we drop printk_locks.

> + if (page) {
> + p = file_path(f, page, PAGE_SIZE);
> + if (IS_ERR(p))
> + p = "?";
> + buf = string(buf, end, kbasename(p), default_str_spec);
> + buf = string_nocheck(buf, end, "[", default_str_spec);
> + buf = pointer_string(buf, end,
> + (void *)vma->vm_start,
> + default_hex_spec);
> + buf = string_nocheck(buf, end, "+", default_str_spec);
> + buf = pointer_string(buf, end,
> + (void *)(vma->vm_end - vma->vm_start),
> + default_hex_spec);
> + buf = string_nocheck(buf, end, "]", default_str_spec);
> + free_page((unsigned long)page);
> + }
> + }
> + mmap_read_unlock(mm);
> +#else
> + buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);

Hmm, we don't usually do that CONFIG_FOO=n thing, I think we just need
to skip %pv and print nothing. Otherwise on !CONFIG_MMU systems the logbuf
may contain a number of CONFIG_MMU=n messages, which are hardly useful.

> +#endif
> + return buf;
> +}
> +
> /*
> * Show a '%p' thing. A kernel extension is that the '%p' is followed
> * by an extra set of alphanumeric characters that are extended format
> @@ -2254,6 +2304,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
> return uuid_string(buf, end, ptr, spec, fmt);
> case 'V':
> return va_format(buf, end, ptr, spec, fmt);

+ #ifdef CONFIG_MMU
> + case 'v':
> + return vma_addr(buf, end, ptr, spec, fmt);
+ #endif

> case 'K':
> return restricted_pointer(buf, end, ptr, spec);
> case 'N':

-ss

2020-08-15 22:00:20

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

On Sat, 2020-08-15 at 12:52 +0900, Sergey Senozhatsky wrote:
> Cc-ing John
>
> On (20/08/14 10:53), Joe Perches wrote:
> [..]
>
> In general, the idea looks nice.
>
> > +static noinline_for_stack
> > +char *vma_addr(char *buf, char *end, void *ip,
> > + struct printf_spec spec, const char *fmt)
> > +{
> > +#ifdef CONFIG_MMU
> > + struct mm_struct *mm = current->mm;
> > + struct vm_area_struct *vma;
> > +
> > + /*
> > + * we might be running from an atomic context so we cannot sleep
> > + */
> > + if (!mmap_read_trylock(mm))
> > + return buf;
> > +
> > + vma = find_vma(mm, (unsigned long)ip);
> > + if (vma && vma->vm_file) {
> > + char *p;
> > + struct file *f = vma->vm_file;
> > + char *page = (char *)__get_free_page(GFP_NOWAIT);
>
> Hmm, this is huge. For the time being this is going to introduce lock
> inversion chains:
>
> PRINTK -> printk_locks -> MM -> mm_locks
>
> vs
> MM -> mm_locks -> PRINTK -> printk_locks
>
> Another thing to mention is
>
> PRINTK -> printk_locks -> MM (WANR_ON/etc) -> PRINTK
>
> we are in printk_safe, currently, but that's going to change.
>
> We might not be ready to take this as of now, but things can change
> once we drop printk_locks.
>
> > + if (page) {
> > + p = file_path(f, page, PAGE_SIZE);
> > + if (IS_ERR(p))
> > + p = "?";
> > + buf = string(buf, end, kbasename(p), default_str_spec);
> > + buf = string_nocheck(buf, end, "[", default_str_spec);
> > + buf = pointer_string(buf, end,
> > + (void *)vma->vm_start,
> > + default_hex_spec);
> > + buf = string_nocheck(buf, end, "+", default_str_spec);
> > + buf = pointer_string(buf, end,
> > + (void *)(vma->vm_end - vma->vm_start),
> > + default_hex_spec);
> > + buf = string_nocheck(buf, end, "]", default_str_spec);
> > + free_page((unsigned long)page);
> > + }
> > + }
> > + mmap_read_unlock(mm);
> > +#else
> > + buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);
>
> Hmm, we don't usually do that CONFIG_FOO=n thing, I think we just need
> to skip %pv and print nothing.

I don't.

Right now, include/linux/mm.h has

#ifdef CONFIG_MMU
void print_vma_addr(char *prefix, unsigned long rip);
#else
static inline void print_vma_addr(char *prefix, unsigned long rip)
{
}
#endif

and the 'v' can't be #ifdef'd in vsprintf/pointer()
otherwise %pv would fallthrough to

return ptr_to_id(buf, end, ptr, spec);


2020-08-17 14:40:51

by Joe Perches

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

On Mon, 2020-08-17 at 14:44 +0300, Andy Shevchenko wrote:
> On Fri, Aug 14, 2020 at 10:53:03AM -0700, Joe Perches wrote:
> > There is a print_vma_addr function used several places
> > that requires KERN_CONT use.
> >
> > Add a %pv mechanism to avoid the need for KERN_CONT.
>
> I like the idea, but I would accent the selling point to make code
> (in the user call sites) nicer.
[]
> > +#else
> > + buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);
> > +#endif
>
> Can we avoid this spammy message? Really it's quite long and fills valuable
> space in kernel buffer. I would rather print the hashed pointer as it's done
> for the rest of %pXXX.

Don't see why not. I believe it'd just use
buf = ptr_to_id(buf, end, ip, spec);
instead


2020-08-17 20:29:49

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [RFC PATCH] vsprintf: Add %pv extension replacement for print_vma_addr

On Fri, Aug 14, 2020 at 10:53:03AM -0700, Joe Perches wrote:
> There is a print_vma_addr function used several places
> that requires KERN_CONT use.
>
> Add a %pv mechanism to avoid the need for KERN_CONT.

I like the idea, but I would accent the selling point to make code
(in the user call sites) nicer.

> An example conversion is arch/x86/kernel/signal.c
>
> from:
> if (show_unhandled_signals && printk_ratelimit()) {
> printk("%s"
> "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
> task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
> me->comm, me->pid, where, frame,
> regs->ip, regs->sp, regs->orig_ax);
> print_vma_addr(KERN_CONT " in ", regs->ip);
> pr_cont("\n");
> to:
> printk("%s"
> "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx in %pv\n",
> task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
> me->comm, me->pid, where, frame,
> regs->ip, regs->sp, regs->orig_ax, (void *)regs->ip);

...

> +#else
> + buf = string_nocheck(buf, end, "CONFIG_MMU=n", default_str_spec);
> +#endif

Can we avoid this spammy message? Really it's quite long and fills valuable
space in kernel buffer. I would rather print the hashed pointer as it's done
for the rest of %pXXX.

--
With Best Regards,
Andy Shevchenko