KVM: Add host swap event notifications for PV guest
Subsystems (11)
v3 cover KVM: Add host swap event notifications for PV guest
KVM virtualizes guest memory by means of shadow pages or HW assistance like NPT/EPT. Not all memory used by a guest is mapped into the guest address space or even present in a host memory at any given time. When vcpu tries to access memory page that is not mapped into the guest address space KVM is notified about it. KVM maps the page into the guest address space and resumes vcpu execution. If the page is swapped out from host memory vcpu execution is suspended till the page is not swapped into the memory again. This is inefficient since vcpu can do other work (run other task or serve interrupts) while page gets swapped in.
To overcome this inefficiency this patch series implements "asynchronous page fault" for paravirtualized KVM guests. If a page that vcpu is trying to access is swapped out KVM sends an async PF to the vcpu and continues vcpu execution. Requested page is swapped in by another thread in parallel. When vcpu gets async PF it puts faulted task to sleep until "wake up" interrupt is delivered. When the page is brought to the host memory KVM sends "wake up" interrupt and the guest's task resumes execution.
Changes:
v1->v2
Use MSR instead of hypercall.
Move most of the code into arch independent place.
halt inside a guest instead of doing "wait for page" hypercall if
preemption is disabled.
v2->v3
Use MSR from range 0x4b564dxx.
Add slot version tracking.
Support migration by restarting all guest processes after migration. Drop patch that tract preemptability for non-preemptable kernels
due to performance concerns. Send async PF to non-preemptable guests only when vcpu is executing userspace code.
Gleb Natapov (12):
Move kvm_smp_prepare_boot_cpu() from kvmclock.c to kvm.c. Add PV MSR to enable asynchronous page faults delivery. Add async PF initialization to PV guest.
Add "handle page fault" PV helper.
Export __get_user_pages_fast.
Add get_user_pages() variant that fails if major fault is required. Maintain memslot version number
Inject asynchronous page fault into a guest if page is swapped out. Retry fault before vmentry
Handle async PF in non preemptable context
Let host know whether the guest can handle async PF in non-userspace
context.
Send async PF when guest is not in userspace too.
arch/x86/include/asm/kvm_host.h | 25 +++- arch/x86/include/asm/kvm_para.h | 14 ++ arch/x86/include/asm/paravirt.h | 11 ++- arch/x86/include/asm/paravirt_types.h | 4 + arch/x86/kernel/kvm.c | 253 +++++++++++++++++++++++++++++++++ arch/x86/kernel/kvmclock.c | 13 +-- arch/x86/kernel/paravirt.c | 8 + arch/x86/kernel/paravirt_patch_32.c | 8 + arch/x86/kernel/paravirt_patch_64.c | 7 + arch/x86/kernel/smpboot.c | 3 + arch/x86/kvm/Kconfig | 2 + arch/x86/kvm/mmu.c | 63 ++++++++- arch/x86/kvm/paging_tmpl.h | 49 ++++++- arch/x86/kvm/x86.c | 121 +++++++++++++++- arch/x86/mm/fault.c | 3 + arch/x86/mm/gup.c | 2 + fs/ncpfs/mmap.c | 2 + include/linux/kvm.h | 1 + include/linux/kvm_host.h | 29 ++++ include/linux/kvm_para.h | 2 + include/linux/mm.h | 5 + include/trace/events/kvm.h | 60 ++++++++ mm/filemap.c | 3 + mm/memory.c | 31 ++++- mm/shmem.c | 8 +- virt/kvm/Kconfig | 3 + virt/kvm/kvm_main.c | 245 +++++++++++++++++++++++++++++++- 27 files changed, 941 insertions(+), 34 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 1/12 Move kvm_smp_prepare_boot_cpu() from kvmclock.c to kvm.c.
Async PF also needs to hook into smp_prepare_boot_cpu so move the hook into generic code.
--- arch/x86/include/asm/kvm_para.h | 1 + arch/x86/kernel/kvm.c | 11 +++++++++++ arch/x86/kernel/kvmclock.c | 13 +------------ 3 files changed, 13 insertions(+), 12 deletions(-)
arch/x86/include/asm/kvm_para.h +1 -0
@@ -51,6 +51,7 @@ struct kvm_mmu_op_release_pt {#include <asm/processor.h> extern void kvmclock_init (void ); +extern int kvm_register_clock (char *txt);/* This instruction is vmcall. On non-VT architectures, it will generate a
arch/x86/kernel/kvm.c +11 -0
@@ -231,10 +231,21 @@ static void __init paravirt_ops_setup(void)#endif } +#ifdef CONFIG_SMP +static void __init kvm_smp_prepare_boot_cpu (void ) +{ +WARN_ON (kvm_register_clock ("primary cpu clock" )); +native_smp_prepare_boot_cpu (); +} +#endif +void __init kvm_guest_init (void ) {if (!kvm_para_available ())return ;paravirt_ops_setup (); +#ifdef CONFIG_SMP + smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; +#endif }
arch/x86/kernel/kvmclock.c +1 -12
@@ -122,7 +122,7 @@ static struct clocksource kvm_clock = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static int kvm_register_clock (char *txt) +int kvm_register_clock (char *txt) {int cpu =smp_processor_id ();int low, high;
@@ -146,14 +146,6 @@ static void __cpuinit kvm_setup_secondary_clock(void) }#endif -#ifdef CONFIG_SMP -static void __init kvm_smp_prepare_boot_cpu (void ) -{ -WARN_ON (kvm_register_clock ("primary cpu clock" )); -native_smp_prepare_boot_cpu (); -} -#endif -/* * After the clock is registered, the host will keep writing to the * registered memory location. If the guest happens to shutdown, this memory
@@ -192,9 +184,6 @@ void __init kvmclock_init(void) x86_cpuinit.setup_percpu_clockev = kvm_setup_secondary_clock;#endif -#ifdef CONFIG_SMP - smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; -#endif machine_ops.shutdown = kvm_shutdown;#ifdef CONFIG_KEXEC machine_ops.crash_shutdown = kvm_crash_shutdown;
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 2/12 Add PV MSR to enable asynchronous page faults delivery.
In reply to Gleb Natapov--- arch/x86/include/asm/kvm_host.h | 3 ++ arch/x86/include/asm/kvm_para.h | 4 +++ arch/x86/kvm/x86.c | 49 +++++++++++++++++++++++++++++++++++++- include/linux/kvm.h | 1 + 4 files changed, 55 insertions(+), 2 deletions(-)
arch/x86/include/asm/kvm_host.h +3 -0
@@ -362,6 +362,9 @@ struct kvm_vcpu_arch {/* used for guest single stepping over the given code position */ u16 singlestep_cs;unsigned long singlestep_rip; + +u32 __user *apf_data; +u64 apf_msr_val; };struct kvm_mem_alias {
arch/x86/include/asm/kvm_para.h +4 -0
@@ -15,12 +15,16 @@#define KVM_FEATURE_CLOCKSOURCE 0#define KVM_FEATURE_NOP_IO_DELAY 1#define KVM_FEATURE_MMU_OP 2 +#define KVM_FEATURE_ASYNC_PF 3#define MSR_KVM_WALL_CLOCK 0x11#define MSR_KVM_SYSTEM_TIME 0x12 +#define MSR_KVM_ASYNC_PF_EN 0x4b564d00#define KVM_MAX_MMU_OP_BATCH 32 +#define KVM_ASYNC_PF_ENABLED (1 << 0) +/* Operations for KVM_HC_MMU_OP */ #define KVM_MMU_OP_WRITE_PTE 1#define KVM_MMU_OP_FLUSH_TLB 2
arch/x86/kvm/x86.c +47 -2
92 lines not on this page · raw message
include/linux/kvm.h +1 -0
@@ -497,6 +497,7 @@ struct kvm_ioeventfd {#endif #define KVM_CAP_S390_PSW 42#define KVM_CAP_PPC_SEGSTATE 43 +#define KVM_CAP_ASYNC_PF 44#ifdef KVM_CAP_IRQ_ROUTING
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 2/12 Add PV MSR to enable asynchronous page faults delivery.
What's missing in this patch set and in similar pvclock implementation is userspace activation of the features. This should be part of the machine description and not enabled by default without no control to deactivate it on a per guest basis.
Gerd, since you're the qdev master, what's the best way to control it?
Quoted 158 lines · Gleb Natapov
Signed-off-by Gleb Natapov<[email protected]>--- arch/x86/include/asm/kvm_host.h | 3 ++ arch/x86/include/asm/kvm_para.h | 4 +++ arch/x86/kvm/x86.c | 49 +++++++++++++++++++++++++++++++++++++- include/linux/kvm.h | 1 + 4 files changed, 55 insertions(+), 2 deletions(-)arch/x86/include/asm/kvm_host.h +3
-0@@ -362,6 +362,9 @@ struct kvm_vcpu_arch {/* used for guest single stepping over the given code position */ u16 singlestep_cs;unsigned long singlestep_rip; + +u32 __user *apf_data; +u64 apf_msr_val; };struct kvm_mem_alias {arch/x86/include/asm/kvm_para.h +4
-0@@ -15,12 +15,16 @@#define KVM_FEATURE_CLOCKSOURCE 0#define KVM_FEATURE_NOP_IO_DELAY 1#define KVM_FEATURE_MMU_OP 2 +#define KVM_FEATURE_ASYNC_PF 3#define MSR_KVM_WALL_CLOCK 0x11#define MSR_KVM_SYSTEM_TIME 0x12 +#define MSR_KVM_ASYNC_PF_EN 0x4b564d00#define KVM_MAX_MMU_OP_BATCH 32 +#define KVM_ASYNC_PF_ENABLED (1<< 0) +/* Operations for KVM_HC_MMU_OP */ #define KVM_MMU_OP_WRITE_PTE 1#define KVM_MMU_OP_FLUSH_TLB 2arch/x86/kvm/x86.c +47
-2@@ -620,9 +620,9 @@ static inline u32 bit(int bitno)* kvm-specific. Those are put in the beginning of the list. */ -#define KVM_SAVE_MSRS_BEGIN 2 +#define KVM_SAVE_MSRS_BEGIN 3static u32 msrs_to_save[] = { -MSR_KVM_SYSTEM_TIME ,MSR_KVM_WALL_CLOCK , +MSR_KVM_SYSTEM_TIME ,MSR_KVM_WALL_CLOCK ,MSR_KVM_ASYNC_PF_EN ,MSR_IA32_SYSENTER_CS ,MSR_IA32_SYSENTER_ESP ,MSR_IA32_SYSENTER_EIP ,MSR_K6_STAR , #ifdef CONFIG_X86_64@@ -1003,6 +1003,37 @@ out:return r; } +static int kvm_pv_enable_async_pf (struct kvm_vcpu *vcpu,u64 data) +{ +u64 gpa = data& ~0x3f ; +int offset =offset_in_page (gpa); +unsigned long addr; + +/* Bits 1:5 are resrved, Should be zero */ +if (data&0x3e ) +return 1 ; + + vcpu->arch.apf_msr_val = data; + +if (!(data&KVM_ASYNC_PF_ENABLED )) { + vcpu->arch.apf_data =NULL ; +return 0 ; + } + + addr =gfn_to_hva (vcpu->kvm, gpa>>PAGE_SHIFT ); +if (kvm_is_error_hva (addr)) +return 1 ; + + vcpu->arch.apf_data = (u32 __user *)(addr + offset); + +/* check if address is mapped */ +if (get_user (offset, vcpu->arch.apf_data)) { + vcpu->arch.apf_data =NULL ; +return 1 ; + } +return 0 ; +} +int kvm_set_msr_common (struct kvm_vcpu *vcpu,u32 msr,u64 data) {switch (msr) {@@ -1083,6 +1114,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)kvm_request_guest_time_update (vcpu);break ; } +case MSR_KVM_ASYNC_PF_EN : +if (kvm_pv_enable_async_pf (vcpu, data)) +return 1 ; +break ;case MSR_IA32_MCG_CTL :case MSR_IA32_MCG_STATUS : case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:@@ -1275,6 +1310,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)case MSR_KVM_SYSTEM_TIME : data = vcpu->arch.time;break ; +case MSR_KVM_ASYNC_PF_EN : + data = vcpu->arch.apf_msr_val; +break ;case MSR_IA32_P5_MC_ADDR :case MSR_IA32_P5_MC_TYPE :case MSR_IA32_MCG_CAP :@@ -1397,6 +1435,7 @@ int kvm_dev_ioctl_check_extension(long ext)case KVM_CAP_XEN_HVM :case KVM_CAP_ADJUST_CLOCK :case KVM_CAP_VCPU_EVENTS : +case KVM_CAP_ASYNC_PF : r =1 ;break ;case KVM_CAP_COALESCED_MMIO :@@ -5117,6 +5156,9 @@ free_vcpu:void kvm_arch_vcpu_destroy (struct kvm_vcpu *vcpu) { + vcpu->arch.apf_data =NULL ; + vcpu->arch.apf_msr_val =0 ; +vcpu_load (vcpu);kvm_mmu_unload (vcpu);vcpu_put (vcpu);@@ -5134,6 +5176,9 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.dr6 =DR6_FIXED_1 ; vcpu->arch.dr7 =DR7_FIXED_1 ; + vcpu->arch.apf_data =NULL ; + vcpu->arch.apf_msr_val =0 ; +return kvm_x86_ops->vcpu_reset (vcpu); }include/linux/kvm.h +1
-0@@ -497,6 +497,7 @@ struct kvm_ioeventfd {#endif #define KVM_CAP_S390_PSW 42#define KVM_CAP_PPC_SEGSTATE 43 +#define KVM_CAP_ASYNC_PF 44#ifdef KVM_CAP_IRQ_ROUTING
[Qemu-devel] Re: Fw: [PATCH v3 02/12] Add PV MSR to enable asynchronous page faults delivery.
Quoted 7 lines · Dor Laor
What's missing in this patch set and in similar pvclock implementation is userspace activation of the features. This should be part of the machine description and not enabled by default without no control to deactivate it on a per guest basis.
Gerd, since you're the qdev master, what's the best way to control it?
May be it should be done as other cpuid flags i.e -cpu kvm64,-kvmpvmmu,+kvmclock
--
Gleb.
[Qemu-devel] Re: Fw: [PATCH v3 02/12] Add PV MSR to enable asynchronous page faults delivery.
Quoted 7 lines · Gleb Natapov
Quoted 5 lines · Dor Laor
What's missing in this patch set and in similar pvclock implementation is userspace activation of the features. This should be part of the machine description and not enabled by default without no control to deactivate it on a per guest basis.
Quoted 5 lines
Quoted 3 lines
Gerd, since you're the qdev master, what's the best way to control it?
May be it should be done as other cpuid flags i.e -cpu kvm64,-kvmpvmmu,+kvmclock
I was about to suggest the same ;)
cheers,
Gerd
Re: [Qemu-devel] Re: Fw: [PATCH v3 02/12] Add PV MSR to enable asynchronous page faults delivery.
In reply to Gleb NatapovQuoted 7 lines · Gleb Natapov
Quoted 5 lines · Dor Laor
What's missing in this patch set and in similar pvclock implementation is userspace activation of the features. This should be part of the machine description and not enabled by default without no control to deactivate it on a per guest basis.
Quoted 5 lines
Quoted 3 lines
Gerd, since you're the qdev master, what's the best way to control it?
May be it should be done as other cpuid flags i.e -cpu kvm64,-kvmpvmmu,+kvmclock
Makes sense to me.
Regards,
Anthony Liguori
Quoted 5 lines
--
Gleb.
PATCH v3 3/12 Add async PF initialization to PV guest.
In reply to Gleb Natapov--- arch/x86/include/asm/kvm_para.h | 5 ++++ arch/x86/kernel/kvm.c | 49 +++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/smpboot.c | 3 ++ include/linux/kvm_para.h | 2 + 4 files changed, 59 insertions(+), 0 deletions(-)
arch/x86/include/asm/kvm_para.h +5 -0
@@ -51,6 +51,11 @@ struct kvm_mmu_op_release_pt {__u64 pt_phys; }; +struct kvm_vcpu_pv_apf_data { +__u32 reason; +__u32 enabled; +}; +#ifdef __KERNEL__#include <asm/processor.h>
arch/x86/kernel/kvm.c +49 -0
79 lines not on this page · raw message
arch/x86/kernel/smpboot.c +3 -0
@@ -65,6 +65,7 @@#include <asm/setup.h> #include <asm/uv/uv.h> #include <linux/mc146818rtc.h> +#include <linux/kvm_para.h> #include <asm/smpboot_hooks.h>
@@ -321,6 +322,8 @@ notrace static void __cpuinit start_secondary(void *unused)ipi_call_unlock ();per_cpu (cpu_state,smp_processor_id ()) =CPU_ONLINE ; +kvm_guest_cpu_init (); +/* enable local interrupts */ local_irq_enable ();
include/linux/kvm_para.h +2 -0
@@ -26,8 +26,10 @@#ifdef __KERNEL__#ifdef CONFIG_KVM_GUEST void __init kvm_guest_init (void ); +void __cpuinit kvm_guest_cpu_init (void );#else #define kvm_guest_init () do { } while (0) +#define kvm_guest_cpu_init () do { } while (0)#endif static inline int kvm_para_has_feature (unsigned int feature)
Signature · 1 line
1.6.5
PATCH v3 4/12 Add "handle page fault" PV helper.
In reply to Gleb NatapovAllow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to do_page_fault() function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:
With 'if': Without 'if':
Average Half load -j 8 Run (std deviation):
Elapsed Time 338.122 (0.869207) Elapsed Time 336.404 (1.69196) User Time 2025.49 (4.11097) User Time 2028.17 (1.34199) System Time 218.098 (0.826632) System Time 219.022 (0.978581) Percent CPU 663 (2.12132) Percent CPU 667.4 (3.20936) Context Switches 140903 (2655.99) Context Switches 138476 (3408.49) Sleeps 836103 (1594.93) Sleeps 836048 (2597.78)
Average Optimal load -j 16 Run (std deviation):
Elapsed Time 255.32 (1.28328) Elapsed Time 255.144 (1.09674) User Time 2342.93 (334.625) User Time 2343.7 (332.612) System Time 248.722 (32.2921) System Time 250.06 (32.7329) Percent CPU 906.9 (257.13) Percent CPU 909.6 (255.326) Context Switches 294395 (161817) Context Switches 293186 (163124) Sleeps 890162 (57019.2) Sleeps 890534 (57494.5)
Average Custom load -j 32 Run (std deviation):
Elapsed Time 236.318 (1.56739) Elapsed Time 236.018 (1.32215) User Time 2528.19 (381.49) User Time 2530.75 (382.228) System Time 264.739 (34.9425) System Time 266.082 (35.1991) Percent CPU 1055.2 (299.438) Percent CPU 1058.6 (299.153) Context Switches 445730 (256736) Context Switches 446093 (259253) Sleeps 939835 (85894.1) Sleeps 939638 (85396.9)
This is how the 'if' affects generated assembly:
With 'if': Without 'if':do_page_fault: do_page_fault:
push %rbp push %rbp mov %rsp,%rbp mov %rsp,%rbp push %r15 push %r15 push %r14 push %r14 push %r13 push %r13 push %r12 push %r12 push %rbx push %rbx sub $0x28,%rsp sub $0x18,%rsp callq ffffffff81002a80 callq ffffffff81002a80 mov %rdi,%r14 mov %gs:0xb540,%r15 mov %rsi,%r13 mov 0x270(%r15),%rax callq *0xffffffff816ab308 mov %rdi,%r14 test %eax,%eax mov %rsi,%r13 jne ffffffff813f10cb mov %gs:0xb540,%r15 mov 0x270(%r15),%rax
And this is how the code looks like at runtime after patching:
Running on kvm: Running on phys HW: do_page_fault: do_page_fault: push %rbp push %rbp mov %rsp,%rbp mov %rsp,%rbp push %r15 push %r15 push %r14 push %r14 push %r13 push %r13 push %r12 push %r12 push %rbx push %rbx sub $0x28,%rsp sub $0x28,%rsp callq 0xffffffff81002a80 callq 0xffffffff81002a80 mov %rdi,%r14 mov %rdi,%r14 mov %rsi,%r13 mov %rsi,%r13 callq 0xffffffff8102417e xor %rax,%rax xchg %ax,%ax nopl 0x0(%rax) test %eax,%eax test %eax,%eax jne 0xffffffff813f10cb jne 0xffffffff813f10cb mov %gs:0xb540,%r15 mov %gs:0xb540,%r15
--- arch/x86/include/asm/kvm_para.h | 3 + arch/x86/include/asm/paravirt.h | 11 ++- arch/x86/include/asm/paravirt_types.h | 4 + arch/x86/kernel/kvm.c | 162 +++++++++++++++++++++++++++++++++ arch/x86/kernel/paravirt.c | 8 ++ arch/x86/kernel/paravirt_patch_32.c | 8 ++ arch/x86/kernel/paravirt_patch_64.c | 7 ++ arch/x86/mm/fault.c | 3 + 8 files changed, 204 insertions(+), 2 deletions(-)
arch/x86/include/asm/kvm_para.h +3 -0
@@ -51,6 +51,9 @@ struct kvm_mmu_op_release_pt {__u64 pt_phys; }; +#define KVM_PV_REASON_PAGE_NOT_PRESENT 1 +#define KVM_PV_REASON_PAGE_READY 2 +struct kvm_vcpu_pv_apf_data {__u32 reason;__u32 enabled;
arch/x86/include/asm/paravirt.h +9 -2
@@ -6,6 +6,7 @@#ifdef CONFIG_PARAVIRT #include <asm/pgtable_types.h> #include <asm/asm.h> +#include <asm/ptrace.h> #include <asm/paravirt_types.h>
@@ -699,15 +700,21 @@ static inline void pmd_clear(pmd_t *pmdp) }#endif /* CONFIG_X86_PAE */ +static inline void arch_end_context_switch (struct task_struct *next) +{ +PVOP_VCALL1 (pv_cpu_ops.end_context_switch, next); +} +#define __HAVE_ARCH_START_CONTEXT_SWITCHstatic inline void arch_start_context_switch (struct task_struct *prev) {PVOP_VCALL1 (pv_cpu_ops.start_context_switch, prev); } -static inline void arch_end_context_switch (struct task_struct *next) +static inline int handle_page_fault (struct pt_regs *regs, +unsigned long error_code) { -PVOP_VCALL1 (pv_cpu_ops.end_context_switch, next); +return PVOP_CALL2 (int, pv_cpu_ops.handle_pf, regs, error_code); }#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
arch/x86/include/asm/paravirt_types.h +4 -0
@@ -186,6 +186,7 @@ struct pv_cpu_ops {void (*start_context_switch)(struct task_struct *prev);void (*end_context_switch)(struct task_struct *next); +int (*handle_pf)(struct pt_regs *regs,unsigned long error_code); };struct pv_irq_ops {
@@ -385,6 +386,7 @@ extern struct pv_lock_ops pv_lock_ops;unsigned paravirt_patch_nop (void );unsigned paravirt_patch_ident_32 (void *insnbuf,unsigned len);unsigned paravirt_patch_ident_64 (void *insnbuf,unsigned len); +unsigned paravirt_patch_ret_0 (void *insnbuf,unsigned len);unsigned paravirt_patch_ignore (unsigned len); unsigned paravirt_patch_call(void *insnbuf, const void *target, u16 tgt_clobbers,
@@ -676,8 +678,10 @@ void paravirt_leave_lazy_mmu(void);void _paravirt_nop (void );u32 _paravirt_ident_32 (u32 );u64 _paravirt_ident_64 (u64 ); +unsigned long _paravirt_ret_0 (void );#define paravirt_nop ((void *)_paravirt_nop) +#define paravirt_ret_0 ((void *)_paravirt_ret_0)/* These all sit in the .parainstructions section to tell us what to patch. */ struct paravirt_patch_site {
arch/x86/kernel/kvm.c +162 -0
191 lines not on this page · raw message
arch/x86/kernel/paravirt.c +8 -0
@@ -54,6 +54,11 @@ u64 _paravirt_ident_64(u64 x)return x; } +unsigned long _paravirt_ret_0 (void ) +{ +return 0 ; +} +void __init default_banner (void ) { printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
@@ -154,6 +159,8 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, ret =paravirt_patch_ident_32 (insnbuf, len); else if (opfunc == _paravirt_ident_64) ret =paravirt_patch_ident_64 (insnbuf, len); + else if (opfunc == _paravirt_ret_0) + ret =paravirt_patch_ret_0 (insnbuf, len); else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) || type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
@@ -380,6 +387,7 @@ struct pv_cpu_ops pv_cpu_ops = { .start_context_switch = paravirt_nop, .end_context_switch = paravirt_nop, + .handle_pf = paravirt_ret_0, };struct pv_apic_ops pv_apic_ops = {
arch/x86/kernel/paravirt_patch_32.c +8 -0
@@ -12,6 +12,8 @@ DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");DEF_NATIVE (pv_cpu_ops, clts,"clts" );DEF_NATIVE (pv_cpu_ops, read_tsc,"rdtsc" ); +DEF_NATIVE(, mov0, "xor %eax, %eax"); +unsigned paravirt_patch_ident_32 (void *insnbuf,unsigned len) {/* arg in %eax, return in %eax */
@@ -24,6 +26,12 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)return 0 ; } +unsigned paravirt_patch_ret_0 (void *insnbuf,unsigned len) +{ +return paravirt_patch_insns (insnbuf, len, + start__mov0, end__mov0); +} +unsigned native_patch (u8 type,u16 clobbers,void *ibuf,unsigned long addr,unsigned len) {
arch/x86/kernel/paravirt_patch_64.c +7 -0
@@ -21,6 +21,7 @@ DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs"); DEF_NATIVE(, mov32, "mov %edi, %eax"); DEF_NATIVE(, mov64, "mov %rdi, %rax"); +DEF_NATIVE(, mov0, "xor %rax, %rax");unsigned paravirt_patch_ident_32 (void *insnbuf,unsigned len) {
@@ -34,6 +35,12 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len) start__mov64, end__mov64); } +unsigned paravirt_patch_ret_0 (void *insnbuf,unsigned len) +{ +return paravirt_patch_insns (insnbuf, len, + start__mov0, end__mov0); +} +unsigned native_patch (u8 type,u16 clobbers,void *ibuf,unsigned long addr,unsigned len) {
arch/x86/mm/fault.c +3 -0
@@ -953,6 +953,9 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)int write;int fault; +if (handle_page_fault (regs, error_code)) +return ; + tsk = current; mm = tsk->mm;
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 5 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:
So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 9 lines · Peter Zijlstra
Quoted 5 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 4 lines · Gleb Natapov
Quoted 3 lines · Peter Zijlstra
Quoted 2 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
Whatever are we doing to end up in do_page_fault() as it stands? Surely we can tell the CPU to go elsewhere to handle faults?
Isn't that as simple as calling set_intr_gate(14, my_page_fault) somewhere on the cpuinit instead of the regular page_fault handler?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 11 lines · Peter Zijlstra
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Peter Zijlstra
Quoted 5 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
Quoted 9 lines
Quoted 2 lines
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
Whatever are we doing to end up in
do_page_fault()as it stands? Surely we can tell the CPU to go elsewhere to handle faults?Isn't that as simple as calling
set_intr_gate(14, my_page_fault)somewhere on the cpuinit instead of the regularpage_faulthandler?
Hmm, good idea. I'll look into that. Thanks.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
In reply to Peter ZijlstraQuoted 6 lines · Peter Zijlstra
Whatever are we doing to end up in
do_page_fault()as it stands? Surely we can tell the CPU to go elsewhere to handle faults?Isn't that as simple as calling
set_intr_gate(14, my_page_fault)somewhere on the cpuinit instead of the regularpage_faulthandler?
That typically requires ugly ifdefs in entry*S and could be described as code obfuscation ("come from")
As long as he avoids a global reference (patch) the if should be practially free anyways.
-Andi
Signature · 7 lines
[email protected] -- Speaking for myself only. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
In reply to Gleb NatapovQuoted 4 lines · Gleb Natapov
Quoted 3 lines · Peter Zijlstra
Quoted 2 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
That's what it's there for... see Peter Z.'s response.
-hpa
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 9 lines · H. Peter Anvin
Quoted 8 lines · Gleb Natapov
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
That's what it's there for... see Peter Z.'s response.
Do you mean I can use one of exception vectors reserved by Intel (20-31)? What Peter Z says is that I can register my own handler for #PF and avoid the 'if' in non PV case as far as I understand him.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 16 lines · Gleb Natapov
Quoted 15 lines · H. Peter Anvin
Quoted 13 lines · Gleb Natapov
Quoted 9 lines · Peter Zijlstra
Quoted 5 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
Quoted 6 lines
Quoted 2 lines
That's what it's there for... see Peter Z.'s response.
Do you mean I can use one of exception vectors reserved by Intel (20-31)? What Peter Z says is that I can register my own handler for #PF and avoid the 'if' in non PV case as far as I understand him.
What I mean is that vector 14 is page faults -- that's what it is all about. Why on Earth do you need another vector?
-hpa
Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 19 lines · H. Peter Anvin
Quoted 18 lines · Gleb Natapov
Quoted 17 lines · H. Peter Anvin
Quoted 4 lines · Gleb Natapov
Quoted 3 lines · Peter Zijlstra
Quoted 2 lines · Gleb Natapov
Allow paravirtualized guest to do special handling for some page faults.
Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
The patch adds one 'if' to
do_page_fault()function. The call is patched out when running on physical HW. I ran kernbech on the kernel with and without that additional 'if' and result were rawly the same:So why not program a different handler address for the #PF/#GP faults and avoid the if all together?
I would gladly use fault vector reserved by x86 architecture, but I am not sure Intel will be happy about it.
That's what it's there for... see Peter Z.'s response.
Quoted 8 lines
Quoted 4 lines
Do you mean I can use one of exception vectors reserved by Intel (20-31)? What Peter Z says is that I can register my own handler for #PF and avoid the 'if' in non PV case as far as I understand him.
What I mean is that vector 14 is page faults -- that's what it is all about. Why on Earth do you need another vector?
Because this is not usual pagefault that tell the OS that page is not mapped. This is a notification to a guest OS that the page it is trying to access is swapped out by the host OS. There is nothing guest can do about it except schedule another task. So the guest should handle both type of exceptions: usual #PF when page is not mapped by the guest and new type of notifications. Ideally we would use one of unused exception vectors for new type of notifications.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 4 lines · Gleb Natapov
Quoted 4 lines
What I mean is that vector 14 is page faults -- that's what it is all about. Why on Earth do you need another vector?
Quoted 8 lines
Because this is not usual pagefault that tell the OS that page is not mapped. This is a notification to a guest OS that the page it is trying to access is swapped out by the host OS. There is nothing guest can do about it except schedule another task. So the guest should handle both type of exceptions: usual #PF when page is not mapped by the guest and new type of notifications. Ideally we would use one of unused exception vectors for new type of notifications.
Ah, this kind of stuff. We have talked about this in the past, and the right way to do that is to have the guest OS pick a vector our of the standard 0x20-0xff range, and then notify the hypervisor via a hypercall which vector to use.
In Linux this means marking it as a system vector. Note that there are real hardware system vectors which will be mutually exclusive with this, e.g. the UV one.
-hpa
Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 14 lines · H. Peter Anvin
Quoted 4 lines · Gleb Natapov
Quoted 4 lines
What I mean is that vector 14 is page faults -- that's what it is all about. Why on Earth do you need another vector?
Quoted 8 lines
Because this is not usual pagefault that tell the OS that page is not mapped. This is a notification to a guest OS that the page it is trying to access is swapped out by the host OS. There is nothing guest can do about it except schedule another task. So the guest should handle both type of exceptions: usual #PF when page is not mapped by the guest and new type of notifications. Ideally we would use one of unused exception vectors for new type of notifications.
Quoted 8 lines
Ah, this kind of stuff. We have talked about this in the past, and the right way to do that is to have the guest OS pick a vector our of the standard 0x20-0xff range, and then notify the hypervisor via a hypercall which vector to use.
In Linux this means marking it as a system vector. Note that there are real hardware system vectors which will be mutually exclusive with this, e.g. the UV one.
Yes it can be done this way and I'll look into it once more. Using exception vector is more convenient for three reasons: it allows to pass additional data in error code, it doesn't require guest to issue EOI, exception can be injected when interrupts are disabled by a guest. The last one is not important for now since host doesn't inject notifications when interrupts are disabled currently. Having Intel allocate one exception vector for hypervisor use would be really nice though.
--
Gleb.
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 9 lines · Gleb Natapov
Yes it can be done this way and I'll look into it once more. Using exception vector is more convenient for three reasons: it allows to pass additional data in error code, it doesn't require guest to issue EOI, exception can be injected when interrupts are disabled by a guest. The last one is not important for now since host doesn't inject notifications when interrupts are disabled currently. Having Intel allocate one exception vector for hypervisor use would be really nice though.
That's probably not going to happen, for the rather obvious reason: *you already have 224 of them*.
You seem to be thinking here that vectors 0-31 have to be exceptions and 32-255 have to be interrupts. *There is no such distinction*; the only thing special about 0-31 is that we (Intel) reserve the right to control the assignments; for 32-255 the platform and OS control the assignment.
You can have the guest OS take an exception on a vector above 31 just fine; you just need it to tell the hypervisor which vector it, the OS, assigned for this purpose.
-hpa
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 11 lines · H. Peter Anvin
Quoted 9 lines · Gleb Natapov
Yes it can be done this way and I'll look into it once more. Using exception vector is more convenient for three reasons: it allows to pass additional data in error code, it doesn't require guest to issue EOI, exception can be injected when interrupts are disabled by a guest. The last one is not important for now since host doesn't inject notifications when interrupts are disabled currently. Having Intel allocate one exception vector for hypervisor use would be really nice though.
Quoted 8 lines
That's probably not going to happen, for the rather obvious reason: *you already have 224 of them*.
You seem to be thinking here that vectors 0-31 have to be exceptions and 32-255 have to be interrupts. *There is no such distinction*; the only thing special about 0-31 is that we (Intel) reserve the right to control the assignments; for 32-255 the platform and OS control the assignment.
I would be glad to interpret the spec like you do, but table 6-1 SDM 3A mark vectors 2,32-255 as interrupts while others are traps, fault and aborts. Unfortunately VMX designers seems to be interpreting the spec like I do. See below.
Quoted 4 lines
You can have the guest OS take an exception on a vector above 31 just fine; you just need it to tell the hypervisor which vector it, the OS, assigned for this purpose.
VMX doesn't allow to inject hardware exception with vector greater then 31. SDM 3B section 23.2.1.3.
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through __do_IRQ() which assumes that interrupts should be ACKed.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 7 lines · Gleb Natapov
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through
__do_IRQ()which assumes that interrupts should be ACKed.
Further, we start to interact with the TPR; Linux doesn't use the TPR or cr8 but if it does one day we don't want it interfering with apf.
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 11 lines · Avi Kivity
Quoted 7 lines · Gleb Natapov
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural
and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through__do_IRQ()which assumes that interrupts should be ACKed.Further, we start to interact with the TPR; Linux doesn't use the TPR or cr8 but if it does one day we don't want it interfering with apf.
That's not an issue is it? The guest will tell the host what vector to use for pseudo page faults.
Signature · 7 lines
All rights reversed. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 10 lines · Rik van Riel
Quoted 9 lines · Avi Kivity
Quoted 7 lines · Gleb Natapov
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural
and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through__do_IRQ()which assumes that interrupts should be ACKed.
Quoted 5 lines
Quoted 2 lines
Further, we start to interact with the TPR; Linux doesn't use the TPR or cr8 but if it does one day we don't want it interfering with apf.
That's not an issue is it? The guest will tell the host what vector to use for pseudo page faults.
And kill 15 other vectors?
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
In reply to Avi KivityQuoted 10 lines · Avi Kivity
Quoted 8 lines · Gleb Natapov
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural
and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through__do_IRQ()which assumes that interrupts should be ACKed.
Quoted 3 lines
Further, we start to interact with the TPR; Linux doesn't use the TPR or cr8 but if it does one day we don't want it interfering with apf.
I don't think the TPR would be involved unless you involve the APIC (which you absolutely don't want to do.) What I'm trying to figure out is if you could inject this vector as "external interrupt" and still have it deliver if IF=0, or if it would cause any other funnies.
As that point, you do not want to go through the do_IRQ path but rather through your own exception vector entry point (it would be an entry point which doesn't get an error code, like #UD.)
-hpa
Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 12 lines · H. Peter Anvin
Quoted 10 lines · Avi Kivity
Quoted 8 lines · Gleb Natapov
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural
and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through__do_IRQ()which assumes that interrupts should be ACKed.
Quoted 9 lines
Quoted 4 lines
Further, we start to interact with the TPR; Linux doesn't use the TPR or cr8 but if it does one day we don't want it interfering with apf.
I don't think the TPR would be involved unless you involve the APIC (which you absolutely don't want to do.) What I'm trying to figure out is if you could inject this vector as "external interrupt" and still have it deliver if IF=0, or if it would cause any other funnies.
No, and it poses problems further down the line if the hardware virtualizes more and more of the APIC as seems likely to happen.
External interrupts are asynchronous events, so they're likely not to be guaranteed to be delivered on an instruction boundary like exceptions. Things like interrupt shadow will affect them as well.
Quoted 4 lines
As that point, you do not want to go through the
do_IRQpath but rather through your own exception vector entry point (it would be an entry point which doesn't get an error code, like #UD.)
An error code would actually be useful.
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
In reply to Gleb NatapovQuoted 8 lines · Gleb Natapov
Quoted 5 lines
You can have the guest OS take an exception on a vector above 31 just fine; you just need it to tell the hypervisor which vector it, the OS, assigned for this purpose.
VMX doesn't allow to inject hardware exception with vector greater then 31. SDM 3B section 23.2.1.3.
OK, you're right. I had missed that... I presume it was done for implementation reasons.
Quoted 5 lines
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through
__do_IRQ()which assumes that interrupts should be ACKed.
You can also just emulate the state transition -- since you know you're dealing with a flat protected-mode or long-mode OS (and just make that a condition of enabling the feature) you don't have to deal with all the strange combinations of directions that an unrestricted x86 event can take. Since it's an exception, it is unconditional.
-hpa
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 11 lines · H. Peter Anvin
Quoted 8 lines · Gleb Natapov
Quoted 5 lines
You can have the guest OS take an exception on a vector above 31 just fine; you just need it to tell the hypervisor which vector it, the OS, assigned for this purpose.
VMX doesn't allow to inject hardware exception with vector greater then 31. SDM 3B section 23.2.1.3.
OK, you're right. I had missed that... I presume it was done for implementation reasons.
My expectation is that is was done for forward compatibility reasons.
Quoted 8 lines
Quoted 6 lines
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through
__do_IRQ()which assumes that interrupts should be ACKed.You can also just emulate the state transition -- since you know you're dealing with a flat protected-mode or long-mode OS (and just make that a condition of enabling the feature) you don't have to deal with all the strange combinations of directions that an unrestricted x86 event can take. Since it's an exception, it is unconditional.
Do you mean create the stack frame manually? I'd really like to avoid that for many reasons, one of which is performance (need to do all the virt-to-phys walks manually), the other is that we're certain to end up with something horribly underspecified. I'd really like to keep as close as possible to the hardware. For the alternative approach, see Xen.
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 33 lines · Avi Kivity
Quoted 6 lines · H. Peter Anvin
Quoted 5 lines · Gleb Natapov
Quoted 5 lines
You can have the guest OS take an exception on a vector above 31 just fine; you just need it to tell the hypervisor which vector it, the OS, assigned for this purpose.
Quoted 7 lines
Quoted 4 lines
VMX doesn't allow to inject hardware exception with vector greater then 31.
SDM 3B section 23.2.1.3.OK, you're right. I had missed that... I presume it was done for implementation reasons.
My expectation is that is was done for forward compatibility reasons.
Quoted 9 lines
Quoted 8 lines
I can inject the event as HW interrupt on vector greater then 32 but not go through APIC so EOI will not be required. This sounds non-architectural
and I am not sure kernel has entry point code for this kind of event, it has one for exception and one for interrupts that goes through__do_IRQ()
which assumes that interrupts should be ACKed.Quoted 6 lines
You can also just emulate the state transition -- since you know you're dealing with a flat protected-mode or long-mode OS (and just make that a condition of enabling the feature) you don't have to deal with all the strange combinations of directions that an unrestricted x86 event can take. Since it's an exception, it is unconditional.
Quoted 7 lines
Do you mean create the stack frame manually? I'd really like to avoid that for many reasons, one of which is performance (need to do all the virt-to-phys walks manually), the other is that we're certain to end up with something horribly underspecified. I'd really like to keep as close as possible to the hardware. For the alternative approach, see Xen.
That and our event injection path can't play with guest memory right now since it is done from atomic context.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 9 lines · Gleb Natapov
Quoted 9 lines
Do you mean create the stack frame manually? I'd really like to avoid that for many reasons, one of which is performance (need to do all the virt-to-phys walks manually), the other is that we're certain to end up with something horribly underspecified. I'd really like to keep as close as possible to the hardware. For the alternative approach, see Xen.
Quoted 3 lines
That and our event injection path can't play with guest memory right now since it is done from atomic context.
That's true (I'd like to fix that though, for the real mode stuff).
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
H. Peter Anvin
reviewerRe: [PATCH v3 04/12] Add "handle page fault" PV helper.
In reply to Avi KivityQuoted 7 lines · Avi Kivity
Quoted 6 lines
You can also just emulate the state transition -- since you know you're dealing with a flat protected-mode or long-mode OS (and just make that a condition of enabling the feature) you don't have to deal with all the strange combinations of directions that an unrestricted x86 event can take. Since it's an exception, it is unconditional.
Quoted 6 lines
Do you mean create the stack frame manually? I'd really like to avoid that for many reasons, one of which is performance (need to do all the virt-to-phys walks manually), the other is that we're certain to end up with something horribly underspecified. I'd really like to keep as close as possible to the hardware. For the alternative approach, see Xen.
I obviously didn't mean to do something which didn't look like a hardware-delivered exception. That by itself provides a tight spec. The performance issue is real, of course.
Obviously, the design of VT-x was before my time at Intel, so I'm not familiar with why the tradeoffs that were done they way they were.
-hpa
Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 04/12] Add "handle page fault" PV helper.
Quoted 15 lines · H. Peter Anvin
Quoted 7 lines · Avi Kivity
Quoted 6 lines
You can also just emulate the state transition -- since you know you're dealing with a flat protected-mode or long-mode OS (and just make that a condition of enabling the feature) you don't have to deal with all the strange combinations of directions that an unrestricted x86 event can take. Since it's an exception, it is unconditional.
Quoted 6 lines
Do you mean create the stack frame manually? I'd really like to avoid that for many reasons, one of which is performance (need to do all the virt-to-phys walks manually), the other is that we're certain to end up with something horribly underspecified. I'd really like to keep as close as possible to the hardware. For the alternative approach, see Xen.
Quoted 7 lines
I obviously didn't mean to do something which didn't look like a hardware-delivered exception. That by itself provides a tight spec. The performance issue is real, of course.
Obviously, the design of VT-x was before my time at Intel, so I'm not familiar with why the tradeoffs that were done they way they were.
Is it so out of question to reserver exception below 32 for PV use?
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 5/12 Export __get_user_pages_fast.
In reply to Gleb NatapovKVM will use it to try and find a page without falling back to slow gup. That is why get_user_pages_fast() is not enough.
--- arch/x86/mm/gup.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/mm/gup.c +2 -0
@@ -8,6 +8,7 @@#include <linux/mm.h> #include <linux/vmstat.h> #include <linux/highmem.h> +#include <linux/module.h> #include <asm/pgtable.h>
@@ -274,6 +275,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,return nr; } +EXPORT_SYMBOL_GPL (__get_user_pages_fast);/** * get_user_pages_fast() - pin user pages in memory
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 05/12] Export __get_user_pages_fast.
Quoted 2 lines · Gleb Natapov
KVM will use it to try and find a page without falling back to slow gup. That is why
get_user_pages_fast()is not enough.
Btw, it seems like currently is declared unconditionally in linux/mm.h but only implemented by x86, and you code using it needs ifdefs for that. I think you should just introduce a stub that always returns an error here.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 6/12 Add get_user_pages() variant that fails if major fault is required.
In reply to Gleb NatapovThis patch add get_user_pages() variant that only succeeds if getting a reference to a page doesn't require major fault.
--- fs/ncpfs/mmap.c | 2 ++ include/linux/mm.h | 5 +++++ mm/filemap.c | 3 +++ mm/memory.c | 31 ++++++++++++++++++++++++++++--- mm/shmem.c | 8 +++++++- 5 files changed, 45 insertions(+), 4 deletions(-)
fs/ncpfs/mmap.c +2 -0
@@ -39,6 +39,8 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area,int bufsize;int pos;/* XXX: loff_t ? */ +if (vmf->flags &FAULT_FLAG_MINOR ) +return VM_FAULT_MAJOR |VM_FAULT_ERROR ;/* * ncpfs has nothing against high pages as long * as recvmsg and memset works on it
include/linux/mm.h +5 -0
@@ -136,6 +136,7 @@ extern pgprot_t protection_map[16];#define FAULT_FLAG_WRITE 0x01/* Fault was a write access */ #define FAULT_FLAG_NONLINEAR 0x02/* Fault was via a nonlinear mapping */ #define FAULT_FLAG_MKWRITE 0x04/* Fault was mkwrite of existing pte */ +#define FAULT_FLAG_MINOR 0x08/* Do only minor fault */ /* * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -836,6 +837,9 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *int get_user_pages (struct task_struct *tsk,struct mm_struct *mm,unsigned long start,int nr_pages,int write,int force,struct page **pages,struct vm_area_struct **vmas); +int get_user_pages_noio (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,int nr_pages,int write,int force, +struct page **pages,struct vm_area_struct **vmas);int get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages);struct page *get_dump_page (unsigned long addr);
@@ -1257,6 +1261,7 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address,#define FOLL_GET 0x04/* do get_page on page */ #define FOLL_DUMP 0x08/* give error on hole if it would be zero */ #define FOLL_FORCE 0x10/* get_user_pages read/write w/o permission */ +#define FOLL_MINOR 0x20/* do only minor page faults */ typedef int (*pte_fn_t )(pte_t *pte,pgtable_t token,unsigned long addr,void *data);
mm/filemap.c +3 -0
@@ -1509,6 +1509,9 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto no_cached_page; } }else { +if (vmf->flags &FAULT_FLAG_MINOR ) +return VM_FAULT_MAJOR |VM_FAULT_ERROR ; +/* No page in the page cache at all */ do_sync_mmap_readahead (vma, ra, file, offset);count_vm_event (PGMAJFAULT );
mm/memory.c +28 -3
@@ -1336,10 +1336,13 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,cond_resched ();while (!(page =follow_page (vma, start, foll_flags))) {int ret; +unsigned int fault_fl = + ((foll_flags &FOLL_WRITE ) ? +FAULT_FLAG_WRITE :0 ) | + ((foll_flags &FOLL_MINOR ) ? +FAULT_FLAG_MINOR :0 ); - ret =handle_mm_fault (mm, vma, start, - (foll_flags &FOLL_WRITE ) ? -FAULT_FLAG_WRITE :0 ); + ret =handle_mm_fault (mm, vma, start, fault_fl);if (ret &VM_FAULT_ERROR ) {if (ret &VM_FAULT_OOM )
@@ -1347,6 +1350,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,if (ret & (VM_FAULT_HWPOISON |VM_FAULT_SIGBUS ))return i ? i : -EFAULT ; +else if (ret &VM_FAULT_MAJOR ) +return i ? i : -EFAULT ;BUG (); }if (ret &VM_FAULT_MAJOR )
@@ -1457,6 +1462,23 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, }EXPORT_SYMBOL (get_user_pages); +int get_user_pages_noio (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,int nr_pages,int write,int force, +struct page **pages,struct vm_area_struct **vmas) +{ +int flags =FOLL_TOUCH |FOLL_MINOR ; + +if (pages) + flags |=FOLL_GET ; +if (write) + flags |=FOLL_WRITE ; +if (force) + flags |=FOLL_FORCE ; + +return __get_user_pages (tsk, mm, start, nr_pages, flags, pages, vmas); +} +EXPORT_SYMBOL (get_user_pages_noio); +/** * get_dump_page() - pin user page in memory while writing it to core dump * @addr: user address
@@ -2536,6 +2558,9 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,delayacct_set_flag (DELAYACCT_PF_SWAPIN ); page =lookup_swap_cache (entry);if (!page) { +if (flags &FAULT_FLAG_MINOR ) +return VM_FAULT_MAJOR |VM_FAULT_ERROR ; +grab_swap_token (mm);/* Contend for token _before_ read-in */ page =swapin_readahead (entry,GFP_HIGHUSER_MOVABLE , vma, address);
mm/shmem.c +7 -1
@@ -1225,6 +1225,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,swp_entry_t swap;gfp_t gfp;int error; +int flags = type ? *type :0 ;if (idx >=SHMEM_MAX_INDEX )return -EFBIG ;
@@ -1273,6 +1274,11 @@ repeat: swappage =lookup_swap_cache (swap);if (!swappage) {shmem_swp_unmap (entry); +if (flags &FAULT_FLAG_MINOR ) { +spin_unlock (&info->lock); + *type =VM_FAULT_MAJOR |VM_FAULT_ERROR ; + goto failed; + }/* here we actually do the io */ if (type && !(*type &VM_FAULT_MAJOR )) {__count_vm_event (PGMAJFAULT );
@@ -1481,7 +1487,7 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) {struct inode *inode = vma->vm_file->f_path.dentry->d_inode;int error; -int ret; +int ret = (int )vmf->flags;if (((loff_t )vmf->pgoff <<PAGE_CACHE_SHIFT ) >=i_size_read (inode))return VM_FAULT_SIGBUS ;
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3 06/12] Add get_user_pages() variant that fails if major fault is required.
Quoted 8 lines · Gleb Natapov
This patch add
get_user_pages()variant that only succeeds if getting a reference to a page doesn't require major fault.mm/memory.c +4
-0+int get_user_pages_noio (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,int nr_pages,int write,int force, +struct page **pages,struct vm_area_struct **vmas) +{
mm/memory.c int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, · line 1478
Quoted 10 lines
mm/memory.c +10
-0+int flags =FOLL_TOUCH |FOLL_MINOR ; + +if (pages) + flags |=FOLL_GET ; +if (write) + flags |=FOLL_WRITE ; +if (force) + flags |=FOLL_FORCE ; + +return __get_user_pages (tsk, mm, start, nr_pages, flags, pages, vmas);
Wouldn't it be better to just export __get_user_pages as a proper user interface, maybe replacing get_user_pages by it entirely?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 7/12 Maintain memslot version number
In reply to Gleb NatapovCode that depends on particular memslot layout can track changes and adjust to new layout.
--- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
include/linux/kvm_host.h +1 -0
@@ -163,6 +163,7 @@ struct kvm {spinlock_t requests_lock;struct mutex slots_lock;struct mm_struct *mm;/* userspace tied to this vm */ +u32 memslot_version;struct kvm_memslots *memslots;struct srcu_struct srcu;#ifdef CONFIG_KVM_APIC_ARCHITECTURE
virt/kvm/kvm_main.c +1 -0
@@ -737,6 +737,7 @@ skip_lpage: slots->memslots[mem->slot] = new; old_memslots = kvm->memslots;rcu_assign_pointer (kvm->memslots, slots); + kvm->memslot_version++;synchronize_srcu_expedited (&kvm->srcu);kvm_arch_commit_memory_region (kvm, mem, old, user_alloc);
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 8/12 Inject asynchronous page fault into a guest if page is swapped out.
In reply to Gleb NatapovIf guest access swapped out memory do not swap it in from vcpu thread context. Setup slow work to do swapping and send async page fault to a guest.
Allow async page fault injection only when guest is in user mode since otherwise guest may be in non-sleepable context and will not be able to reschedule.
--- arch/x86/include/asm/kvm_host.h | 14 +++ arch/x86/kvm/Kconfig | 2 + arch/x86/kvm/mmu.c | 36 ++++++- arch/x86/kvm/paging_tmpl.h | 16 +++- arch/x86/kvm/x86.c | 62 +++++++++- include/linux/kvm_host.h | 28 +++++ include/trace/events/kvm.h | 60 ++++++++++ virt/kvm/Kconfig | 3 + virt/kvm/kvm_main.c | 242 ++++++++++++++++++++++++++++++++++++++- 9 files changed, 456 insertions(+), 7 deletions(-)
arch/x86/include/asm/kvm_host.h +14 -0
@@ -364,7 +364,9 @@ struct kvm_vcpu_arch {unsigned long singlestep_rip;u32 __user *apf_data; +u32 apf_memslot_ver;u64 apf_msr_val; +u32 async_pf_id; };struct kvm_mem_alias {
@@ -537,6 +539,10 @@ struct kvm_x86_ops {const struct trace_print_flags *exit_reasons_str; }; +struct kvm_arch_async_pf { +u32 token; +}; +extern struct kvm_x86_ops *kvm_x86_ops;int kvm_mmu_module_init (void );
@@ -815,4 +821,12 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v);void kvm_define_shared_msr (unsigned index,u32 msr);void kvm_set_shared_msr (unsigned index,u64 val,u64 mask); +struct kvm_async_pf ; + +void kvm_arch_inject_async_page_not_present (struct kvm_vcpu *vcpu, +struct kvm_async_pf *work); +void kvm_arch_inject_async_page_present (struct kvm_vcpu *vcpu, +struct kvm_async_pf *work); +bool kvm_arch_can_inject_async_page_present (struct kvm_vcpu *vcpu);#endif /* _ASM_X86_KVM_HOST_H */ +
arch/x86/kvm/Kconfig +2 -0
@@ -28,6 +28,8 @@ config KVM select HAVE_KVM_IRQCHIP select HAVE_KVM_EVENTFD select KVM_APIC_ARCHITECTURE + select KVM_ASYNC_PF + select SLOW_WORK select USER_RETURN_NOTIFIER select KVM_MMIO ---help---
arch/x86/kvm/mmu.c +35 -1
@@ -19,6 +19,7 @@#include "mmu.h" #include "kvm_cache_regs.h" +#include "x86.h" #include <linux/kvm_host.h> #include <linux/types.h>
@@ -30,6 +31,8 @@#include <linux/hugetlb.h> #include <linux/compiler.h> #include <linux/srcu.h> +#include <trace/events/kvm.h> +#undef TRACE_INCLUDE_FILE#include <asm/page.h> #include <asm/cmpxchg.h>
@@ -2186,6 +2189,21 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, error_code & PFERR_WRITE_MASK, gfn); } +int kvm_arch_setup_async_pf (struct kvm_vcpu *vcpu,gva_t gva,gfn_t gfn) +{ +struct kvm_arch_async_pf arch; + arch.token = (vcpu->arch.async_pf_id++ <<12 ) | vcpu->vcpu_id; +return kvm_setup_async_pf (vcpu, gva, gfn, &arch); +} + +static bool can_do_async_pf (struct kvm_vcpu *vcpu) +{ +if (!vcpu->arch.apf_data ||kvm_event_needs_reinjection (vcpu)) +return false; + +return !!kvm_x86_ops->get_cpl (vcpu); +} +static int tdp_page_fault (struct kvm_vcpu *vcpu,gva_t gpa,u32 error_code) {
@@ -2208,7 +2226,23 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, mmu_seq = vcpu->kvm->mmu_notifier_seq;smp_rmb (); - pfn =gfn_to_pfn (vcpu->kvm, gfn); + +if (can_do_async_pf (vcpu)) { + r =gfn_to_pfn_async (vcpu->kvm, gfn, &pfn); +trace_kvm_try_async_get_page (r, pfn); + }else { +do_sync: + r =1 ; + pfn =gfn_to_pfn (vcpu->kvm, gfn); + } + +if (!r) { +if (!kvm_arch_setup_async_pf (vcpu, gpa, gfn)) + goto do_sync; +return 0 ; + } + +/* mmio */ if (is_error_pfn (pfn)) {kvm_release_pfn_clean (pfn);return 1 ;
arch/x86/kvm/paging_tmpl.h +15 -1
@@ -419,7 +419,21 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, mmu_seq = vcpu->kvm->mmu_notifier_seq;smp_rmb (); - pfn =gfn_to_pfn (vcpu->kvm, walker.gfn); + +if (can_do_async_pf (vcpu)) { + r =gfn_to_pfn_async (vcpu->kvm, walker.gfn, &pfn); +trace_kvm_try_async_get_page (r, pfn); + }else { +do_sync: + r =1 ; + pfn =gfn_to_pfn (vcpu->kvm, walker.gfn); + } + +if (!r) { +if (!kvm_arch_setup_async_pf (vcpu, addr, walker.gfn)) + goto do_sync; +return 0 ; + }/* mmio */ if (is_error_pfn (pfn)) {
arch/x86/kvm/x86.c +58 -4
94 lines not on this page · raw message
include/linux/kvm_host.h +28 -0
@@ -16,6 +16,7 @@#include <linux/mm.h> #include <linux/preempt.h> #include <linux/msi.h> +#include <linux/slow-work.h> #include <asm/signal.h> #include <linux/kvm.h>
@@ -72,6 +73,26 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,int kvm_io_bus_unregister_dev (struct kvm *kvm,enum kvm_bus bus_idx,struct kvm_io_device *dev); +#ifdef CONFIG_KVM_ASYNC_PF +struct kvm_async_pf { +struct slow_work work; +struct list_head link; +struct kvm_vcpu *vcpu; +struct mm_struct *mm; +gva_t gva; +unsigned long addr; +struct kvm_arch_async_pf arch; +struct page *page; +atomic_t used; +}; + +void kvm_clear_async_pf_completion_queue (struct kvm_vcpu *vcpu); +void kvm_check_async_pf_completion (struct kvm_vcpu *vcpu); +int kvm_setup_async_pf (struct kvm_vcpu *vcpu,gva_t gva,gfn_t gfn, +struct kvm_arch_async_pf *arch); +int kvm_async_pf_wakeup_all (struct kvm_vcpu *vcpu); +#endif +struct kvm_vcpu {struct kvm *kvm;#ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -101,6 +122,12 @@ struct kvm_vcpu {gpa_t mmio_phys_addr;#endif +#ifdef CONFIG_KVM_ASYNC_PF +struct list_head async_pf_done; +spinlock_t async_pf_lock; +struct kvm_async_pf *async_pf_work; +#endif +struct kvm_vcpu_arch arch; };
@@ -276,6 +303,7 @@ void kvm_release_page_dirty(struct page *page);void kvm_set_page_dirty (struct page *page);void kvm_set_page_accessed (struct page *page); +int gfn_to_pfn_async (struct kvm *kvm,gfn_t gfn,pfn_t *pfn);pfn_t gfn_to_pfn (struct kvm *kvm,gfn_t gfn);pfn_t gfn_to_pfn_memslot (struct kvm *kvm,struct kvm_memory_slot *slot,gfn_t gfn);
include/trace/events/kvm.h +60 -0
66 lines not on this page · raw message
virt/kvm/Kconfig +3 -0
@@ -15,3 +15,6 @@ config KVM_APIC_ARCHITECTURE config KVM_MMIO bool + +config KVM_ASYNC_PF + bool
virt/kvm/kvm_main.c +241 -1
291 lines not on this page · raw message
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 9/12 Retry fault before vmentry
In reply to Gleb NatapovWhen page is swapped in it is mapped into guest memory only after guest tries to access it again and generate another fault. To save this fault we can map it immediately since we know that guest is going to access the page.
--- arch/x86/include/asm/kvm_host.h | 7 ++++++- arch/x86/kvm/mmu.c | 27 ++++++++++++++++++++------- arch/x86/kvm/paging_tmpl.h | 37 +++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.c | 9 +++++++++ virt/kvm/kvm_main.c | 2 ++ 5 files changed, 70 insertions(+), 12 deletions(-)
arch/x86/include/asm/kvm_host.h +6 -1
@@ -241,7 +241,8 @@ struct kvm_pio_request {*/ struct kvm_mmu {void (*new_cr3)(struct kvm_vcpu *vcpu); -int (*page_fault)(struct kvm_vcpu *vcpu,gva_t gva,u32 err); +int (*page_fault)(struct kvm_vcpu *vcpu,gva_t gva,u32 err,bool sync); +int (*page_fault_other_cr3)(struct kvm_vcpu *vcpu,gpa_t cr3,gva_t gva,u32 err);void (*free)(struct kvm_vcpu *vcpu);gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu,gva_t gva); void (*prefetch_page)(struct kvm_vcpu *vcpu,
@@ -541,6 +542,8 @@ struct kvm_x86_ops {struct kvm_arch_async_pf {u32 token; +gpa_t cr3; +u32 error_code; };extern struct kvm_x86_ops *kvm_x86_ops;
@@ -827,6 +830,8 @@ void kvm_arch_inject_async_page_not_present(struct kvm_vcpu *vcpu, struct kvm_async_pf *work);void kvm_arch_inject_async_page_present (struct kvm_vcpu *vcpu,struct kvm_async_pf *work); +void kvm_arch_async_page_ready (struct kvm_vcpu *vcpu, +struct kvm_async_pf *work);bool kvm_arch_can_inject_async_page_present (struct kvm_vcpu *vcpu);#endif /* _ASM_X86_KVM_HOST_H */
arch/x86/kvm/mmu.c +20 -7
@@ -2170,7 +2170,7 @@ static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) }static int nonpaging_page_fault (struct kvm_vcpu *vcpu,gva_t gva, -u32 error_code) +u32 error_code,bool sync) {gfn_t gfn;int r;
@@ -2189,10 +2189,13 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, error_code & PFERR_WRITE_MASK, gfn); } -int kvm_arch_setup_async_pf (struct kvm_vcpu *vcpu,gva_t gva,gfn_t gfn) +int kvm_arch_setup_async_pf (struct kvm_vcpu *vcpu,gpa_t cr3,gva_t gva, +gfn_t gfn,u32 error_code) {struct kvm_arch_async_pf arch; arch.token = (vcpu->arch.async_pf_id++ <<12 ) | vcpu->vcpu_id; + arch.cr3 = cr3; + arch.error_code = error_code;return kvm_setup_async_pf (vcpu, gva, gfn, &arch); }
@@ -2204,8 +2207,8 @@ static bool can_do_async_pf(struct kvm_vcpu *vcpu)return !!kvm_x86_ops->get_cpl (vcpu); } -static int tdp_page_fault (struct kvm_vcpu *vcpu,gva_t gpa, -u32 error_code) +static int tdp_page_fault (struct kvm_vcpu *vcpu,gva_t gpa,u32 error_code, +bool sync) {pfn_t pfn;int r;
@@ -2227,7 +2230,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, mmu_seq = vcpu->kvm->mmu_notifier_seq;smp_rmb (); -if (can_do_async_pf (vcpu)) { +if (!sync &&can_do_async_pf (vcpu)) { r =gfn_to_pfn_async (vcpu->kvm, gfn, &pfn);trace_kvm_try_async_get_page (r, pfn); }else {
@@ -2237,7 +2240,8 @@ do_sync: }if (!r) { -if (!kvm_arch_setup_async_pf (vcpu, gpa, gfn)) +if (!kvm_arch_setup_async_pf (vcpu, vcpu->arch.cr3, gpa, gfn, + error_code)) goto do_sync;return 0 ; }
@@ -2263,6 +2267,12 @@ out_unlock:return 0 ; } +static int tdp_page_fault_sync (struct kvm_vcpu *vcpu,gpa_t cr3,gva_t gpa, +u32 error_code) +{ +return tdp_page_fault (vcpu, gpa, error_code, true); +} +static void nonpaging_free (struct kvm_vcpu *vcpu) {mmu_free_roots (vcpu);
@@ -2387,6 +2397,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)ASSERT (is_pae (vcpu)); context->new_cr3 = paging_new_cr3; context->page_fault = paging64_page_fault; + context->page_fault_other_cr3 = paging64_page_fault_other_cr3; context->gva_to_gpa = paging64_gva_to_gpa; context->prefetch_page = paging64_prefetch_page; context->sync_page = paging64_sync_page;
@@ -2411,6 +2422,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)reset_rsvds_bits_mask (vcpu,PT32_ROOT_LEVEL ); context->new_cr3 = paging_new_cr3; context->page_fault = paging32_page_fault; + context->page_fault_other_cr3 = paging32_page_fault_other_cr3; context->gva_to_gpa = paging32_gva_to_gpa; context->free = paging_free; context->prefetch_page = paging32_prefetch_page;
@@ -2434,6 +2446,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) context->new_cr3 = nonpaging_new_cr3; context->page_fault = tdp_page_fault; + context->page_fault_other_cr3 = tdp_page_fault_sync; context->free = nonpaging_free; context->prefetch_page = nonpaging_prefetch_page; context->sync_page = nonpaging_sync_page;
@@ -2807,7 +2820,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)int r;enum emulation_result er; - r = vcpu->arch.mmu.page_fault (vcpu, cr2, error_code); + r = vcpu->arch.mmu.page_fault (vcpu, cr2, error_code, false);if (r <0 ) goto out;
arch/x86/kvm/paging_tmpl.h +33 -4
@@ -375,8 +375,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,* Returns: 1 if we need to emulate the instruction, 0 otherwise, or * a negative value on error. */ -static int FNAME (page_fault )(struct kvm_vcpu *vcpu,gva_t addr, -u32 error_code) +static int FNAME (page_fault )(struct kvm_vcpu *vcpu,gva_t addr,u32 error_code, +bool sync) {int write_fault = error_code &PFERR_WRITE_MASK ;int user_fault = error_code &PFERR_USER_MASK ;
@@ -420,7 +420,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, mmu_seq = vcpu->kvm->mmu_notifier_seq;smp_rmb (); -if (can_do_async_pf (vcpu)) { +if (!sync &&can_do_async_pf (vcpu)) { r =gfn_to_pfn_async (vcpu->kvm, walker.gfn, &pfn);trace_kvm_try_async_get_page (r, pfn); }else {
@@ -430,7 +430,8 @@ do_sync: }if (!r) { -if (!kvm_arch_setup_async_pf (vcpu, addr, walker.gfn)) +if (!kvm_arch_setup_async_pf (vcpu, vcpu->arch.cr3, addr, + walker.gfn, error_code)) goto do_sync;return 0 ; }
@@ -466,6 +467,34 @@ out_unlock:return 0 ; } +static int FNAME (page_fault_other_cr3 )(struct kvm_vcpu *vcpu,gpa_t cr3, +gva_t addr,u32 error_code) +{ +int r =0 ; +gpa_t curr_cr3 = vcpu->arch.cr3; + +if (curr_cr3 != cr3) { +/* +* We do page fault on behalf of a process that is sleeping +* because of async PF. PV guest takes reference to mm that cr3 +* belongs too, so it has to be valid here. +*/ +kvm_set_cr3 (vcpu, cr3); +if (kvm_mmu_reload (vcpu)) + goto switch_cr3; + } + + r =FNAME (page_fault)(vcpu, addr, error_code, true); + +switch_cr3: +if (curr_cr3 != vcpu->arch.cr3) { +kvm_set_cr3 (vcpu, curr_cr3); +kvm_mmu_reload (vcpu); + } + +return r; +} +static void FNAME (invlpg )(struct kvm_vcpu *vcpu,gva_t gva) {struct kvm_shadow_walk_iterator iterator;
arch/x86/kvm/x86.c +9 -0
@@ -5483,6 +5483,15 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) }EXPORT_SYMBOL_GPL (kvm_set_rflags); +void kvm_arch_async_page_ready (struct kvm_vcpu *vcpu, +struct kvm_async_pf *work) +{ +if (!vcpu->arch.mmu.page_fault_other_cr3 ||is_error_page (work->page)) +return ; + vcpu->arch.mmu.page_fault_other_cr3 (vcpu, work->arch.cr3, work->gva, + work->arch.error_code); +} +static int apf_put_user (struct kvm_vcpu *vcpu,u32 val) { if (unlikely(vcpu->arch.apf_memslot_ver !=
virt/kvm/kvm_main.c +2 -0
@@ -1322,6 +1322,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)spin_lock (&vcpu->async_pf_lock);list_del (&work->link);spin_unlock (&vcpu->async_pf_lock); +kvm_arch_async_page_ready (vcpu, work);put_page (work->page);async_pf_work_free (work); }
@@ -1336,6 +1337,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)list_del (&work->link);spin_unlock (&vcpu->async_pf_lock); +kvm_arch_async_page_ready (vcpu, work);kvm_arch_inject_async_page_present (vcpu, work);put_page (work->page);
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 10/12 Handle async PF in non preemptable context
In reply to Gleb NatapovIf async page fault is received by idle task or when preemp_count is not zero guest cannot reschedule, so do sti; hlt and wait for page to be ready. vcpu can still process interrupts while it waits for the page to be ready.
--- arch/x86/kernel/kvm.c | 36 ++++++++++++++++++++++++++++++++---- 1 files changed, 32 insertions(+), 4 deletions(-)
arch/x86/kernel/kvm.c +32 -4
@@ -33,6 +33,7 @@#include <linux/sched.h> #include <asm/timer.h> #include <asm/cpu.h> +#include <asm/tlbflush.h> #define MMU_QUEUE_SIZE 1024
@@ -64,6 +65,8 @@ struct kvm_task_sleep_node {wait_queue_head_t wq;u32 token;int cpu; +bool halted; +struct mm_struct *mm; }; static struct kvm_task_sleep_head {
@@ -92,6 +95,11 @@ static void apf_task_wait(struct task_struct *tsk, u32 token)struct kvm_task_sleep_head *b = &async_pf_sleepers[key];struct kvm_task_sleep_node n, *e;DEFINE_WAIT (wait); +int cpu, idle; + + cpu =get_cpu (); + idle =idle_cpu (cpu); +put_cpu ();spin_lock (&b->lock); e =_find_apf_task (b, token);
@@ -105,17 +113,31 @@ static void apf_task_wait(struct task_struct *tsk, u32 token) n.token = token; n.cpu =smp_processor_id (); + n.mm =percpu_read (cpu_tlbstate.active_mm); + n.halted = idle ||preempt_count () >1 ; +atomic_inc (&n.mm->mm_count);init_waitqueue_head (&n.wq);hlist_add_head (&n.link, &b->list);spin_unlock (&b->lock);for (;;) { -prepare_to_wait (&n.wq, &wait,TASK_UNINTERRUPTIBLE ); +if (!n.halted) +prepare_to_wait (&n.wq, &wait,TASK_UNINTERRUPTIBLE );if (hlist_unhashed (&n.link))break ; -schedule (); + +if (!n.halted) { +schedule (); + }else { +/* +* We cannot reschedule. So halt. +*/ +native_safe_halt (); +local_irq_disable (); + } } -finish_wait (&n.wq, &wait); +if (!n.halted) +finish_wait (&n.wq, &wait);return ; }
@@ -123,7 +145,12 @@ static void apf_task_wait(struct task_struct *tsk, u32 token)static void apf_task_wake_one (struct kvm_task_sleep_node *n) {hlist_del_init (&n->link); -if (waitqueue_active (&n->wq)) +if (!n->mm) +return ; +mmdrop (n->mm); +if (n->halted) +smp_send_reschedule (n->cpu); +else if (waitqueue_active (&n->wq))wake_up (&n->wq); }
@@ -153,6 +180,7 @@ again: } n->token = token; n->cpu =smp_processor_id (); + n->mm =NULL ;init_waitqueue_head (&n->wq);hlist_add_head (&n->link, &b->list); }else
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 11/12 Let host know whether the guest can handle async PF in non-userspace context.
In reply to Gleb NatapovIf guest can detect that it runs in non-preemptable context it can handle async PFs at any time, so let host know that it can send async PF even if guest cpu is not in userspace.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/include/asm/kvm_para.h | 1 + arch/x86/kernel/kvm.c | 3 +++ arch/x86/kvm/x86.c | 5 +++-- 4 files changed, 8 insertions(+), 2 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -365,6 +365,7 @@ struct kvm_vcpu_arch {unsigned long singlestep_rip;u32 __user *apf_data; +bool apf_send_user_only;u32 apf_memslot_ver;u64 apf_msr_val;u32 async_pf_id;
arch/x86/include/asm/kvm_para.h +1 -0
@@ -24,6 +24,7 @@#define KVM_MAX_MMU_OP_BATCH 32#define KVM_ASYNC_PF_ENABLED (1 << 0) +#define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1)/* Operations for KVM_HC_MMU_OP */ #define KVM_MMU_OP_WRITE_PTE 1
arch/x86/kernel/kvm.c +3 -0
@@ -480,6 +480,9 @@ void __cpuinit kvm_guest_cpu_init(void)if (kvm_para_has_feature (KVM_FEATURE_ASYNC_PF )) {u64 pa =__pa (&__get_cpu_var (apf_reason)); +#ifdef CONFIG_PREEMPT + pa |=KVM_ASYNC_PF_SEND_ALWAYS ; +#endif if (native_write_msr_safe (MSR_KVM_ASYNC_PF_EN , pa |KVM_ASYNC_PF_ENABLED , pa >>32 ))return ;
arch/x86/kvm/x86.c +3 -2
@@ -1009,8 +1009,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)int offset =offset_in_page (gpa);unsigned long addr; -/* Bits 1:5 are resrved, Should be zero */ -if (data &0x3e ) +/* Bits 2:5 are resrved, Should be zero */ +if (data &0x3c )return 1 ; vcpu->arch.apf_msr_val = data;
@@ -1032,6 +1032,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)return 1 ; } vcpu->arch.apf_memslot_ver = vcpu->kvm->memslot_version; + vcpu->arch.apf_send_user_only = !(data &KVM_ASYNC_PF_SEND_ALWAYS );kvm_async_pf_wakeup_all (vcpu);return 0 ; }
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 12/12 Send async PF when guest is not in userspace too.
In reply to Gleb Natapov--- arch/x86/kvm/mmu.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
arch/x86/kvm/mmu.c +7 -1
@@ -2204,7 +2204,13 @@ static bool can_do_async_pf(struct kvm_vcpu *vcpu)if (!vcpu->arch.apf_data ||kvm_event_needs_reinjection (vcpu))return false; -return !!kvm_x86_ops->get_cpl (vcpu); +if (vcpu->arch.apf_send_user_only) +return !!kvm_x86_ops->get_cpl (vcpu); + +if (!kvm_x86_ops->interrupt_allowed (vcpu)) +return false; + +return true; } static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
Signature · 7 lines
1.6.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Gleb Natapov
KVM virtualizes guest memory by means of shadow pages or HW assistance like NPT/EPT. Not all memory used by a guest is mapped into the guest address space or even present in a host memory at any given time. When vcpu tries to access memory page that is not mapped into the guest address space KVM is notified about it. KVM maps the page into the guest address space and resumes vcpu execution. If the page is swapped out from host memory vcpu execution is suspended till the page is not swapped into the memory again. This is inefficient since vcpu can do other work (run other task or serve interrupts) while page gets swapped in.
Quoted 9 lines
To overcome this inefficiency this patch series implements "asynchronous page fault" for paravirtualized KVM guests. If a page that vcpu is trying to access is swapped out KVM sends an async PF to the vcpu and continues vcpu execution. Requested page is swapped in by another thread in parallel. When vcpu gets async PF it puts faulted task to sleep until "wake up" interrupt is delivered. When the page is brought to the host memory KVM sends "wake up" interrupt and the guest's task resumes execution.
Is it true that to make this work, we will need a (PV) kernel driver for each guest OS (Windows, Linux, ...)?
Thanks,
Jun
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 21 lines · Jun Koi
Quoted 10 lines · Gleb Natapov
KVM virtualizes guest memory by means of shadow pages or HW assistance like NPT/EPT. Not all memory used by a guest is mapped into the guest address space or even present in a host memory at any given time. When vcpu tries to access memory page that is not mapped into the guest address space KVM is notified about it. KVM maps the page into the guest address space and resumes vcpu execution. If the page is swapped out from host memory vcpu execution is suspended till the page is not swapped into the memory again. This is inefficient since vcpu can do other work (run other task or serve interrupts) while page gets swapped in.
Quoted 9 lines
To overcome this inefficiency this patch series implements "asynchronous page fault" for paravirtualized KVM guests. If a page that vcpu is trying to access is swapped out KVM sends an async PF to the vcpu and continues vcpu execution. Requested page is swapped in by another thread in parallel. When vcpu gets async PF it puts faulted task to sleep until "wake up" interrupt is delivered. When the page is brought to the host memory KVM sends "wake up" interrupt and the guest's task resumes execution.
Quoted 2 lines
Is it true that to make this work, we will need a (PV) kernel driver for each guest OS (Windows, Linux, ...)?
This patch series contains the guest kernel code for Linux, as well as the host side code.
Signature · 7 lines
All rights reversed. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 4 lines · Jun Koi
Is it true that to make this work, we will need a (PV) kernel driver for each guest OS (Windows, Linux, ...)?
It's partially usable even without guest modifications; while servicing a host page fault we can still deliver interrupts to the guest (which might cause a context switch and thus further progress to be made).
Signature · 7 lines
error compiling committee.c: too many arguments to function -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Avi Kivity
Quoted 5 lines · Jun Koi
Is it true that to make this work, we will need a (PV) kernel driver for each guest OS (Windows, Linux, ...)?
It's partially usable even without guest modifications; while servicing a host page fault we can still deliver interrupts to the guest (which might cause a context switch and thus further progress to be made).
Lets say, in the case the guest has no PV driver. When we find that a guest page is swapped out, we can send a pagefault
to the guest to trick it to load that page in. And we dont need the driver at all.
Is that a reasonable solution?
Thanks,
J
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Jun Koi
Quoted 7 lines · Avi Kivity
Quoted 5 lines · Jun Koi
Is it true that to make this work, we will need a (PV) kernel driver for each guest OS (Windows, Linux, ...)?
Quoted 9 lines
Quoted 3 lines
It's partially usable even without guest modifications; while servicing a host page fault we can still deliver interrupts to the guest (which might cause a context switch and thus further progress to be made).
Lets say, in the case the guest has no PV driver. When we find that a guest page is swapped out, we can send a pagefault
to the guest to trick it to load that page in. And we dont need the driver at all.
That's not the guest who should load the page. From guest's point of view the page is in memory.
Quoted 4 lines
Is that a reasonable solution?
Thanks,
J
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Gleb Natapov
KVM virtualizes guest memory by means of shadow pages or HW assistance like NPT/EPT. Not all memory used by a guest is mapped into the guest address space or even present in a host memory at any given time. When vcpu tries to access memory page that is not mapped into the guest address space KVM is notified about it. KVM maps the page into the guest address space and resumes vcpu execution. If the page is swapped out from host memory vcpu execution is suspended till the page is not swapped into the memory again. This is inefficient since vcpu can do other work (run other task or serve interrupts) while page gets swapped in.
Quoted 8 lines
To overcome this inefficiency this patch series implements "asynchronous page fault" for paravirtualized KVM guests. If a page that vcpu is trying to access is swapped out KVM sends an async PF to the vcpu and continues vcpu execution. Requested page is swapped in by another thread in parallel. When vcpu gets async PF it puts faulted task to sleep until "wake up" interrupt is delivered. When the page is brought to the host memory KVM sends "wake up" interrupt and the guest's task resumes execution.
Some high level comments:
- cr2 used as token: better use the shared region? what if:
async pf queued
guest triple faults without a vmexit
inject async-pf-done with token in cr2
Also, in such scenario, can't you potentially corrupt guest memory after the triple fault by writing to the previously registered shared region address?
- The token can overflow relatively easy. Use u64?
- Does it really inject interrupts for non-pv guests while waiting for swapin? Can't see that. Wish it was more geared towards fv.
- Please share some perf numbers.
- Limit the number of queued async pf's per guest ?
- Unify gfn_to_pfn / gfn_to_pfn_async code in the pf handlers (easier to review).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 24 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
KVM virtualizes guest memory by means of shadow pages or HW assistance like NPT/EPT. Not all memory used by a guest is mapped into the guest address space or even present in a host memory at any given time. When vcpu tries to access memory page that is not mapped into the guest address space KVM is notified about it. KVM maps the page into the guest address space and resumes vcpu execution. If the page is swapped out from host memory vcpu execution is suspended till the page is not swapped into the memory again. This is inefficient since vcpu can do other work (run other task or serve interrupts) while page gets swapped in.
Quoted 8 lines
To overcome this inefficiency this patch series implements "asynchronous page fault" for paravirtualized KVM guests. If a page that vcpu is trying to access is swapped out KVM sends an async PF to the vcpu and continues vcpu execution. Requested page is swapped in by another thread in parallel. When vcpu gets async PF it puts faulted task to sleep until "wake up" interrupt is delivered. When the page is brought to the host memory KVM sends "wake up" interrupt and the guest's task resumes execution.
Some high level comments:
- cr2 used as token: better use the shared region? what if:
Quoted 8 lines
async pf queued
guest triple faults without a vmexit
inject async-pf-done with token in cr2Also, in such scenario, can't you potentially corrupt guest memory after the triple fault by writing to the previously registered shared region address?
After triple faults guest will reboot and this should clear all pending async pf injections. I'll check that this is indeed happens.
Quoted 1 line
- The token can overflow relatively easy. Use u64?
It not only can it frequently does, but since there can't be 2^20 outstanding page faults per vcpu simultaneously this doesn't cause any problem.
Quoted 4 lines
- Does it really inject interrupts for non-pv guests while waiting for swapin? Can't see that. Wish it was more geared towards fv.
No it does not yet. I only started to play with this to see how it can work.
Quoted 2 lines
- Please share some perf numbers.
OK.
Quoted 2 lines
- Limit the number of queued async pf's per guest ?
Make sense.
Quoted 2 lines
- Unify
gfn_to_pfn/gfn_to_pfn_asynccode in the pf handlers (easier to review).
OK.
--
Gleb.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Marcelo Tosatti
- Limit the number of queued async pf's per guest ?
This is automatically limited to the number of processes running in a guest :)
Signature · 7 lines
All rights reversed. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Rik van Riel
Quoted 1 line · Marcelo Tosatti
- Limit the number of queued async pf's per guest ?
This is automatically limited to the number of processes running in a guest :)
Only if the guest is nice and plays by the rules. What is to stop a malicious guest from just immediately switching back to userspace and kicking off another page-in every time it gets an async PF?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Bryan Donlan
Quoted 6 lines · Rik van Riel
Quoted 1 line · Marcelo Tosatti
- Limit the number of queued async pf's per guest ?
This is automatically limited to the number of processes running in a guest :)
Only if the guest is nice and plays by the rules. What is to stop a malicious guest from just immediately switching back to userspace and kicking off another page-in every time it gets an async PF?
Good point, a malicious guest could do that and ruin things for everyone. I guess we do need a limit :)
Signature · 7 lines
All rights reversed. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>