aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 21:49:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 21:49:02 -0400
commit31003e3a9df675f1ac85d7bcf8e5a5d622576375 (patch)
tree6b08171deca1bf3cdcd6968ce0859e505048c73a /arch/um
parent1ee07ef6b5db7235b133ee257a3adf507697e6b3 (diff)
parent5f786595a291092d20fafe10c5a30378971a8cc3 (diff)
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.common3
-rw-r--r--arch/um/drivers/net_kern.c4
-rw-r--r--arch/um/drivers/ubd_kern.c5
-rw-r--r--arch/um/include/asm/stacktrace.h42
-rw-r--r--arch/um/include/shared/mem_user.h2
-rw-r--r--arch/um/kernel/Makefile1
-rw-r--r--arch/um/kernel/physmem.c32
-rw-r--r--arch/um/kernel/stacktrace.c80
-rw-r--r--arch/um/kernel/sysrq.c69
-rw-r--r--arch/um/kernel/um_arch.c7
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
39 39
40config STACKTRACE_SUPPORT 40config STACKTRACE_SUPPORT
41 bool 41 bool
42 default n 42 default y
43 select STACKTRACE
43 44
44config GENERIC_CALIBRATE_DELAY 45config GENERIC_CALIBRATE_DELAY
45 bool 46 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)
659 } 659 }
660 660
661 new = alloc_bootmem(sizeof(*new)); 661 new = alloc_bootmem(sizeof(*new));
662 if (new == NULL) {
663 printk(KERN_ERR "eth_init : alloc_bootmem failed\n");
664 return 1;
665 }
666 662
667 INIT_LIST_HEAD(&new->list); 663 INIT_LIST_HEAD(&new->list);
668 new->index = n; 664 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)
1277 1277
1278 while(1){ 1278 while(1){
1279 struct ubd *dev = q->queuedata; 1279 struct ubd *dev = q->queuedata;
1280 if(dev->end_sg == 0){ 1280 if(dev->request == NULL){
1281 struct request *req = blk_fetch_request(q); 1281 struct request *req = blk_fetch_request(q);
1282 if(req == NULL) 1282 if(req == NULL)
1283 return; 1283 return;
@@ -1299,7 +1299,8 @@ static void do_ubd_request(struct request_queue *q)
1299 return; 1299 return;
1300 } 1300 }
1301 prepare_flush_request(req, io_req); 1301 prepare_flush_request(req, io_req);
1302 submit_request(io_req, dev); 1302 if (submit_request(io_req, dev) == false)
1303 return;
1303 } 1304 }
1304 1305
1305 while(dev->start_sg < dev->end_sg){ 1306 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 @@
1#ifndef _ASM_UML_STACKTRACE_H
2#define _ASM_UML_STACKTRACE_H
3
4#include <linux/uaccess.h>
5#include <linux/ptrace.h>
6
7struct stack_frame {
8 struct stack_frame *next_frame;
9 unsigned long return_address;
10};
11
12struct stacktrace_ops {
13 void (*address)(void *data, unsigned long address, int reliable);
14};
15
16#ifdef CONFIG_FRAME_POINTER
17static inline unsigned long
18get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs)
19{
20 if (!task || task == current)
21 return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
22 return KSTK_EBP(task);
23}
24#else
25static inline unsigned long
26get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs)
27{
28 return 0;
29}
30#endif
31
32static inline unsigned long
33*get_stack_pointer(struct task_struct *task, struct pt_regs *segv_regs)
34{
35 if (!task || task == current)
36 return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
37 return (unsigned long *)KSTK_ESP(task);
38}
39
40void dump_trace(struct task_struct *tsk, const struct stacktrace_ops *ops, void *data);
41
42#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;
49extern int init_mem_user(void); 49extern int init_mem_user(void);
50extern void setup_memory(void *entry); 50extern void setup_memory(void *entry);
51extern unsigned long find_iomem(char *driver, unsigned long *len_out); 51extern unsigned long find_iomem(char *driver, unsigned long *len_out);
52extern int init_maps(unsigned long physmem, unsigned long iomem, 52extern void mem_total_pages(unsigned long physmem, unsigned long iomem,
53 unsigned long highmem); 53 unsigned long highmem);
54extern unsigned long get_vm(unsigned long len); 54extern unsigned long get_vm(unsigned long len);
55extern void setup_physmem(unsigned long start, unsigned long usable, 55extern 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
19obj-$(CONFIG_GPROF) += gprof_syms.o 19obj-$(CONFIG_GPROF) += gprof_syms.o
20obj-$(CONFIG_GCOV) += gmon_syms.o 20obj-$(CONFIG_GCOV) += gmon_syms.o
21obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 21obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
22obj-$(CONFIG_STACKTRACE) += stacktrace.o
22 23
23USER_OBJS := config.o 24USER_OBJS := config.o
24 25
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);
22 22
23extern unsigned long long physmem_size; 23extern unsigned long long physmem_size;
24 24
25int __init init_maps(unsigned long physmem, unsigned long iomem, 25void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
26 unsigned long highmem) 26 unsigned long highmem)
27{ 27{
28 struct page *p, *map; 28 unsigned long phys_pages, highmem_pages;
29 unsigned long phys_len, phys_pages, highmem_len, highmem_pages; 29 unsigned long iomem_pages, total_pages;
30 unsigned long iomem_len, iomem_pages, total_len, total_pages;
31 int i;
32
33 phys_pages = physmem >> PAGE_SHIFT;
34 phys_len = phys_pages * sizeof(struct page);
35
36 iomem_pages = iomem >> PAGE_SHIFT;
37 iomem_len = iomem_pages * sizeof(struct page);
38 30
31 phys_pages = physmem >> PAGE_SHIFT;
32 iomem_pages = iomem >> PAGE_SHIFT;
39 highmem_pages = highmem >> PAGE_SHIFT; 33 highmem_pages = highmem >> PAGE_SHIFT;
40 highmem_len = highmem_pages * sizeof(struct page);
41
42 total_pages = phys_pages + iomem_pages + highmem_pages;
43 total_len = phys_len + iomem_len + highmem_len;
44 34
45 map = alloc_bootmem_low_pages(total_len); 35 total_pages = phys_pages + iomem_pages + highmem_pages;
46 if (map == NULL)
47 return -ENOMEM;
48
49 for (i = 0; i < total_pages; i++) {
50 p = &map[i];
51 memset(p, 0, sizeof(struct page));
52 SetPageReserved(p);
53 INIT_LIST_HEAD(&p->lru);
54 }
55 36
56 max_mapnr = total_pages; 37 max_mapnr = total_pages;
57 return 0;
58} 38}
59 39
60void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 40void 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 @@
1/*
2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Copyright (C) 2013 Richard Weinberger <richard@nod.at>
4 * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kallsyms.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/stacktrace.h>
15#include <linux/module.h>
16#include <linux/uaccess.h>
17#include <asm/stacktrace.h>
18
19void dump_trace(struct task_struct *tsk,
20 const struct stacktrace_ops *ops,
21 void *data)
22{
23 int reliable = 0;
24 unsigned long *sp, bp, addr;
25 struct pt_regs *segv_regs = tsk->thread.segv_regs;
26 struct stack_frame *frame;
27
28 bp = get_frame_pointer(tsk, segv_regs);
29 sp = get_stack_pointer(tsk, segv_regs);
30
31 frame = (struct stack_frame *)bp;
32 while (((long) sp & (THREAD_SIZE-1)) != 0) {
33 addr = *sp;
34 if (__kernel_text_address(addr)) {
35 reliable = 0;
36 if ((unsigned long) sp == bp + sizeof(long)) {
37 frame = frame ? frame->next_frame : NULL;
38 bp = (unsigned long)frame;
39 reliable = 1;
40 }
41 ops->address(data, addr, reliable);
42 }
43 sp++;
44 }
45}
46
47static void save_addr(void *data, unsigned long address, int reliable)
48{
49 struct stack_trace *trace = data;
50
51 if (!reliable)
52 return;
53 if (trace->nr_entries >= trace->max_entries)
54 return;
55
56 trace->entries[trace->nr_entries++] = address;
57}
58
59static const struct stacktrace_ops dump_ops = {
60 .address = save_addr
61};
62
63static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace)
64{
65 dump_trace(tsk, &dump_ops, trace);
66 if (trace->nr_entries < trace->max_entries)
67 trace->entries[trace->nr_entries++] = ULONG_MAX;
68}
69
70void save_stack_trace(struct stack_trace *trace)
71{
72 __save_stack_trace(current, trace);
73}
74EXPORT_SYMBOL_GPL(save_stack_trace);
75
76void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
77{
78 __save_stack_trace(tsk, trace);
79}
80EXPORT_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 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <asm/sysrq.h> 14#include <asm/sysrq.h>
15#include <asm/stacktrace.h>
15#include <os.h> 16#include <os.h>
16 17
17struct stack_frame { 18static void _print_addr(void *data, unsigned long address, int reliable)
18 struct stack_frame *next_frame;
19 unsigned long return_address;
20};
21
22static void do_stack_trace(unsigned long *sp, unsigned long bp)
23{ 19{
24 int reliable; 20 pr_info(" [<%08lx>]", address);
25 unsigned long addr; 21 pr_cont(" %s", reliable ? "" : "? ");
26 struct stack_frame *frame = (struct stack_frame *)bp; 22 print_symbol("%s", address);
27 23 pr_cont("\n");
28 printk(KERN_INFO "Call Trace:\n");
29 while (((long) sp & (THREAD_SIZE-1)) != 0) {
30 addr = *sp;
31 if (__kernel_text_address(addr)) {
32 reliable = 0;
33 if ((unsigned long) sp == bp + sizeof(long)) {
34 frame = frame ? frame->next_frame : NULL;
35 bp = (unsigned long)frame;
36 reliable = 1;
37 }
38
39 printk(KERN_INFO " [<%08lx>]", addr);
40 printk(KERN_CONT " %s", reliable ? "" : "? ");
41 print_symbol(KERN_CONT "%s", addr);
42 printk(KERN_CONT "\n");
43 }
44 sp++;
45 }
46 printk(KERN_INFO "\n");
47} 24}
48 25
49static unsigned long get_frame_pointer(struct task_struct *task, 26static const struct stacktrace_ops stackops = {
50 struct pt_regs *segv_regs) 27 .address = _print_addr
51{ 28};
52 if (!task || task == current)
53 return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
54 else
55 return KSTK_EBP(task);
56}
57
58static unsigned long *get_stack_pointer(struct task_struct *task,
59 struct pt_regs *segv_regs)
60{
61 if (!task || task == current)
62 return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
63 else
64 return (unsigned long *)KSTK_ESP(task);
65}
66 29
67void show_stack(struct task_struct *task, unsigned long *stack) 30void show_stack(struct task_struct *task, unsigned long *stack)
68{ 31{
@@ -71,7 +34,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
71 int i; 34 int i;
72 35
73 if (!segv_regs && os_is_signal_stack()) { 36 if (!segv_regs && os_is_signal_stack()) {
74 printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," 37 pr_err("Received SIGSEGV in SIGSEGV handler,"
75 " aborting stack trace!\n"); 38 " aborting stack trace!\n");
76 return; 39 return;
77 } 40 }
@@ -83,16 +46,18 @@ void show_stack(struct task_struct *task, unsigned long *stack)
83 if (!stack) 46 if (!stack)
84 sp = get_stack_pointer(task, segv_regs); 47 sp = get_stack_pointer(task, segv_regs);
85 48
86 printk(KERN_INFO "Stack:\n"); 49 pr_info("Stack:\n");
87 stack = sp; 50 stack = sp;
88 for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) { 51 for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) {
89 if (kstack_end(stack)) 52 if (kstack_end(stack))
90 break; 53 break;
91 if (i && ((i % STACKSLOTS_PER_LINE) == 0)) 54 if (i && ((i % STACKSLOTS_PER_LINE) == 0))
92 printk(KERN_CONT "\n"); 55 pr_cont("\n");
93 printk(KERN_CONT " %08lx", *stack++); 56 pr_cont(" %08lx", *stack++);
94 } 57 }
95 printk(KERN_CONT "\n"); 58 pr_cont("\n");
96 59
97 do_stack_trace(sp, bp); 60 pr_info("Call Trace:\n");
61 dump_trace(current, &stackops, NULL);
62 pr_info("\n");
98} 63}
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)
348 start_vm = VMALLOC_START; 348 start_vm = VMALLOC_START;
349 349
350 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); 350 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
351 if (init_maps(physmem_size, iomem_size, highmem)) { 351 mem_total_pages(physmem_size, iomem_size, highmem);
352 printf("Failed to allocate mem_map for %Lu bytes of physical "
353 "memory and %Lu bytes of highmem\n", physmem_size,
354 highmem);
355 exit(1);
356 }
357 352
358 virtmem_size = physmem_size; 353 virtmem_size = physmem_size;
359 stack = (unsigned long) argv; 354 stack = (unsigned long) argv;