diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-14 03:49:02 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-14 03:49:02 +0200 |
commit | 31003e3a9df675f1ac85d7bcf8e5a5d622576375 (patch) | |
tree | 6b08171deca1bf3cdcd6968ce0859e505048c73a /arch/um | |
parent | 1ee07ef6b5db7235b133ee257a3adf507697e6b3 (diff) | |
parent | 5f786595a291092d20fafe10c5a30378971a8cc3 (diff) | |
download | linux-31003e3a9df675f1ac85d7bcf8e5a5d622576375.tar.gz linux-31003e3a9df675f1ac85d7bcf8e5a5d622576375.tar.bz2 linux-31003e3a9df675f1ac85d7bcf8e5a5d622576375.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML update from Richard Weinberger:
"Besides of fixes this contains also support for CONFIG_STACKTRACE by
Daniel Walter"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
um: net: Eliminate NULL test after alloc_bootmem
um: Add support for CONFIG_STACKTRACE
um: ubd: Fix for processes stuck in D state forever
um: delete unnecessary bootmem struct page array
um: remove csum_partial_copy_generic_i386 to clean up exception table
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/Kconfig.common | 3 | ||||
-rw-r--r-- | arch/um/drivers/net_kern.c | 4 | ||||
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 5 | ||||
-rw-r--r-- | arch/um/include/asm/stacktrace.h | 42 | ||||
-rw-r--r-- | arch/um/include/shared/mem_user.h | 2 | ||||
-rw-r--r-- | arch/um/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/um/kernel/physmem.c | 32 | ||||
-rw-r--r-- | arch/um/kernel/stacktrace.c | 80 | ||||
-rw-r--r-- | arch/um/kernel/sysrq.c | 69 | ||||
-rw-r--r-- | arch/um/kernel/um_arch.c | 7 |
10 files changed, 153 insertions, 92 deletions
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common index 6915d28cf118..87bc86821bc9 100644 --- a/arch/um/Kconfig.common +++ b/arch/um/Kconfig.common @@ -39,7 +39,8 @@ config LOCKDEP_SUPPORT config STACKTRACE_SUPPORT bool - default n + default y + select STACKTRACE config GENERIC_CALIBRATE_DELAY bool diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 7d26d9c0b2fb..f70dd540655d 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -659,10 +659,6 @@ static int __init eth_setup(char *str) } new = alloc_bootmem(sizeof(*new)); - if (new == NULL) { - printk(KERN_ERR "eth_init : alloc_bootmem failed\n"); - return 1; - } INIT_LIST_HEAD(&new->list); new->index = n; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 3716e6952554..e8ab93c3e638 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1277,7 +1277,7 @@ static void do_ubd_request(struct request_queue *q) while(1){ struct ubd *dev = q->queuedata; - if(dev->end_sg == 0){ + if(dev->request == NULL){ struct request *req = blk_fetch_request(q); if(req == NULL) return; @@ -1299,7 +1299,8 @@ static void do_ubd_request(struct request_queue *q) return; } prepare_flush_request(req, io_req); - submit_request(io_req, dev); + if (submit_request(io_req, dev) == false) + return; } while(dev->start_sg < dev->end_sg){ diff --git a/arch/um/include/asm/stacktrace.h b/arch/um/include/asm/stacktrace.h new file mode 100644 index 000000000000..9a864328c67f --- /dev/null +++ b/arch/um/include/asm/stacktrace.h @@ -0,0 +1,42 @@ +#ifndef _ASM_UML_STACKTRACE_H +#define _ASM_UML_STACKTRACE_H + +#include <linux/uaccess.h> +#include <linux/ptrace.h> + +struct stack_frame { + struct stack_frame *next_frame; + unsigned long return_address; +}; + +struct stacktrace_ops { + void (*address)(void *data, unsigned long address, int reliable); +}; + +#ifdef CONFIG_FRAME_POINTER +static inline unsigned long +get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) +{ + if (!task || task == current) + return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); + return KSTK_EBP(task); +} +#else +static inline unsigned long +get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) +{ + return 0; +} +#endif + +static inline unsigned long +*get_stack_pointer(struct task_struct *task, struct pt_regs *segv_regs) +{ + if (!task || task == current) + return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); + return (unsigned long *)KSTK_ESP(task); +} + +void dump_trace(struct task_struct *tsk, const struct stacktrace_ops *ops, void *data); + +#endif /* _ASM_UML_STACKTRACE_H */ diff --git a/arch/um/include/shared/mem_user.h b/arch/um/include/shared/mem_user.h index 46384acd547b..cb84414e3e66 100644 --- a/arch/um/include/shared/mem_user.h +++ b/arch/um/include/shared/mem_user.h @@ -49,7 +49,7 @@ extern int iomem_size; extern int init_mem_user(void); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern int init_maps(unsigned long physmem, unsigned long iomem, +extern void mem_total_pages(unsigned long physmem, unsigned long iomem, unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index d8b78a03855c..2d840a070c8b 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o USER_OBJS := config.o diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 30fdd5d0067b..549ecf3f5857 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -22,39 +22,19 @@ EXPORT_SYMBOL(high_physmem); extern unsigned long long physmem_size; -int __init init_maps(unsigned long physmem, unsigned long iomem, +void __init mem_total_pages(unsigned long physmem, unsigned long iomem, unsigned long highmem) { - struct page *p, *map; - unsigned long phys_len, phys_pages, highmem_len, highmem_pages; - unsigned long iomem_len, iomem_pages, total_len, total_pages; - int i; - - phys_pages = physmem >> PAGE_SHIFT; - phys_len = phys_pages * sizeof(struct page); - - iomem_pages = iomem >> PAGE_SHIFT; - iomem_len = iomem_pages * sizeof(struct page); + unsigned long phys_pages, highmem_pages; + unsigned long iomem_pages, total_pages; + phys_pages = physmem >> PAGE_SHIFT; + iomem_pages = iomem >> PAGE_SHIFT; highmem_pages = highmem >> PAGE_SHIFT; - highmem_len = highmem_pages * sizeof(struct page); - - total_pages = phys_pages + iomem_pages + highmem_pages; - total_len = phys_len + iomem_len + highmem_len; - map = alloc_bootmem_low_pages(total_len); - if (map == NULL) - return -ENOMEM; - - for (i = 0; i < total_pages; i++) { - p = &map[i]; - memset(p, 0, sizeof(struct page)); - SetPageReserved(p); - INIT_LIST_HEAD(&p->lru); - } + total_pages = phys_pages + iomem_pages + highmem_pages; max_mapnr = total_pages; - return 0; } void map_memory(unsigned long virt, unsigned long phys, unsigned long len, diff --git a/arch/um/kernel/stacktrace.c b/arch/um/kernel/stacktrace.c new file mode 100644 index 000000000000..ebe7bcf62684 --- /dev/null +++ b/arch/um/kernel/stacktrace.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2013 Richard Weinberger <richard@nod.at> + * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kallsyms.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/stacktrace.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <asm/stacktrace.h> + +void dump_trace(struct task_struct *tsk, + const struct stacktrace_ops *ops, + void *data) +{ + int reliable = 0; + unsigned long *sp, bp, addr; + struct pt_regs *segv_regs = tsk->thread.segv_regs; + struct stack_frame *frame; + + bp = get_frame_pointer(tsk, segv_regs); + sp = get_stack_pointer(tsk, segv_regs); + + frame = (struct stack_frame *)bp; + while (((long) sp & (THREAD_SIZE-1)) != 0) { + addr = *sp; + if (__kernel_text_address(addr)) { + reliable = 0; + if ((unsigned long) sp == bp + sizeof(long)) { + frame = frame ? frame->next_frame : NULL; + bp = (unsigned long)frame; + reliable = 1; + } + ops->address(data, addr, reliable); + } + sp++; + } +} + +static void save_addr(void *data, unsigned long address, int reliable) +{ + struct stack_trace *trace = data; + + if (!reliable) + return; + if (trace->nr_entries >= trace->max_entries) + return; + + trace->entries[trace->nr_entries++] = address; +} + +static const struct stacktrace_ops dump_ops = { + .address = save_addr +}; + +static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace) +{ + dump_trace(tsk, &dump_ops, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} + +void save_stack_trace(struct stack_trace *trace) +{ + __save_stack_trace(current, trace); +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + __save_stack_trace(tsk, trace); +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 799d7e413bf5..894c8d303cda 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -12,57 +12,20 @@ #include <linux/module.h> #include <linux/sched.h> #include <asm/sysrq.h> +#include <asm/stacktrace.h> #include <os.h> -struct stack_frame { - struct stack_frame *next_frame; - unsigned long return_address; -}; - -static void do_stack_trace(unsigned long *sp, unsigned long bp) +static void _print_addr(void *data, unsigned long address, int reliable) { - int reliable; - unsigned long addr; - struct stack_frame *frame = (struct stack_frame *)bp; - - printk(KERN_INFO "Call Trace:\n"); - while (((long) sp & (THREAD_SIZE-1)) != 0) { - addr = *sp; - if (__kernel_text_address(addr)) { - reliable = 0; - if ((unsigned long) sp == bp + sizeof(long)) { - frame = frame ? frame->next_frame : NULL; - bp = (unsigned long)frame; - reliable = 1; - } - - printk(KERN_INFO " [<%08lx>]", addr); - printk(KERN_CONT " %s", reliable ? "" : "? "); - print_symbol(KERN_CONT "%s", addr); - printk(KERN_CONT "\n"); - } - sp++; - } - printk(KERN_INFO "\n"); + pr_info(" [<%08lx>]", address); + pr_cont(" %s", reliable ? "" : "? "); + print_symbol("%s", address); + pr_cont("\n"); } -static unsigned long get_frame_pointer(struct task_struct *task, - struct pt_regs *segv_regs) -{ - if (!task || task == current) - return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); - else - return KSTK_EBP(task); -} - -static unsigned long *get_stack_pointer(struct task_struct *task, - struct pt_regs *segv_regs) -{ - if (!task || task == current) - return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); - else - return (unsigned long *)KSTK_ESP(task); -} +static const struct stacktrace_ops stackops = { + .address = _print_addr +}; void show_stack(struct task_struct *task, unsigned long *stack) { @@ -71,7 +34,7 @@ void show_stack(struct task_struct *task, unsigned long *stack) int i; if (!segv_regs && os_is_signal_stack()) { - printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," + pr_err("Received SIGSEGV in SIGSEGV handler," " aborting stack trace!\n"); return; } @@ -83,16 +46,18 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (!stack) sp = get_stack_pointer(task, segv_regs); - printk(KERN_INFO "Stack:\n"); + pr_info("Stack:\n"); stack = sp; for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) { if (kstack_end(stack)) break; if (i && ((i % STACKSLOTS_PER_LINE) == 0)) - printk(KERN_CONT "\n"); - printk(KERN_CONT " %08lx", *stack++); + pr_cont("\n"); + pr_cont(" %08lx", *stack++); } - printk(KERN_CONT "\n"); + pr_cont("\n"); - do_stack_trace(sp, bp); + pr_info("Call Trace:\n"); + dump_trace(current, &stackops, NULL); + pr_info("\n"); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 016adf0985d5..9274eae6ae7b 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -348,12 +348,7 @@ int __init linux_main(int argc, char **argv) start_vm = VMALLOC_START; setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); - if (init_maps(physmem_size, iomem_size, highmem)) { - printf("Failed to allocate mem_map for %Lu bytes of physical " - "memory and %Lu bytes of highmem\n", physmem_size, - highmem); - exit(1); - } + mem_total_pages(physmem_size, iomem_size, highmem); virtmem_size = physmem_size; stack = (unsigned long) argv; |