diff options
-rw-r--r-- | arch/ia64/kvm/Kconfig | 3 | ||||
-rw-r--r-- | arch/powerpc/kvm/Kconfig | 11 | ||||
-rw-r--r-- | arch/powerpc/kvm/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kvm/Kconfig | 3 | ||||
-rw-r--r-- | arch/x86/kvm/Kconfig | 12 | ||||
-rw-r--r-- | arch/x86/kvm/Makefile | 1 | ||||
-rw-r--r-- | include/linux/kvm.h | 31 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 31 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 3 | ||||
-rw-r--r-- | virt/kvm/kvm_trace.c | 285 |
10 files changed, 2 insertions, 380 deletions
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig index cbadd8a65233..ef3e7be29caf 100644 --- a/arch/ia64/kvm/Kconfig +++ b/arch/ia64/kvm/Kconfig | |||
@@ -47,9 +47,6 @@ config KVM_INTEL | |||
47 | Provides support for KVM on Itanium 2 processors equipped with the VT | 47 | Provides support for KVM on Itanium 2 processors equipped with the VT |
48 | extensions. | 48 | extensions. |
49 | 49 | ||
50 | config KVM_TRACE | ||
51 | bool | ||
52 | |||
53 | source drivers/virtio/Kconfig | 50 | source drivers/virtio/Kconfig |
54 | 51 | ||
55 | endif # VIRTUALIZATION | 52 | endif # VIRTUALIZATION |
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 46019dccce1c..c29926846613 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -58,17 +58,6 @@ config KVM_E500 | |||
58 | 58 | ||
59 | If unsure, say N. | 59 | If unsure, say N. |
60 | 60 | ||
61 | config KVM_TRACE | ||
62 | bool "KVM trace support" | ||
63 | depends on KVM && MARKERS && SYSFS | ||
64 | select RELAY | ||
65 | select DEBUG_FS | ||
66 | default n | ||
67 | ---help--- | ||
68 | This option allows reading a trace of kvm-related events through | ||
69 | relayfs. Note the ABI is not considered stable and will be | ||
70 | modified in future updates. | ||
71 | |||
72 | source drivers/virtio/Kconfig | 61 | source drivers/virtio/Kconfig |
73 | 62 | ||
74 | endif # VIRTUALIZATION | 63 | endif # VIRTUALIZATION |
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 4f407f2662f7..37655fe19f2f 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile | |||
@@ -8,8 +8,6 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm | |||
8 | 8 | ||
9 | common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) | 9 | common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) |
10 | 10 | ||
11 | common-objs-$(CONFIG_KVM_TRACE) += $(addprefix ../../../virt/kvm/, kvm_trace.o) | ||
12 | |||
13 | CFLAGS_44x_tlb.o := -I. | 11 | CFLAGS_44x_tlb.o := -I. |
14 | CFLAGS_e500_tlb.o := -I. | 12 | CFLAGS_e500_tlb.o := -I. |
15 | CFLAGS_emulate.o := -I. | 13 | CFLAGS_emulate.o := -I. |
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index ad75ce33be12..bf164fc21864 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig | |||
@@ -34,9 +34,6 @@ config KVM | |||
34 | 34 | ||
35 | If unsure, say N. | 35 | If unsure, say N. |
36 | 36 | ||
37 | config KVM_TRACE | ||
38 | bool | ||
39 | |||
40 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | 37 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under |
41 | # the virtualization menu. | 38 | # the virtualization menu. |
42 | source drivers/virtio/Kconfig | 39 | source drivers/virtio/Kconfig |
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 7fbedfd34d6c..b84e571f4175 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig | |||
@@ -62,18 +62,6 @@ config KVM_AMD | |||
62 | To compile this as a module, choose M here: the module | 62 | To compile this as a module, choose M here: the module |
63 | will be called kvm-amd. | 63 | will be called kvm-amd. |
64 | 64 | ||
65 | config KVM_TRACE | ||
66 | bool "KVM trace support" | ||
67 | depends on KVM && SYSFS | ||
68 | select MARKERS | ||
69 | select RELAY | ||
70 | select DEBUG_FS | ||
71 | default n | ||
72 | ---help--- | ||
73 | This option allows reading a trace of kvm-related events through | ||
74 | relayfs. Note the ABI is not considered stable and will be | ||
75 | modified in future updates. | ||
76 | |||
77 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | 65 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under |
78 | # the virtualization menu. | 66 | # the virtualization menu. |
79 | source drivers/lguest/Kconfig | 67 | source drivers/lguest/Kconfig |
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 7c56850b82cb..afaaa7627d95 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile | |||
@@ -7,7 +7,6 @@ CFLAGS_vmx.o := -I. | |||
7 | 7 | ||
8 | kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ | 8 | kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ |
9 | coalesced_mmio.o irq_comm.o eventfd.o) | 9 | coalesced_mmio.o irq_comm.o eventfd.o) |
10 | kvm-$(CONFIG_KVM_TRACE) += $(addprefix ../../../virt/kvm/, kvm_trace.o) | ||
11 | kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) | 10 | kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) |
12 | 11 | ||
13 | kvm-y += x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ | 12 | kvm-y += x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 671051829da6..76c640834ea6 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #define KVM_API_VERSION 12 | 15 | #define KVM_API_VERSION 12 |
16 | 16 | ||
17 | /* for KVM_TRACE_ENABLE */ | 17 | /* for KVM_TRACE_ENABLE, deprecated */ |
18 | struct kvm_user_trace_setup { | 18 | struct kvm_user_trace_setup { |
19 | __u32 buf_size; /* sub_buffer size of each per-cpu */ | 19 | __u32 buf_size; /* sub_buffer size of each per-cpu */ |
20 | __u32 buf_nr; /* the number of sub_buffers of each per-cpu */ | 20 | __u32 buf_nr; /* the number of sub_buffers of each per-cpu */ |
@@ -325,35 +325,6 @@ struct kvm_guest_debug { | |||
325 | #define KVM_TRC_CYCLE_SIZE 8 | 325 | #define KVM_TRC_CYCLE_SIZE 8 |
326 | #define KVM_TRC_EXTRA_MAX 7 | 326 | #define KVM_TRC_EXTRA_MAX 7 |
327 | 327 | ||
328 | /* This structure represents a single trace buffer record. */ | ||
329 | struct kvm_trace_rec { | ||
330 | /* variable rec_val | ||
331 | * is split into: | ||
332 | * bits 0 - 27 -> event id | ||
333 | * bits 28 -30 -> number of extra data args of size u32 | ||
334 | * bits 31 -> binary indicator for if tsc is in record | ||
335 | */ | ||
336 | __u32 rec_val; | ||
337 | __u32 pid; | ||
338 | __u32 vcpu_id; | ||
339 | union { | ||
340 | struct { | ||
341 | __u64 timestamp; | ||
342 | __u32 extra_u32[KVM_TRC_EXTRA_MAX]; | ||
343 | } __attribute__((packed)) timestamp; | ||
344 | struct { | ||
345 | __u32 extra_u32[KVM_TRC_EXTRA_MAX]; | ||
346 | } notimestamp; | ||
347 | } u; | ||
348 | }; | ||
349 | |||
350 | #define TRACE_REC_EVENT_ID(val) \ | ||
351 | (0x0fffffff & (val)) | ||
352 | #define TRACE_REC_NUM_DATA_ARGS(val) \ | ||
353 | (0x70000000 & ((val) << 28)) | ||
354 | #define TRACE_REC_TCS(val) \ | ||
355 | (0x80000000 & ((val) << 31)) | ||
356 | |||
357 | #define KVMIO 0xAE | 328 | #define KVMIO 0xAE |
358 | 329 | ||
359 | /* | 330 | /* |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 06af936a250a..0604d56f6eed 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -482,37 +482,6 @@ struct kvm_stats_debugfs_item { | |||
482 | extern struct kvm_stats_debugfs_item debugfs_entries[]; | 482 | extern struct kvm_stats_debugfs_item debugfs_entries[]; |
483 | extern struct dentry *kvm_debugfs_dir; | 483 | extern struct dentry *kvm_debugfs_dir; |
484 | 484 | ||
485 | #define KVMTRACE_5D(evt, vcpu, d1, d2, d3, d4, d5, name) \ | ||
486 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
487 | vcpu, 5, d1, d2, d3, d4, d5) | ||
488 | #define KVMTRACE_4D(evt, vcpu, d1, d2, d3, d4, name) \ | ||
489 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
490 | vcpu, 4, d1, d2, d3, d4, 0) | ||
491 | #define KVMTRACE_3D(evt, vcpu, d1, d2, d3, name) \ | ||
492 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
493 | vcpu, 3, d1, d2, d3, 0, 0) | ||
494 | #define KVMTRACE_2D(evt, vcpu, d1, d2, name) \ | ||
495 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
496 | vcpu, 2, d1, d2, 0, 0, 0) | ||
497 | #define KVMTRACE_1D(evt, vcpu, d1, name) \ | ||
498 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
499 | vcpu, 1, d1, 0, 0, 0, 0) | ||
500 | #define KVMTRACE_0D(evt, vcpu, name) \ | ||
501 | trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ | ||
502 | vcpu, 0, 0, 0, 0, 0, 0) | ||
503 | |||
504 | #ifdef CONFIG_KVM_TRACE | ||
505 | int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg); | ||
506 | void kvm_trace_cleanup(void); | ||
507 | #else | ||
508 | static inline | ||
509 | int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg) | ||
510 | { | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | #define kvm_trace_cleanup() ((void)0) | ||
514 | #endif | ||
515 | |||
516 | #ifdef KVM_ARCH_WANT_MMU_NOTIFIER | 485 | #ifdef KVM_ARCH_WANT_MMU_NOTIFIER |
517 | static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_seq) | 486 | static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_seq) |
518 | { | 487 | { |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f1e2e8c373c6..bbb4029d7c4d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -2398,7 +2398,7 @@ static long kvm_dev_ioctl(struct file *filp, | |||
2398 | case KVM_TRACE_ENABLE: | 2398 | case KVM_TRACE_ENABLE: |
2399 | case KVM_TRACE_PAUSE: | 2399 | case KVM_TRACE_PAUSE: |
2400 | case KVM_TRACE_DISABLE: | 2400 | case KVM_TRACE_DISABLE: |
2401 | r = kvm_trace_ioctl(ioctl, arg); | 2401 | r = -EOPNOTSUPP; |
2402 | break; | 2402 | break; |
2403 | default: | 2403 | default: |
2404 | return kvm_arch_dev_ioctl(filp, ioctl, arg); | 2404 | return kvm_arch_dev_ioctl(filp, ioctl, arg); |
@@ -2748,7 +2748,6 @@ EXPORT_SYMBOL_GPL(kvm_init); | |||
2748 | 2748 | ||
2749 | void kvm_exit(void) | 2749 | void kvm_exit(void) |
2750 | { | 2750 | { |
2751 | kvm_trace_cleanup(); | ||
2752 | tracepoint_synchronize_unregister(); | 2751 | tracepoint_synchronize_unregister(); |
2753 | misc_deregister(&kvm_dev); | 2752 | misc_deregister(&kvm_dev); |
2754 | kmem_cache_destroy(kvm_vcpu_cache); | 2753 | kmem_cache_destroy(kvm_vcpu_cache); |
diff --git a/virt/kvm/kvm_trace.c b/virt/kvm/kvm_trace.c deleted file mode 100644 index f59874446440..000000000000 --- a/virt/kvm/kvm_trace.c +++ /dev/null | |||
@@ -1,285 +0,0 @@ | |||
1 | /* | ||
2 | * kvm trace | ||
3 | * | ||
4 | * It is designed to allow debugging traces of kvm to be generated | ||
5 | * on UP / SMP machines. Each trace entry can be timestamped so that | ||
6 | * it's possible to reconstruct a chronological record of trace events. | ||
7 | * The implementation refers to blktrace kernel support. | ||
8 | * | ||
9 | * Copyright (c) 2008 Intel Corporation | ||
10 | * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk> | ||
11 | * | ||
12 | * Authors: Feng(Eric) Liu, eric.e.liu@intel.com | ||
13 | * | ||
14 | * Date: Feb 2008 | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/relay.h> | ||
19 | #include <linux/debugfs.h> | ||
20 | #include <linux/ktime.h> | ||
21 | |||
22 | #include <linux/kvm_host.h> | ||
23 | |||
24 | #define KVM_TRACE_STATE_RUNNING (1 << 0) | ||
25 | #define KVM_TRACE_STATE_PAUSE (1 << 1) | ||
26 | #define KVM_TRACE_STATE_CLEARUP (1 << 2) | ||
27 | |||
28 | struct kvm_trace { | ||
29 | int trace_state; | ||
30 | struct rchan *rchan; | ||
31 | struct dentry *lost_file; | ||
32 | atomic_t lost_records; | ||
33 | }; | ||
34 | static struct kvm_trace *kvm_trace; | ||
35 | |||
36 | struct kvm_trace_probe { | ||
37 | const char *name; | ||
38 | const char *format; | ||
39 | u32 timestamp_in; | ||
40 | marker_probe_func *probe_func; | ||
41 | }; | ||
42 | |||
43 | static inline int calc_rec_size(int timestamp, int extra) | ||
44 | { | ||
45 | int rec_size = KVM_TRC_HEAD_SIZE; | ||
46 | |||
47 | rec_size += extra; | ||
48 | return timestamp ? rec_size += KVM_TRC_CYCLE_SIZE : rec_size; | ||
49 | } | ||
50 | |||
51 | static void kvm_add_trace(void *probe_private, void *call_data, | ||
52 | const char *format, va_list *args) | ||
53 | { | ||
54 | struct kvm_trace_probe *p = probe_private; | ||
55 | struct kvm_trace *kt = kvm_trace; | ||
56 | struct kvm_trace_rec rec; | ||
57 | struct kvm_vcpu *vcpu; | ||
58 | int i, size; | ||
59 | u32 extra; | ||
60 | |||
61 | if (unlikely(kt->trace_state != KVM_TRACE_STATE_RUNNING)) | ||
62 | return; | ||
63 | |||
64 | rec.rec_val = TRACE_REC_EVENT_ID(va_arg(*args, u32)); | ||
65 | vcpu = va_arg(*args, struct kvm_vcpu *); | ||
66 | rec.pid = current->tgid; | ||
67 | rec.vcpu_id = vcpu->vcpu_id; | ||
68 | |||
69 | extra = va_arg(*args, u32); | ||
70 | WARN_ON(!(extra <= KVM_TRC_EXTRA_MAX)); | ||
71 | extra = min_t(u32, extra, KVM_TRC_EXTRA_MAX); | ||
72 | |||
73 | rec.rec_val |= TRACE_REC_TCS(p->timestamp_in) | ||
74 | | TRACE_REC_NUM_DATA_ARGS(extra); | ||
75 | |||
76 | if (p->timestamp_in) { | ||
77 | rec.u.timestamp.timestamp = ktime_to_ns(ktime_get()); | ||
78 | |||
79 | for (i = 0; i < extra; i++) | ||
80 | rec.u.timestamp.extra_u32[i] = va_arg(*args, u32); | ||
81 | } else { | ||
82 | for (i = 0; i < extra; i++) | ||
83 | rec.u.notimestamp.extra_u32[i] = va_arg(*args, u32); | ||
84 | } | ||
85 | |||
86 | size = calc_rec_size(p->timestamp_in, extra * sizeof(u32)); | ||
87 | relay_write(kt->rchan, &rec, size); | ||
88 | } | ||
89 | |||
90 | static struct kvm_trace_probe kvm_trace_probes[] = { | ||
91 | { "kvm_trace_entryexit", "%u %p %u %u %u %u %u %u", 1, kvm_add_trace }, | ||
92 | { "kvm_trace_handler", "%u %p %u %u %u %u %u %u", 0, kvm_add_trace }, | ||
93 | }; | ||
94 | |||
95 | static int lost_records_get(void *data, u64 *val) | ||
96 | { | ||
97 | struct kvm_trace *kt = data; | ||
98 | |||
99 | *val = atomic_read(&kt->lost_records); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | DEFINE_SIMPLE_ATTRIBUTE(kvm_trace_lost_ops, lost_records_get, NULL, "%llu\n"); | ||
104 | |||
105 | /* | ||
106 | * The relay channel is used in "no-overwrite" mode, it keeps trace of how | ||
107 | * many times we encountered a full subbuffer, to tell user space app the | ||
108 | * lost records there were. | ||
109 | */ | ||
110 | static int kvm_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, | ||
111 | void *prev_subbuf, size_t prev_padding) | ||
112 | { | ||
113 | struct kvm_trace *kt; | ||
114 | |||
115 | if (!relay_buf_full(buf)) { | ||
116 | if (!prev_subbuf) { | ||
117 | /* | ||
118 | * executed only once when the channel is opened | ||
119 | * save metadata as first record | ||
120 | */ | ||
121 | subbuf_start_reserve(buf, sizeof(u32)); | ||
122 | *(u32 *)subbuf = 0x12345678; | ||
123 | } | ||
124 | |||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | kt = buf->chan->private_data; | ||
129 | atomic_inc(&kt->lost_records); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static struct dentry *kvm_create_buf_file_callack(const char *filename, | ||
135 | struct dentry *parent, | ||
136 | int mode, | ||
137 | struct rchan_buf *buf, | ||
138 | int *is_global) | ||
139 | { | ||
140 | return debugfs_create_file(filename, mode, parent, buf, | ||
141 | &relay_file_operations); | ||
142 | } | ||
143 | |||
144 | static int kvm_remove_buf_file_callback(struct dentry *dentry) | ||
145 | { | ||
146 | debugfs_remove(dentry); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static struct rchan_callbacks kvm_relay_callbacks = { | ||
151 | .subbuf_start = kvm_subbuf_start_callback, | ||
152 | .create_buf_file = kvm_create_buf_file_callack, | ||
153 | .remove_buf_file = kvm_remove_buf_file_callback, | ||
154 | }; | ||
155 | |||
156 | static int do_kvm_trace_enable(struct kvm_user_trace_setup *kuts) | ||
157 | { | ||
158 | struct kvm_trace *kt; | ||
159 | int i, r = -ENOMEM; | ||
160 | |||
161 | if (!kuts->buf_size || !kuts->buf_nr) | ||
162 | return -EINVAL; | ||
163 | |||
164 | kt = kzalloc(sizeof(*kt), GFP_KERNEL); | ||
165 | if (!kt) | ||
166 | goto err; | ||
167 | |||
168 | r = -EIO; | ||
169 | atomic_set(&kt->lost_records, 0); | ||
170 | kt->lost_file = debugfs_create_file("lost_records", 0444, kvm_debugfs_dir, | ||
171 | kt, &kvm_trace_lost_ops); | ||
172 | if (!kt->lost_file) | ||
173 | goto err; | ||
174 | |||
175 | kt->rchan = relay_open("trace", kvm_debugfs_dir, kuts->buf_size, | ||
176 | kuts->buf_nr, &kvm_relay_callbacks, kt); | ||
177 | if (!kt->rchan) | ||
178 | goto err; | ||
179 | |||
180 | kvm_trace = kt; | ||
181 | |||
182 | for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) { | ||
183 | struct kvm_trace_probe *p = &kvm_trace_probes[i]; | ||
184 | |||
185 | r = marker_probe_register(p->name, p->format, p->probe_func, p); | ||
186 | if (r) | ||
187 | printk(KERN_INFO "Unable to register probe %s\n", | ||
188 | p->name); | ||
189 | } | ||
190 | |||
191 | kvm_trace->trace_state = KVM_TRACE_STATE_RUNNING; | ||
192 | |||
193 | return 0; | ||
194 | err: | ||
195 | if (kt) { | ||
196 | if (kt->lost_file) | ||
197 | debugfs_remove(kt->lost_file); | ||
198 | if (kt->rchan) | ||
199 | relay_close(kt->rchan); | ||
200 | kfree(kt); | ||
201 | } | ||
202 | return r; | ||
203 | } | ||
204 | |||
205 | static int kvm_trace_enable(char __user *arg) | ||
206 | { | ||
207 | struct kvm_user_trace_setup kuts; | ||
208 | int ret; | ||
209 | |||
210 | ret = copy_from_user(&kuts, arg, sizeof(kuts)); | ||
211 | if (ret) | ||
212 | return -EFAULT; | ||
213 | |||
214 | ret = do_kvm_trace_enable(&kuts); | ||
215 | if (ret) | ||
216 | return ret; | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int kvm_trace_pause(void) | ||
222 | { | ||
223 | struct kvm_trace *kt = kvm_trace; | ||
224 | int r = -EINVAL; | ||
225 | |||
226 | if (kt == NULL) | ||
227 | return r; | ||
228 | |||
229 | if (kt->trace_state == KVM_TRACE_STATE_RUNNING) { | ||
230 | kt->trace_state = KVM_TRACE_STATE_PAUSE; | ||
231 | relay_flush(kt->rchan); | ||
232 | r = 0; | ||
233 | } | ||
234 | |||
235 | return r; | ||
236 | } | ||
237 | |||
238 | void kvm_trace_cleanup(void) | ||
239 | { | ||
240 | struct kvm_trace *kt = kvm_trace; | ||
241 | int i; | ||
242 | |||
243 | if (kt == NULL) | ||
244 | return; | ||
245 | |||
246 | if (kt->trace_state == KVM_TRACE_STATE_RUNNING || | ||
247 | kt->trace_state == KVM_TRACE_STATE_PAUSE) { | ||
248 | |||
249 | kt->trace_state = KVM_TRACE_STATE_CLEARUP; | ||
250 | |||
251 | for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) { | ||
252 | struct kvm_trace_probe *p = &kvm_trace_probes[i]; | ||
253 | marker_probe_unregister(p->name, p->probe_func, p); | ||
254 | } | ||
255 | marker_synchronize_unregister(); | ||
256 | |||
257 | relay_close(kt->rchan); | ||
258 | debugfs_remove(kt->lost_file); | ||
259 | kfree(kt); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg) | ||
264 | { | ||
265 | void __user *argp = (void __user *)arg; | ||
266 | long r = -EINVAL; | ||
267 | |||
268 | if (!capable(CAP_SYS_ADMIN)) | ||
269 | return -EPERM; | ||
270 | |||
271 | switch (ioctl) { | ||
272 | case KVM_TRACE_ENABLE: | ||
273 | r = kvm_trace_enable(argp); | ||
274 | break; | ||
275 | case KVM_TRACE_PAUSE: | ||
276 | r = kvm_trace_pause(); | ||
277 | break; | ||
278 | case KVM_TRACE_DISABLE: | ||
279 | r = 0; | ||
280 | kvm_trace_cleanup(); | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | return r; | ||
285 | } | ||