Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 942d917

Browse files
committed
xen: make multicall debug boot time selectable
Today Xen multicall debugging needs to be enabled via modifying a define in a source file for getting debug data of multicall errors encountered by users. Switch multicall debugging to depend on a boot parameter "xen_mc_debug" instead, enabling affected users to boot with the new parameter set in order to get better diagnostics. With debugging enabled print the following information in case at least one of the batched calls failed: - all calls of the batch with operation, result and caller - all parameters of each call - all parameters stored in the multicall data for each call Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Message-ID: <20240710092749.13595-1-jgross@suse.com> Signed-off-by: Juergen Gross <jgross@suse.com>
1 parent fab451d commit 942d917

File tree

2 files changed

+108
-23
lines changed

2 files changed

+108
-23
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7427,6 +7427,12 @@
74277427
Crash from Xen panic notifier, without executing late
74287428
panic() code such as dumping handler.
74297429

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+
74307436
xen_msr_safe= [X86,XEN,EARLY]
74317437
Format: <bool>
74327438
Select whether to always use non-faulting (safe) MSR

arch/x86/xen/multicalls.c

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <linux/percpu.h>
2424
#include <linux/hardirq.h>
2525
#include <linux/debugfs.h>
26+
#include <linux/jump_label.h>
27+
#include <linux/printk.h>
2628

2729
#include <asm/xen/hypercall.h>
2830

@@ -31,32 +33,111 @@
3133

3234
#define MC_BATCH 32
3335

34-
#define MC_DEBUG 0
35-
3636
#define MC_ARGS (MC_BATCH * 16)
3737

3838

3939
struct mc_buffer {
4040
unsigned mcidx, argidx, cbidx;
4141
struct multicall_entry entries[MC_BATCH];
42-
#if MC_DEBUG
43-
struct multicall_entry debug[MC_BATCH];
44-
void *caller[MC_BATCH];
45-
#endif
4642
unsigned char args[MC_ARGS];
4743
struct callback {
4844
void (*fn)(void *);
4945
void *data;
5046
} callbacks[MC_BATCH];
5147
};
5248

49+
struct mc_debug_data {
50+
struct multicall_entry entries[MC_BATCH];
51+
void *caller[MC_BATCH];
52+
size_t argsz[MC_BATCH];
53+
unsigned long *args[MC_BATCH];
54+
};
55+
5356
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
57+
static struct mc_debug_data mc_debug_data_early __initdata;
58+
static struct mc_debug_data __percpu *mc_debug_data __refdata =
59+
&mc_debug_data_early;
5460
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
5561

