diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:05 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:05 -0400 |
commit | a70ce4b6064b64477ed12ef1878980f842819094 (patch) | |
tree | 0864f1eea8570a8d3bf713d135b09d00858a4e3d | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) | |
parent | 086748e52fb072ff0935ba4512e29c421bd5b716 (diff) |
Merge branch 'upstream/core' into upstream/xen
* upstream/core:
xen/panic: use xen_reboot and fix smp_send_stop
Xen: register panic notifier to take crashes of xen guests on panic
xen: support large numbers of CPUs with vcpu info placement
xen: drop xen_sched_clock in favour of using plain wallclock time
pvops: do not notify callers from register_xenstore_notifier
xen: make sure pages are really part of domain before freeing
xen: release unused free memory
-rw-r--r-- | arch/x86/xen/enlighten.c | 41 | ||||
-rw-r--r-- | arch/x86/xen/setup.c | 72 | ||||
-rw-r--r-- | arch/x86/xen/smp.c | 2 | ||||
-rw-r--r-- | arch/x86/xen/time.c | 39 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 2 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 5 |
6 files changed, 112 insertions, 49 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 65d8d79b46a8..3c4da8bee06f 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -97,6 +97,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; | |||
97 | */ | 97 | */ |
98 | static int have_vcpu_info_placement = 1; | 98 | static int have_vcpu_info_placement = 1; |
99 | 99 | ||
100 | static void clamp_max_cpus(void) | ||
101 | { | ||
102 | #ifdef CONFIG_SMP | ||
103 | if (setup_max_cpus > MAX_VIRT_CPUS) | ||
104 | setup_max_cpus = MAX_VIRT_CPUS; | ||
105 | #endif | ||
106 | } | ||
107 | |||
100 | static void xen_vcpu_setup(int cpu) | 108 | static void xen_vcpu_setup(int cpu) |
101 | { | 109 | { |
102 | struct vcpu_register_vcpu_info info; | 110 | struct vcpu_register_vcpu_info info; |
@@ -104,13 +112,17 @@ static void xen_vcpu_setup(int cpu) | |||
104 | struct vcpu_info *vcpup; | 112 | struct vcpu_info *vcpup; |
105 | 113 | ||
106 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 114 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
107 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
108 | 115 | ||
109 | if (!have_vcpu_info_placement) | 116 | if (cpu < MAX_VIRT_CPUS) |
110 | return; /* already tested, not available */ | 117 | per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; |
111 | 118 | ||
112 | vcpup = &per_cpu(xen_vcpu_info, cpu); | 119 | if (!have_vcpu_info_placement) { |
120 | if (cpu >= MAX_VIRT_CPUS) | ||
121 | clamp_max_cpus(); | ||
122 | return; | ||
123 | } | ||
113 | 124 | ||
125 | vcpup = &per_cpu(xen_vcpu_info, cpu); | ||
114 | info.mfn = arbitrary_virt_to_mfn(vcpup); | 126 | info.mfn = arbitrary_virt_to_mfn(vcpup); |
115 | info.offset = offset_in_page(vcpup); | 127 | info.offset = offset_in_page(vcpup); |
116 | 128 | ||
@@ -125,6 +137,7 @@ static void xen_vcpu_setup(int cpu) | |||
125 | if (err) { | 137 | if (err) { |
126 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); | 138 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); |
127 | have_vcpu_info_placement = 0; | 139 | have_vcpu_info_placement = 0; |
140 | clamp_max_cpus(); | ||
128 | } else { | 141 | } else { |
129 | /* This cpu is using the registered vcpu info, even if | 142 | /* This cpu is using the registered vcpu info, even if |
130 | later ones fail to. */ | 143 | later ones fail to. */ |
@@ -731,7 +744,6 @@ static void set_xen_basic_apic_ops(void) | |||
731 | 744 | ||
732 | #endif | 745 | #endif |
733 | 746 | ||
734 | |||
735 | static void xen_clts(void) | 747 | static void xen_clts(void) |
736 | { | 748 | { |
737 | struct multicall_space mcs; | 749 | struct multicall_space mcs; |
@@ -927,7 +939,7 @@ static const struct pv_init_ops xen_init_ops __initdata = { | |||
927 | }; | 939 | }; |
928 | 940 | ||
929 | static const struct pv_time_ops xen_time_ops __initdata = { | 941 | static const struct pv_time_ops xen_time_ops __initdata = { |
930 | .sched_clock = xen_sched_clock, | 942 | .sched_clock = xen_clocksource_read, |
931 | }; | 943 | }; |
932 | 944 | ||
933 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { | 945 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { |
@@ -1028,6 +1040,23 @@ static void xen_crash_shutdown(struct pt_regs *regs) | |||
1028 | xen_reboot(SHUTDOWN_crash); | 1040 | xen_reboot(SHUTDOWN_crash); |
1029 | } | 1041 | } |
1030 | 1042 | ||
1043 | static int | ||
1044 | xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
1045 | { | ||
1046 | xen_reboot(SHUTDOWN_crash); | ||
1047 | return NOTIFY_DONE; | ||
1048 | } | ||
1049 | |||
1050 | static struct notifier_block xen_panic_block = { | ||
1051 | .notifier_call= xen_panic_event, | ||
1052 | }; | ||
1053 | |||
1054 | int xen_panic_handler_init(void) | ||
1055 | { | ||
1056 | atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); | ||
1057 | return 0; | ||
1058 | } | ||
1059 | |||
1031 | static const struct machine_ops __initdata xen_machine_ops = { | 1060 | static const struct machine_ops __initdata xen_machine_ops = { |
1032 | .restart = xen_restart, | 1061 | .restart = xen_restart, |
1033 | .halt = xen_machine_halt, | 1062 | .halt = xen_machine_halt, |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index ad0047f47cd4..328b00305426 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <xen/page.h> | 20 | #include <xen/page.h> |
21 | #include <xen/interface/callback.h> | 21 | #include <xen/interface/callback.h> |
22 | #include <xen/interface/physdev.h> | 22 | #include <xen/interface/physdev.h> |
23 | #include <xen/interface/memory.h> | ||
23 | #include <xen/features.h> | 24 | #include <xen/features.h> |
24 | 25 | ||
25 | #include "xen-ops.h" | 26 | #include "xen-ops.h" |
@@ -32,6 +33,73 @@ extern void xen_sysenter_target(void); | |||
32 | extern void xen_syscall_target(void); | 33 | extern void xen_syscall_target(void); |
33 | extern void xen_syscall32_target(void); | 34 | extern void xen_syscall32_target(void); |
34 | 35 | ||
36 | static unsigned long __init xen_release_chunk(phys_addr_t start_addr, | ||
37 | phys_addr_t end_addr) | ||
38 | { | ||
39 | struct xen_memory_reservation reservation = { | ||
40 | .address_bits = 0, | ||
41 | .extent_order = 0, | ||
42 | .domid = DOMID_SELF | ||
43 | }; | ||
44 | unsigned long start, end; | ||
45 | unsigned long len = 0; | ||
46 | unsigned long pfn; | ||
47 | int ret; | ||
48 | |||
49 | start = PFN_UP(start_addr); | ||
50 | end = PFN_DOWN(end_addr); | ||
51 | |||
52 | if (end <= start) | ||
53 | return 0; | ||
54 | |||
55 | printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ", | ||
56 | start, end); | ||
57 | for(pfn = start; pfn < end; pfn++) { | ||
58 | unsigned long mfn = pfn_to_mfn(pfn); | ||
59 | |||
60 | /* Make sure pfn exists to start with */ | ||
61 | if (mfn == INVALID_P2M_ENTRY || mfn_to_pfn(mfn) != pfn) | ||
62 | continue; | ||
63 | |||
64 | set_xen_guest_handle(reservation.extent_start, &mfn); | ||
65 | reservation.nr_extents = 1; | ||
66 | |||
67 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | ||
68 | &reservation); | ||
69 | WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n", | ||
70 | start, end, ret); | ||
71 | if (ret == 1) { | ||
72 | set_phys_to_machine(pfn, INVALID_P2M_ENTRY); | ||
73 | len++; | ||
74 | } | ||
75 | } | ||
76 | printk(KERN_CONT "%ld pages freed\n", len); | ||
77 | |||
78 | return len; | ||
79 | } | ||
80 | |||
81 | static unsigned long __init xen_return_unused_memory(unsigned long max_pfn, | ||
82 | const struct e820map *e820) | ||
83 | { | ||
84 | phys_addr_t max_addr = PFN_PHYS(max_pfn); | ||
85 | phys_addr_t last_end = 0; | ||
86 | unsigned long released = 0; | ||
87 | int i; | ||
88 | |||
89 | for (i = 0; i < e820->nr_map && last_end < max_addr; i++) { | ||
90 | phys_addr_t end = e820->map[i].addr; | ||
91 | end = min(max_addr, end); | ||
92 | |||
93 | released += xen_release_chunk(last_end, end); | ||
94 | last_end = e820->map[i].addr + e820->map[i].size; | ||
95 | } | ||
96 | |||
97 | if (last_end < max_addr) | ||
98 | released += xen_release_chunk(last_end, max_addr); | ||
99 | |||
100 | printk(KERN_INFO "released %ld pages of unused memory\n", released); | ||
101 | return released; | ||
102 | } | ||
35 | 103 | ||
36 | /** | 104 | /** |
37 | * machine_specific_memory_setup - Hook for machine specific memory setup. | 105 | * machine_specific_memory_setup - Hook for machine specific memory setup. |
@@ -67,6 +135,8 @@ char * __init xen_memory_setup(void) | |||
67 | 135 | ||
68 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 136 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
69 | 137 | ||
138 | xen_return_unused_memory(xen_start_info->nr_pages, &e820); | ||
139 | |||
70 | return "Xen"; | 140 | return "Xen"; |
71 | } | 141 | } |
72 | 142 | ||
@@ -156,6 +226,8 @@ void __init xen_arch_setup(void) | |||
156 | struct physdev_set_iopl set_iopl; | 226 | struct physdev_set_iopl set_iopl; |
157 | int rc; | 227 | int rc; |
158 | 228 | ||
229 | xen_panic_handler_init(); | ||
230 | |||
159 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); | 231 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); |
160 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); | 232 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); |
161 | 233 | ||
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index a29693fd3138..25f232b18a82 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -394,6 +394,8 @@ static void stop_self(void *v) | |||
394 | load_cr3(swapper_pg_dir); | 394 | load_cr3(swapper_pg_dir); |
395 | /* should set up a minimal gdt */ | 395 | /* should set up a minimal gdt */ |
396 | 396 | ||
397 | set_cpu_online(cpu, false); | ||
398 | |||
397 | HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL); | 399 | HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL); |
398 | BUG(); | 400 | BUG(); |
399 | } | 401 | } |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index b3c6c59ed302..a86df42e46ad 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
@@ -155,45 +155,6 @@ static void do_stolen_accounting(void) | |||
155 | account_idle_ticks(ticks); | 155 | account_idle_ticks(ticks); |
156 | } | 156 | } |
157 | 157 | ||
158 | /* | ||
159 | * Xen sched_clock implementation. Returns the number of unstolen | ||
160 | * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED | ||
161 | * states. | ||
162 | */ | ||
163 | unsigned long long xen_sched_clock(void) | ||
164 | { | ||
165 | struct vcpu_runstate_info state; | ||
166 | cycle_t now; | ||
167 | u64 ret; | ||
168 | s64 offset; | ||
169 | |||
170 | /* | ||
171 | * Ideally sched_clock should be called on a per-cpu basis | ||
172 | * anyway, so preempt should already be disabled, but that's | ||
173 | * not current practice at the moment. | ||
174 | */ | ||
175 | preempt_disable(); | ||
176 | |||
177 | now = xen_clocksource_read(); | ||
178 | |||
179 | get_runstate_snapshot(&state); | ||
180 | |||
181 | WARN_ON(state.state != RUNSTATE_running); | ||
182 | |||
183 | offset = now - state.state_entry_time; | ||
184 | if (offset < 0) | ||
185 | offset = 0; | ||
186 | |||
187 | ret = state.time[RUNSTATE_blocked] + | ||
188 | state.time[RUNSTATE_running] + | ||
189 | offset; | ||
190 | |||
191 | preempt_enable(); | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | |||
197 | /* Get the TSC speed from Xen */ | 158 | /* Get the TSC speed from Xen */ |
198 | unsigned long xen_tsc_khz(void) | 159 | unsigned long xen_tsc_khz(void) |
199 | { | 160 | { |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index f9153a300bce..00d59d608edf 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -101,4 +101,6 @@ void xen_sysret32(void); | |||
101 | void xen_sysret64(void); | 101 | void xen_sysret64(void); |
102 | void xen_adjust_exception_frame(void); | 102 | void xen_adjust_exception_frame(void); |
103 | 103 | ||
104 | extern int xen_panic_handler_init(void); | ||
105 | |||
104 | #endif /* XEN_OPS_H */ | 106 | #endif /* XEN_OPS_H */ |
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 3479332113e9..abc12426ef0a 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -752,10 +752,7 @@ int register_xenstore_notifier(struct notifier_block *nb) | |||
752 | { | 752 | { |
753 | int ret = 0; | 753 | int ret = 0; |
754 | 754 | ||
755 | if (xenstored_ready > 0) | 755 | blocking_notifier_chain_register(&xenstore_chain, nb); |
756 | ret = nb->notifier_call(nb, 0, NULL); | ||
757 | else | ||
758 | blocking_notifier_chain_register(&xenstore_chain, nb); | ||
759 | 756 | ||
760 | return ret; | 757 | return ret; |
761 | } | 758 | } |