View | Details | Raw Unified | Return to bug 1227301
Collapse All | Expand All

(-)a/Documentation/admin-guide/kernel-parameters.txt (+6 lines)
Lines 7427-7432 Link Here
7427
			Crash from Xen panic notifier, without executing late
7427
			Crash from Xen panic notifier, without executing late
7428
			panic() code such as dumping handler.
7428
			panic() code such as dumping handler.
7429
7429
7430
	xen_mc_debug	[X86,XEN,EARLY]
7431
			Enable multicall debugging when running as a Xen PV guest.
7432
			Enabling this feature will reduce performance a little
7433
			bit, so it should only be enabled for obtaining extended
7434
			debug data in case of multicall errors.
7435
7430
	xen_msr_safe=	[X86,XEN,EARLY]
7436
	xen_msr_safe=	[X86,XEN,EARLY]
7431
			Format: <bool>
7437
			Format: <bool>
7432
			Select whether to always use non-faulting (safe) MSR
7438
			Select whether to always use non-faulting (safe) MSR
(-)a/arch/x86/xen/multicalls.c (-24 / +108 lines)
Lines 23-28 Link Here
23
#include <linux/percpu.h>
23
#include <linux/percpu.h>
24
#include <linux/hardirq.h>
24
#include <linux/hardirq.h>
25
#include <linux/debugfs.h>
25
#include <linux/debugfs.h>
26
#include <linux/jump_label.h>
27
#include <linux/printk.h>
26
28
27
#include <asm/xen/hypercall.h>
29
#include <asm/xen/hypercall.h>
28
30
Lines 31-48 Link Here
31
33
32
#define MC_BATCH	32
34
#define MC_BATCH	32
33
35
34
#define MC_DEBUG	0
35
36
#define MC_ARGS		(MC_BATCH * 16)
36
#define MC_ARGS		(MC_BATCH * 16)
37
37
38
38
39
struct mc_buffer {
39
struct mc_buffer {
40
	unsigned mcidx, argidx, cbidx;
40
	unsigned mcidx, argidx, cbidx;
41
	struct multicall_entry entries[MC_BATCH];
41
	struct multicall_entry entries[MC_BATCH];
42
#if MC_DEBUG
43
	struct multicall_entry debug[MC_BATCH];
44
	void *caller[MC_BATCH];
45
#endif
46
	unsigned char args[MC_ARGS];
42
	unsigned char args[MC_ARGS];
47
	struct callback {
43
	struct callback {
48
		void (*fn)(void *);
44
		void (*fn)(void *);
Lines 50-62 struct mc_buffer { Link Here
50
	} callbacks[MC_BATCH];
46
	} callbacks[MC_BATCH];
51
};
47
};
52
48
49
struct mc_debug_data {
50
	struct multicall_entry debug[MC_BATCH];
51
	void *caller[MC_BATCH];
52
	size_t argsz[MC_BATCH];
53
	unsigned long *args[MC_BATCH];
54
};
55
53
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
56
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
57
static struct mc_debug_data __percpu *mc_debug_data;
58
static struct mc_debug_data mc_debug_data_early __initdata;
54
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
59
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
55
60
61
static struct static_key mc_debug __ro_after_init;
62
static bool mc_debug_enabled __initdata;
63
64
static int __init xen_parse_mc_debug(char *arg)
65
{
66
	mc_debug_enabled = true;
67
	static_key_slow_inc(&mc_debug);
68
69
	return 0;
70
}
71
early_param("xen_mc_debug", xen_parse_mc_debug);
72
73
static int __init mc_debug_enable(void)
74
{
75
	struct mc_debug_data __percpu *mcdb;
76
	unsigned long flags;
77
78
	if (!mc_debug_enabled)
79
		return 0;
80
81
	mcdb = alloc_percpu(struct mc_debug_data);
82
	if (!mcdb) {
83
		pr_err("xen_mc_debug inactive\n");
84
		static_key_slow_dec(&mc_debug);
85
		return -ENOMEM;
86
	}
87
88
	/* Be careful when switching to percpu debug data. */
89
	local_irq_save(flags);
90
	xen_mc_flush();
91
	mc_debug_data = mcdb;
92
	local_irq_restore(flags);
93
94
	pr_info("xen_mc_debug active\n");
95
96
	return 0;
97
}
98
early_initcall(mc_debug_enable);
99
100
/* Number of parameters of hypercalls used via multicalls. */
101
static const uint8_t hpcpars[] = {
102
	[__HYPERVISOR_mmu_update] = 4,
103
	[__HYPERVISOR_stack_switch] = 2,
104
	[__HYPERVISOR_fpu_taskswitch] = 1,
105
	[__HYPERVISOR_update_descriptor] = 2,
106
	[__HYPERVISOR_update_va_mapping] = 3,
107
	[__HYPERVISOR_mmuext_op] = 4,
108
};
109
110
static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
111
			     int idx)