62+
static struct static_key mc_debug __ro_after_init;
63+
static bool mc_debug_enabled __initdata;
64+
65+
static int __init xen_parse_mc_debug(char *arg)
66+
{
67+
mc_debug_enabled = true;
68+
static_key_slow_inc(&mc_debug);
69+
70+
return 0;
71+
}
72+
early_param("xen_mc_debug", xen_parse_mc_debug);
73+
74+
static int __init mc_debug_enable(void)
75+
{
76+
struct mc_debug_data __percpu *mcdb;
77+
unsigned long flags;
78+
79+
if (!mc_debug_enabled)
80+
return 0;
81+
82+
mcdb = alloc_percpu(struct mc_debug_data);
83+
if (!mcdb) {
84+
pr_err("xen_mc_debug inactive\n");
85+
static_key_slow_dec(&mc_debug);
86+
return -ENOMEM;
87+
}
88+
89+
/* Be careful when switching to percpu debug data. */
90+
local_irq_save(flags);
91+
xen_mc_flush();
92+
mc_debug_data = mcdb;
93+
local_irq_restore(flags);
94+
95+
pr_info("xen_mc_debug active\n");
96+
97+
return 0;
98+
}
99+
early_initcall(mc_debug_enable);
100+
101+
/* Number of parameters of hypercalls used via multicalls. */
102+
static const uint8_t hpcpars[] = {
103+
[__HYPERVISOR_mmu_update] = 4,
104+
[__HYPERVISOR_stack_switch] = 2,
105+
[__HYPERVISOR_fpu_taskswitch] = 1,
106+
[__HYPERVISOR_update_descriptor] = 2,
107+
[__HYPERVISOR_update_va_mapping] = 3,
108+
[__HYPERVISOR_mmuext_op] = 4,
109+
};
110+
111+
static void print_debug_data(struct mc_buffer *b, struct mc_debug_data *mcdb,
112+
int idx)
113+
{
114+
unsigned int arg;
115+
unsigned int opidx = mcdb->entries[idx].op & 0xff;
116+
unsigned int pars = 0;
117+
118+
pr_err(" call %2d: op=%lu result=%ld caller=%pS ", idx + 1,
119+
mcdb->entries[idx].op, b->entries[idx].result,
120+
mcdb->caller[idx]);
121+
if (opidx < ARRAY_SIZE(hpcpars))
122+
pars = hpcpars[opidx];
123+
if (pars) {
124+
pr_cont("pars=");
125+
for (arg = 0; arg < pars; arg++)
126+
pr_cont("%lx ", mcdb->entries[idx].args[arg]);
127+
}
128+
if (mcdb->argsz[idx]) {
129+
pr_cont("args=");
130+
for (arg = 0; arg < mcdb->argsz[idx] / 8; arg++)
131+
pr_cont("%lx ", mcdb->args[idx][arg]);
132+
}
133+
pr_cont("\n");
134+
}
135+
56136
void xen_mc_flush(void)
57137
{
58138
struct mc_buffer *b = this_cpu_ptr(&mc_buffer);
59139
struct multicall_entry *mc;
140+
struct mc_debug_data *mcdb = NULL;
60141
int ret = 0;
61142
unsigned long flags;
62143
int i;
@@ -69,10 +150,11 @@ void xen_mc_flush(void)
69150

70151
trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx);
71152

72-
#if MC_DEBUG
73-
memcpy(b->debug, b->entries,
74-
b->mcidx * sizeof(struct multicall_entry));
75-
#endif
153+
if (static_key_false(&mc_debug)) {
154+
mcdb = this_cpu_ptr(mc_debug_data);
155+
memcpy(mcdb->entries, b->entries,
156+
b->mcidx * sizeof(struct multicall_entry));
157+
}
76158

77159
switch (b->mcidx) {
78160
case 0:
@@ -103,21 +185,14 @@ void xen_mc_flush(void)
103185
pr_err("%d of %d multicall(s) failed: cpu %d\n",
104186
ret, b->mcidx, smp_processor_id());
105187
for (i = 0; i < b->mcidx; i++) {
106-
if (b->entries[i].result < 0) {
107-
#if MC_DEBUG
108-
pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\t%pS\n",
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
188+
if (static_key_false(&mc_debug)) {
189+
print_debug_data(b, mcdb, i);
190+
} else if (b->entries[i].result < 0) {
115191
pr_err(" call %2d: op=%lu arg=[%lx] result=%ld\n",
116192
i + 1,
117193
b->entries[i].op,
118194
b->entries[i].args[0],
119195
b->entries[i].result);
120-
#endif
121196
}
122197
}
123198
}
@@ -155,9 +230,13 @@ struct multicall_space __xen_mc_entry(size_t args)
155230
}
156231

157232
ret.mc = &b->entries[b->mcidx];
158-
#if MC_DEBUG
159-
b->caller[b->mcidx] = __builtin_return_address(0);
160-
#endif
233+
if (static_key_false(&mc_debug)) {
234+
struct mc_debug_data *mcdb = this_cpu_ptr(mc_debug_data);
235+
236+
mcdb->caller[b->mcidx] = __builtin_return_address(0);
237+
mcdb->argsz[b->mcidx] = args;
238+
mcdb->args[b->mcidx] = (unsigned long *)(&b->args[argidx]);
239+
}
161240
b->mcidx++;
162241
ret.args = &b->args[argidx];
163242
b->argidx = argidx + args;

0 commit comments

Comments
 (0)