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 (-28 / +93 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
};
54
53
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
55
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
56
static struct mc_debug_data __percpu *mc_debug_data;
57
static struct mc_debug_data mc_debug_data_early __initdata;
54
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
58
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
55
59
60
static struct static_key mc_debug __ro_after_init;
61
static bool mc_debug_enabled __initdata;
62
63
static int __init xen_parse_mc_debug(char *arg)
64
{
65
	mc_debug_enabled = true;
66
	static_key_slow_inc(&mc_debug);
67
68
	return 0;
69
}
70
early_param("xen_mc_debug", xen_parse_mc_debug);
71
72
static int __init mc_debug_enable(void)
73
{
74
	struct mc_debug_data __percpu *mcdb;
75
	unsigned long flags;
76
77
	if (!mc_debug_enabled)
78
		return 0;
79
80
	mcdb = alloc_percpu(struct mc_debug_data);
81
	if (!mcdb) {
82
		pr_err("xen_mc_debug inactive\n");
83
		static_key_slow_dec(&mc_debug);
84
		return -ENOMEM;
85
	}
86
87
	/* Be careful when switching to percpu debug data. */
88
	local_irq_save(flags);
89
	xen_mc_flush();
90
	mc_debug_data = mcdb;
91
	local_irq_restore(flags);
92
93
	pr_info("xen_mc_debug active\n");
94
95
	return 0;
96
}
97
early_initcall(mc_debug_enable);
98
99
static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
100
			     int idx)
101
{
102
	unsigned int arg;
103
104
	pr_err("  call %2d: op=%lu result=%ld caller=%pS", idx + 1,
105
	       mcdb->debug[idx].op, b->entries[idx].result, mcdb->caller[idx]);
106
	if (mcdb->argsz[idx]) {
107
		pr_cont(" args=");
108
		for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
109
			pr_cont("%lx ", mcdb->debug[idx].args[arg]);
110
	}
111
	pr_cont("\n");
112
}
113
114
static struct mc_debug_data * __ref get_mc_debug_ptr(void)
115
{
116
	if (likely(mc_debug_data))
117
		return this_cpu_ptr(mc_debug_data);
118
119
	return &mc_debug_data_early;
120
}
121
56
void xen_mc_flush(void)
122
void xen_mc_flush(void)
57
{
123
{
58
	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
124
	struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
59
	struct multicall_entry *mc;
125
	struct multicall_entry *mc;
126
	struct mc_debug_data *mcdb = NULL;
60
	int ret = 0;
127
	int ret = 0;
61
	unsigned long flags;
128
	unsigned long flags;
62
	int i;
129
	int i;
Lines 69-78 void xen_mc_flush(void) Link Here
69
136
70
	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
137
	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
71
138
72
#if MC_DEBUG
139
	if (static_key_false(&mc_debug)) {
73
	memcpy(b->debug, b->entries,
140
		mcdb = get_mc_debug_ptr();
74
	       b->mcidx * sizeof(struct multicall_entry));
141
		memcpy(mcdb->debug, b->entries,
75
#endif
142
		       b->mcidx * sizeof(struct multicall_entry));
143
	}
76
144
77
	switch (b->mcidx) {
145
	switch (b->mcidx) {
78
	case 0:
146
	case 0:
Lines 104-123 void xen_mc_flush(void) Link Here
104
		       ret, b->mcidx, smp_processor_id());
172
		       ret, b->mcidx, smp_processor_id());
105
		for (i = 0; i < b->mcidx; i++) {
173
		for (i = 0; i < b->mcidx; i++) {
106
			if (b->entries[i].result < 0) {
174
			if (b->entries[i].result < 0) {
107
#if MC_DEBUG
175
				if (static_key_false(&mc_debug)) {
108
				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\t%pS\n",
176
					print_debug_data(b, mcdb, i);
109
				       i + 1,
177
				} else {
110
				       b->debug[i].op,
178
					pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\n",
111
				       b->debug[i].args[0],
179
					       i + 1,
112
				       b->entries[i].result,
180
					       b->entries[i].op,
113
				       b->caller[i]);
181
					       b->entries[i].args[0],
114
#else
182
					       b->entries[i].result);
115
				pr_err("  call %2d: op=%lu arg=[%lx] result=%ld\n",
183
				}
116
				       i + 1,
117
				       b->entries[i].op,
118
				       b->entries[i].args[0],
119
				       b->entries[i].result);
120
#endif
121
			}
184
			}
122
		}
185
		}
123
	}
186
	}
Lines 155-163 struct multicall_space __xen_mc_entry(size_t args) Link Here
155
	}
218
	}
156
219
157
	ret.mc = &b->entries[b->mcidx];
220
	ret.mc = &b->entries[b->mcidx];
158
#if MC_DEBUG
221
	if (static_key_false(&mc_debug)) {
159
	b->caller[b->mcidx] = __builtin_return_address(0);
222
		struct mc_debug_data *mcdb = get_mc_debug_ptr();
160
#endif
223
224
		mcdb->caller[b->mcidx] = __builtin_return_address(0);
225
		mcdb->argsz[b->mcidx] = args;
226
	}
161
	b->mcidx++;
227
	b->mcidx++;
162
	ret.args = &b->args[argidx];
228
	ret.args = &b->args[argidx];
163
	b->argidx = argidx + args;
229
	b->argidx = argidx + args;
164
- 

Return to bug 1227301