112
{
113
	unsigned int arg;
114
	unsigned int opidx = mcdb->debug[idx].op & 0xff;
115
	unsigned int pars = 0;
116
117
	pr_err("  call %2d: op=%lu result=%ld caller=%pS ", idx + 1,
118
	       mcdb->debug[idx].op, b->entries[idx].result, mcdb->caller[idx]);
119
	if (opidx < ARRAY_SIZE(hpcpars))
120
		pars = hpcpars[opidx];
121
	if (pars) {
122
		pr_cont("pars=");
123
		for (arg = 0; arg < pars; arg++)
124
			pr_cont("%lx ", mcdb->debug[idx].args[arg]);
125
	}
126
	if (mcdb->argsz[idx]) {
127
		pr_cont("args=");
128
		for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
129
			pr_cont("%lx ", mcdb->args[idx][arg]);
130
	}
131
	pr_cont("\n");
132
}
133
134
static struct mc_debug_data * __ref get_mc_debug_ptr(void)
135
{
136
	if (likely(mc_debug_data))
137
		return this_cpu_ptr(mc_debug_data);
138
139
	return &mc_debug_data_early;
140
}
141
56
void xen_mc_flush(void)
142
void xen_mc_flush(void)
57
{
143
{
58
	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
144
	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
59
	struct multicall_entry *mc;
145
	struct multicall_entry *mc;
146
	struct mc_debug_data *mcdb = NULL;
60
	int ret = 0;
147
	int ret = 0;
61
	unsigned long flags;
148
	unsigned long flags;
62
	int i;
149
	int i;
Lines 69-78 void xen_mc_flush(void) Link Here
69
156
70
	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
157
	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
71
158
72
#if MC_DEBUG
159
	if (static_key_false(&mc_debug)) {
73
	memcpy(b->debug, b->entries,
160
		mcdb = get_mc_debug_ptr();
74
	       b->mcidx * sizeof(struct multicall_entry));
161
		memcpy(mcdb->debug, b->entries,
75
#endif
162
		       b->mcidx * sizeof(struct multicall_entry));
163
	}
76
164
77
	switch (b->mcidx) {
165
	switch (b->mcidx) {
78
	case 0:
166
	case 0:
Lines 103-123 void xen_mc_flush(void) Link Here
103
		pr_err("%d of %d multicall(s) failed: cpu %d\n",
191
		pr_err("%d of %d multicall(s) failed: cpu %d\n",
104
		       ret, b->mcidx, smp_processor_id());
192
		       ret, b->mcidx, smp_processor_id());
105
		for (i = 0; i < b->mcidx; i++) {
193
		for (i = 0; i < b->mcidx; i++) {
106
			if (b->entries[i].result < 0) {
194
			if (static_key_false(&mc_debug)) {
107
#if MC_DEBUG
195
				print_debug_data(b, mcdb, i);
108
				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\t%pS\n",
196
			} else if (b->entries[i].result < 0) {
109
				       i + 1,
110
				       b->debug[i].op,
111
				       b->debug[i].args[0],
112
				       b->entries[i].result,
113
				       b->caller[i]);
114
#else
115
				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\n",
197
				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\n",
116
				       i + 1,
198
				       i + 1,
117
				       b->entries[i].op,
199
				       b->entries[i].op,
118
				       b->entries[i].args[0],
200
				       b->entries[i].args[0],
119
				       b->entries[i].result);
201
				       b->entries[i].result);
120
#endif
121
			}
202
			}
122
		}
203
		}
123
	}
204
	}
Lines 155-163 struct multicall_space __xen_mc_entry(size_t args) Link Here
155
	}
236
	}
156
237
157
	ret.mc = &b->entries[b->mcidx];
238
	ret.mc = &b->entries[b->mcidx];
158
#if MC_DEBUG
239
	if (static_key_false(&mc_debug)) {
159
	b->caller[b->mcidx] = __builtin_return_address(0);
240
		struct mc_debug_data *mcdb = get_mc_debug_ptr();
160
#endif
241
242
		mcdb->caller[b->mcidx] = __builtin_return_address(0);
243
		mcdb->argsz[b->mcidx] = args;
244
		mcdb->args[b->mcidx] = (unsigned long *)(&b->args[argidx]);
245
	}
161
	b->mcidx++;
246
	b->mcidx++;
162
	ret.args = &b->args[argidx];
247
	ret.args = &b->args[argidx];
163
	b->argidx = argidx + args;
248
	b->argidx = argidx + args;
164
- 

Return to bug 1227301