diff options
author | Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | 2010-08-30 06:22:53 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:51:56 -0400 |
commit | 8b1fe17cc7a8b2c62b400dcbfaebd96da6b4f58e (patch) | |
tree | d453a7a24163e58fee9830b42c101fd717a0f67c /arch/x86/kvm | |
parent | 84e0cefa8ddd5d5018d3b582e1e90585ed551757 (diff) |
KVM: MMU: support disable/enable mmu audit dynamicly
Add a r/w module parameter named 'mmu_audit', it can control audit
enable/disable:
enable:
echo 1 > /sys/module/kvm/parameters/mmu_audit
disable:
echo 0 > /sys/module/kvm/parameters/mmu_audit
This patch not change the logic
Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/Kconfig | 7 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 91 | ||||
-rw-r--r-- | arch/x86/kvm/mmutrace.h | 19 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 4 |
4 files changed, 101 insertions, 20 deletions
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 970bbd479516..ddc131ff438f 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig | |||
@@ -64,6 +64,13 @@ config KVM_AMD | |||
64 | To compile this as a module, choose M here: the module | 64 | To compile this as a module, choose M here: the module |
65 | will be called kvm-amd. | 65 | will be called kvm-amd. |
66 | 66 | ||
67 | config KVM_MMU_AUDIT | ||
68 | bool "Audit KVM MMU" | ||
69 | depends on KVM && TRACEPOINTS | ||
70 | ---help--- | ||
71 | This option adds a R/W kVM module parameter 'mmu_audit', which allows | ||
72 | audit KVM MMU at runtime. | ||
73 | |||
67 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | 74 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under |
68 | # the virtualization menu. | 75 | # the virtualization menu. |
69 | source drivers/vhost/Kconfig | 76 | source drivers/vhost/Kconfig |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 0bff4d54817e..8b750ff6911a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -49,15 +49,21 @@ | |||
49 | */ | 49 | */ |
50 | bool tdp_enabled = false; | 50 | bool tdp_enabled = false; |
51 | 51 | ||
52 | #undef MMU_DEBUG | 52 | enum { |
53 | AUDIT_PRE_PAGE_FAULT, | ||
54 | AUDIT_POST_PAGE_FAULT, | ||
55 | AUDIT_PRE_PTE_WRITE, | ||
56 | AUDIT_POST_PTE_WRITE | ||
57 | }; | ||
53 | 58 | ||
54 | #undef AUDIT | 59 | char *audit_point_name[] = { |
60 | "pre page fault", | ||
61 | "post page fault", | ||
62 | "pre pte write", | ||
63 | "post pte write" | ||
64 | }; | ||
55 | 65 | ||
56 | #ifdef AUDIT | 66 | #undef MMU_DEBUG |
57 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); | ||
58 | #else | ||
59 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} | ||
60 | #endif | ||
61 | 67 | ||
62 | #ifdef MMU_DEBUG | 68 | #ifdef MMU_DEBUG |
63 | 69 | ||
@@ -71,7 +77,7 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} | |||
71 | 77 | ||
72 | #endif | 78 | #endif |
73 | 79 | ||
74 | #if defined(MMU_DEBUG) || defined(AUDIT) | 80 | #ifdef MMU_DEBUG |
75 | static int dbg = 0; | 81 | static int dbg = 0; |
76 | module_param(dbg, bool, 0644); | 82 | module_param(dbg, bool, 0644); |
77 | #endif | 83 | #endif |
@@ -2964,7 +2970,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
2964 | kvm_mmu_access_page(vcpu, gfn); | 2970 | kvm_mmu_access_page(vcpu, gfn); |
2965 | kvm_mmu_free_some_pages(vcpu); | 2971 | kvm_mmu_free_some_pages(vcpu); |
2966 | ++vcpu->kvm->stat.mmu_pte_write; | 2972 | ++vcpu->kvm->stat.mmu_pte_write; |
2967 | kvm_mmu_audit(vcpu, "pre pte write"); | 2973 | trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE); |
2968 | if (guest_initiated) { | 2974 | if (guest_initiated) { |
2969 | if (gfn == vcpu->arch.last_pt_write_gfn | 2975 | if (gfn == vcpu->arch.last_pt_write_gfn |
2970 | && !last_updated_pte_accessed(vcpu)) { | 2976 | && !last_updated_pte_accessed(vcpu)) { |
@@ -3037,7 +3043,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
3037 | } | 3043 | } |
3038 | mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush); | 3044 | mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush); |
3039 | kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); | 3045 | kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); |
3040 | kvm_mmu_audit(vcpu, "post pte write"); | 3046 | trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE); |
3041 | spin_unlock(&vcpu->kvm->mmu_lock); | 3047 | spin_unlock(&vcpu->kvm->mmu_lock); |
3042 | if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { | 3048 | if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { |
3043 | kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); | 3049 | kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); |
@@ -3483,8 +3489,7 @@ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]) | |||
3483 | } | 3489 | } |
3484 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); | 3490 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); |
3485 | 3491 | ||
3486 | #ifdef AUDIT | 3492 | #ifdef CONFIG_KVM_MMU_AUDIT |
3487 | |||
3488 | static const char *audit_msg; | 3493 | static const char *audit_msg; |
3489 | 3494 | ||
3490 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); | 3495 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); |
@@ -3699,18 +3704,68 @@ static void audit_write_protection(struct kvm_vcpu *vcpu) | |||
3699 | } | 3704 | } |
3700 | } | 3705 | } |
3701 | 3706 | ||
3702 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) | 3707 | static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point) |
3703 | { | 3708 | { |
3704 | int olddbg = dbg; | 3709 | audit_msg = audit_point_name[audit_point]; |
3705 | |||
3706 | dbg = 0; | ||
3707 | audit_msg = msg; | ||
3708 | audit_rmap(vcpu); | 3710 | audit_rmap(vcpu); |
3709 | audit_write_protection(vcpu); | 3711 | audit_write_protection(vcpu); |
3710 | if (strcmp("pre pte write", audit_msg) != 0) | 3712 | if (strcmp("pre pte write", audit_msg) != 0) |
3711 | audit_mappings(vcpu); | 3713 | audit_mappings(vcpu); |
3712 | audit_sptes_have_rmaps(vcpu); | 3714 | audit_sptes_have_rmaps(vcpu); |
3713 | dbg = olddbg; | ||
3714 | } | 3715 | } |
3715 | 3716 | ||
3717 | static bool mmu_audit; | ||
3718 | |||
3719 | static void mmu_audit_enable(void) | ||
3720 | { | ||
3721 | int ret; | ||
3722 | |||
3723 | if (mmu_audit) | ||
3724 | return; | ||
3725 | |||
3726 | ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); | ||
3727 | WARN_ON(ret); | ||
3728 | |||
3729 | mmu_audit = true; | ||
3730 | } | ||
3731 | |||
3732 | static void mmu_audit_disable(void) | ||
3733 | { | ||
3734 | if (!mmu_audit) | ||
3735 | return; | ||
3736 | |||
3737 | unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); | ||
3738 | tracepoint_synchronize_unregister(); | ||
3739 | mmu_audit = false; | ||
3740 | } | ||
3741 | |||
3742 | static int mmu_audit_set(const char *val, const struct kernel_param *kp) | ||
3743 | { | ||
3744 | int ret; | ||
3745 | unsigned long enable; | ||
3746 | |||
3747 | ret = strict_strtoul(val, 10, &enable); | ||
3748 | if (ret < 0) | ||
3749 | return -EINVAL; | ||
3750 | |||
3751 | switch (enable) { | ||
3752 | case 0: | ||
3753 | mmu_audit_disable(); | ||
3754 | break; | ||
3755 | case 1: | ||
3756 | mmu_audit_enable(); | ||
3757 | break; | ||
3758 | default: | ||
3759 | return -EINVAL; | ||
3760 | } | ||
3761 | |||
3762 | return 0; | ||
3763 | } | ||
3764 | |||
3765 | static struct kernel_param_ops audit_param_ops = { | ||
3766 | .set = mmu_audit_set, | ||
3767 | .get = param_get_bool, | ||
3768 | }; | ||
3769 | |||
3770 | module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644); | ||
3716 | #endif | 3771 | #endif |
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h index 3aab0f0930ef..b60b4fdb3eda 100644 --- a/arch/x86/kvm/mmutrace.h +++ b/arch/x86/kvm/mmutrace.h | |||
@@ -195,6 +195,25 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page, | |||
195 | 195 | ||
196 | TP_ARGS(sp) | 196 | TP_ARGS(sp) |
197 | ); | 197 | ); |
198 | |||
199 | TRACE_EVENT( | ||
200 | kvm_mmu_audit, | ||
201 | TP_PROTO(struct kvm_vcpu *vcpu, int audit_point), | ||
202 | TP_ARGS(vcpu, audit_point), | ||
203 | |||
204 | TP_STRUCT__entry( | ||
205 | __field(struct kvm_vcpu *, vcpu) | ||
206 | __field(int, audit_point) | ||
207 | ), | ||
208 | |||
209 | TP_fast_assign( | ||
210 | __entry->vcpu = vcpu; | ||
211 | __entry->audit_point = audit_point; | ||
212 | ), | ||
213 | |||
214 | TP_printk("vcpu:%d %s", __entry->vcpu->cpu, | ||
215 | audit_point_name[__entry->audit_point]) | ||
216 | ); | ||
198 | #endif /* _TRACE_KVMMMU_H */ | 217 | #endif /* _TRACE_KVMMMU_H */ |
199 | 218 | ||
200 | #undef TRACE_INCLUDE_PATH | 219 | #undef TRACE_INCLUDE_PATH |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index a0f2febf5692..debe77035366 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -542,7 +542,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
542 | if (mmu_notifier_retry(vcpu, mmu_seq)) | 542 | if (mmu_notifier_retry(vcpu, mmu_seq)) |
543 | goto out_unlock; | 543 | goto out_unlock; |
544 | 544 | ||
545 | kvm_mmu_audit(vcpu, "pre page fault"); | 545 | trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT); |
546 | kvm_mmu_free_some_pages(vcpu); | 546 | kvm_mmu_free_some_pages(vcpu); |
547 | sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, | 547 | sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, |
548 | level, &write_pt, pfn); | 548 | level, &write_pt, pfn); |
@@ -554,7 +554,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
554 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ | 554 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ |
555 | 555 | ||
556 | ++vcpu->stat.pf_fixed; | 556 | ++vcpu->stat.pf_fixed; |
557 | kvm_mmu_audit(vcpu, "post page fault (fixed)"); | 557 | trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT); |
558 | spin_unlock(&vcpu->kvm->mmu_lock); | 558 | spin_unlock(&vcpu->kvm->mmu_lock); |
559 | 559 | ||
560 | return write_pt; | 560 | return write_pt; |