?? 接著KVM虛擬機(jī)IO處理過(guò)程中Guest Vm IO處理過(guò)程(http://blog.csdn.net/dashulu/article/details/16820281),本篇文章主要描述IO從guest vm跳轉(zhuǎn)到kvm和qemu后的處理過(guò)程.
? ? 首先回顧一下kvm的啟動(dòng)過(guò)程(http://blog.csdn.net/dashulu/article/details/17074675).qemu通過(guò)調(diào)用kvm提供的一系列接口來(lái)啟動(dòng)kvm. qemu的入口為vl.c中的main函數(shù),main函數(shù)通過(guò)調(diào)用kvm_init 和 machine->init來(lái)初始化kvm. 其中, machine->init會(huì)創(chuàng)建vcpu, 用一個(gè)線程去模擬vcpu, 該線程執(zhí)行的函數(shù)為qemu_kvm_cpu_thread_fn, 并且該線程最終kvm_cpu_exec,該函數(shù)調(diào)用kvm_vcpu_ioctl切換到kvm中,下次從kvm中返回時(shí),會(huì)接著執(zhí)行kvm_vcpu_ioctl之后的代碼,判斷exit_reason,然后進(jìn)行相應(yīng)處理.
[cpp] ?view plaincopy
int?kvm_cpu_exec(CPUState?*cpu)?? {?? ????struct?kvm_run?*run?=?cpu->kvm_run;?? ????int?ret,?run_ret;?? ?? ????DPRINTF("kvm_cpu_exec()\n");?? ?? ????if?(kvm_arch_process_async_events(cpu))?{?? ????????cpu->exit_request?=?0;?? ????????return?EXCP_HLT;?? ????}?? ?? ????do?{?? ????????if?(cpu->kvm_vcpu_dirty)?{?? ????????????kvm_arch_put_registers(cpu,?KVM_PUT_RUNTIME_STATE);?? ????????????cpu->kvm_vcpu_dirty?=?false;?? ????????}?? ?? ????????kvm_arch_pre_run(cpu,?run);?? ????????if?(cpu->exit_request)?{?? ????????????DPRINTF("interrupt?exit?requested\n");?? ???????????? ????????????qemu_cpu_kick_self();?? ????????}?? ????????qemu_mutex_unlock_iothread();?? ?? ????????run_ret?=?kvm_vcpu_ioctl(cpu,?KVM_RUN,?0);?? ?? ????????qemu_mutex_lock_iothread();?? ????????kvm_arch_post_run(cpu,?run);?? ?? ????????if?(run_ret?<?0)?{?? ????????????if?(run_ret?==?-EINTR?||?run_ret?==?-EAGAIN)?{?? ????????????????DPRINTF("io?window?exit\n");?? ????????????????ret?=?EXCP_INTERRUPT;?? ????????????????break;?? ????????????}?? ????????????fprintf(stderr,?"error:?kvm?run?failed?%s\n",?? ????????????????????strerror(-run_ret));?? ????????????abort();?? ????????}?? ?? ????????trace_kvm_run_exit(cpu->cpu_index,?run->exit_reason);?? ????????switch?(run->exit_reason)?{?? ????????case?KVM_EXIT_IO:?? ????????????DPRINTF("handle_io\n");?? ????????????kvm_handle_io(run->io.port,?? ??????????????????????????(uint8_t?*)run?+?run->io.data_offset,?? ??????????????????????????run->io.direction,?? ??????????????????????????run->io.size,?? ??????????????????????????run->io.count);?? ????????????ret?=?0;?? ????????????break;?? ????????case?KVM_EXIT_MMIO:?? ????????????DPRINTF("handle_mmio\n");?? ????????????cpu_physical_memory_rw(run->mmio.phys_addr,?? ???????????????????????????????????run->mmio.data,?? ???????????????????????????????????run->mmio.len,?? ???????????????????????????????????run->mmio.is_write);?? ????????????ret?=?0;?? ????????????break;?? ????????case?KVM_EXIT_IRQ_WINDOW_OPEN:?? ????????????DPRINTF("irq_window_open\n");?? ????????????ret?=?EXCP_INTERRUPT;?? ????????????break;?? ????????case?KVM_EXIT_SHUTDOWN:?? ????????????DPRINTF("shutdown\n");?? ????????????qemu_system_reset_request();?? ????????????ret?=?EXCP_INTERRUPT;?? ????????????break;?? ????????case?KVM_EXIT_UNKNOWN:?? ????????????fprintf(stderr,?"KVM:?unknown?exit,?hardware?reason?%"?PRIx64?"\n",?? ????????????????????(uint64_t)run->hw.hardware_exit_reason);?? ????????????ret?=?-1;?? ????????????break;?? ????????case?KVM_EXIT_INTERNAL_ERROR:?? ????????????ret?=?kvm_handle_internal_error(cpu,?run);?? ????????????break;?? ????????default:?? ????????????DPRINTF("kvm_arch_handle_exit\n");?? ????????????ret?=?kvm_arch_handle_exit(cpu,?run);?? ????????????break;?? ????????}?? ????}?while?(ret?==?0);?? ?? ????if?(ret?<?0)?{?? ????????cpu_dump_state(cpu,?stderr,?fprintf,?CPU_DUMP_CODE);?? ????????vm_stop(RUN_STATE_INTERNAL_ERROR);?? ????}?? ?? ????cpu->exit_request?=?0;?? ????return?ret;?? }?? kvm_vcpu_ioctl執(zhí)行時(shí),調(diào)用的kvm函數(shù)是virt/kvm/kvm-main.c中的kvm_vcpu_ioctl.c函數(shù).當(dāng)傳入?yún)?shù)為KVM_RUN時(shí),最終會(huì)調(diào)用到vcpu_enter_guest函數(shù), vcpu_enter_guest函數(shù)中調(diào)用了kvm_x86_ops->run(vcpu),在intel處理器架構(gòu)中該函數(shù)對(duì)應(yīng)的實(shí)現(xiàn)為vmx_vcpu_run, vmx_vcpu_run設(shè)置好寄存器狀態(tài)之后調(diào)用VM_LAUNCH或者VM_RESUME進(jìn)入guest vm, 一旦發(fā)生vm exit則從此處繼續(xù)執(zhí)行下去.
[cpp] ?view plaincopy
static?void?__noclone?vmx_vcpu_run(struct?kvm_vcpu?*vcpu)?? {?? ????struct?vcpu_vmx?*vmx?=?to_vmx(vcpu);?? ????unsigned?long?debugctlmsr;?? ?? ???? ????vmx->__launched?=?vmx->loaded_vmcs->launched;?? ????asm(?? ???????? ????????"push?%%"?_ASM_DX?";?push?%%"?_ASM_BP?";"?? ????????"push?%%"?_ASM_CX?"?\n\t"? ????????"push?%%"?_ASM_CX?"?\n\t"?? ????????"cmp?%%"?_ASM_SP?",?%c[host_rsp](%0)?\n\t"?? ????????"je?1f?\n\t"?? ????????"mov?%%"?_ASM_SP?",?%c[host_rsp](%0)?\n\t"?? ????????__ex(ASM_VMX_VMWRITE_RSP_RDX)?"\n\t"?? ????????"1:?\n\t"?? ???????? ????????"mov?%c[cr2](%0),?%%"?_ASM_AX?"?\n\t"?? ????????"mov?%%cr2,?%%"?_ASM_DX?"?\n\t"?? ????????"cmp?%%"?_ASM_AX?",?%%"?_ASM_DX?"?\n\t"?? ????????"je?2f?\n\t"?? ????????"mov?%%"?_ASM_AX",?%%cr2?\n\t"?? ????????"2:?\n\t"?? ???????? ????????"cmpl?$0,?%c[launched](%0)?\n\t"?? ???????? ????????"mov?%c[rax](%0),?%%"?_ASM_AX?"?\n\t"?? ????????"mov?%c[rbx](%0),?%%"?_ASM_BX?"?\n\t"?? ????????"mov?%c[rdx](%0),?%%"?_ASM_DX?"?\n\t"?? ????????"mov?%c[rsi](%0),?%%"?_ASM_SI?"?\n\t"?? ????????"mov?%c[rdi](%0),?%%"?_ASM_DI?"?\n\t"?? ????????"mov?%c[rbp](%0),?%%"?_ASM_BP?"?\n\t"?? #ifdef?CONFIG_X86_64?? ????????"mov?%c[r8](%0),??%%r8??\n\t"?? ????????"mov?%c[r9](%0),??%%r9??\n\t"?? ????????"mov?%c[r10](%0),?%%r10?\n\t"?? ????????"mov?%c[r11](%0),?%%r11?\n\t"?? ????????"mov?%c[r12](%0),?%%r12?\n\t"?? ????????"mov?%c[r13](%0),?%%r13?\n\t"?? ????????"mov?%c[r14](%0),?%%r14?\n\t"?? ????????"mov?%c[r15](%0),?%%r15?\n\t"?? #endif?? ????????"mov?%c[rcx](%0),?%%"?_ASM_CX?"?\n\t"? ?? ???????? ????????"jne?1f?\n\t"?? ????????__ex(ASM_VMX_VMLAUNCH)?"\n\t"?? ????????"jmp?2f?\n\t"?? ????????"1:?"?__ex(ASM_VMX_VMRESUME)?"\n\t"?? ????????"2:?"?? ???????? ????????"mov?%0,?%c[wordsize](%%"?_ASM_SP?")?\n\t"?? ????????"pop?%0?\n\t"?? ????????"mov?%%"?_ASM_AX?",?%c[rax](%0)?\n\t"?? ????????"mov?%%"?_ASM_BX?",?%c[rbx](%0)?\n\t"?? ????????__ASM_SIZE(pop)?"?%c[rcx](%0)?\n\t"?? ????????"mov?%%"?_ASM_DX?",?%c[rdx](%0)?\n\t"?? ????????"mov?%%"?_ASM_SI?",?%c[rsi](%0)?\n\t"?? ????????"mov?%%"?_ASM_DI?",?%c[rdi](%0)?\n\t"?? ????????"mov?%%"?_ASM_BP?",?%c[rbp](%0)?\n\t"?? #ifdef?CONFIG_X86_64?? ????????"mov?%%r8,??%c[r8](%0)?\n\t"?? ????????"mov?%%r9,??%c[r9](%0)?\n\t"?? ????????"mov?%%r10,?%c[r10](%0)?\n\t"?? ????????"mov?%%r11,?%c[r11](%0)?\n\t"?? ????????"mov?%%r12,?%c[r12](%0)?\n\t"?? ????????"mov?%%r13,?%c[r13](%0)?\n\t"?? ????????"mov?%%r14,?%c[r14](%0)?\n\t"?? ????????"mov?%%r15,?%c[r15](%0)?\n\t"?? #endif?? ????????"mov?%%cr2,?%%"?_ASM_AX?"???\n\t"?? ????????"mov?%%"?_ASM_AX?",?%c[cr2](%0)?\n\t"?? ?? ????????"pop??%%"?_ASM_BP?";?pop??%%"?_ASM_DX?"?\n\t"?? ????????"setbe?%c[fail](%0)?\n\t"?? ????????".pushsection?.rodata?\n\t"?? ????????".global?vmx_return?\n\t"?? ????????"vmx_return:?"?_ASM_PTR?"?2b?\n\t"?? ????????".popsection"?? ??????????:?:?"c"(vmx),?"d"((unsigned?long)HOST_RSP),?? ????????[launched]"i"(offsetof(struct?vcpu_vmx,?__launched)),?? ????????[fail]"i"(offsetof(struct?vcpu_vmx,?fail)),?? ????????[host_rsp]"i"(offsetof(struct?vcpu_vmx,?host_rsp)),?? ????????[rax]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RAX])),?? ????????[rbx]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RBX])),?? ????????[rcx]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RCX])),?? ????????[rdx]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RDX])),?? ????????[rsi]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RSI])),?? ????????[rdi]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RDI])),?? ????????[rbp]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_RBP])),?? #ifdef?CONFIG_X86_64?? ????????[r8]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R8])),?? ????????[r9]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R9])),?? ????????[r10]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R10])),?? ????????[r11]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R11])),?? ????????[r12]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R12])),?? ????????[r13]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R13])),?? ????????[r14]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R14])),?? ????????[r15]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.regs[VCPU_REGS_R15])),?? #endif?? ????????[cr2]"i"(offsetof(struct?vcpu_vmx,?vcpu.arch.cr2)),?? ????????[wordsize]"i"(sizeof(ulong))?? ??????????:?"cc",?"memory"?? #ifdef?CONFIG_X86_64?? ????????,?"rax",?"rbx",?"rdi",?"rsi"?? ????????,?"r8",?"r9",?"r10",?"r11",?"r12",?"r13",?"r14",?"r15"?? #else?? ????????,?"eax",?"ebx",?"edi",?"esi"?? #endif?? ??????????);?? ?? ???? ????if?(debugctlmsr)?? ????????update_debugctlmsr(debugctlmsr);?? ?? #ifndef?CONFIG_X86_64?? ???? ????loadsegment(ds,?__USER_DS);?? ????loadsegment(es,?__USER_DS);?? #endif?? ?? ????vcpu->arch.regs_avail?=?~((1?<<?VCPU_REGS_RIP)?|?(1?<<?VCPU_REGS_RSP)?? ??????????????????|?(1?<<?VCPU_EXREG_RFLAGS)?? ??????????????????|?(1?<<?VCPU_EXREG_CPL)?? ??????????????????|?(1?<<?VCPU_EXREG_PDPTR)?? ??????????????????|?(1?<<?VCPU_EXREG_SEGMENTS)?? ??????????????????|?(1?<<?VCPU_EXREG_CR3));?? ????vcpu->arch.regs_dirty?=?0;?? ?? ????vmx->idt_vectoring_info?=?vmcs_read32(IDT_VECTORING_INFO_FIELD);?? ?? ????if?(is_guest_mode(vcpu))?{?? ????????struct?vmcs12?*vmcs12?=?get_vmcs12(vcpu);?? ????????vmcs12->idt_vectoring_info_field?=?vmx->idt_vectoring_info;?? ????????if?(vmx->idt_vectoring_info?&?VECTORING_INFO_VALID_MASK)?{?? ????????????vmcs12->idt_vectoring_error_code?=?? ????????????????vmcs_read32(IDT_VECTORING_ERROR_CODE);?? ????????????vmcs12->vm_exit_instruction_len?=?? ????????????????vmcs_read32(VM_EXIT_INSTRUCTION_LEN);?? ????????}?? ????}?? ?? ????vmx->loaded_vmcs->launched?=?1;?? ?? ????vmx->exit_reason?=?vmcs_read32(VM_EXIT_REASON);?? ????trace_kvm_exit(vmx->exit_reason,?vcpu,?KVM_ISA_VMX);?? ?? ????vmx_complete_atomic_exit(vmx);?? ????vmx_recover_nmi_blocking(vmx);?? ????vmx_complete_interrupts(vmx);?? }?? ?
?
? ? 介紹完初始化的流程,可以介紹IO在kvm和qemu中的處理流程了. 當(dāng)Guest Vm進(jìn)行IO操作需要訪問(wèn)設(shè)備時(shí),就會(huì)觸發(fā)vm exit 返回到vmx_vcpu_run, vmx保存好vmcs并且記錄下VM_ExIT_REASON后返回到調(diào)用該函數(shù)的vcpu_enter_guest, 在vcpu_enter_guest函數(shù)末尾調(diào)用了r = kvm_x86_ops->handle_exit(vcpu), 該函數(shù)對(duì)應(yīng)于vmx_handle_exit函數(shù)(intel cpu架構(gòu)對(duì)應(yīng)關(guān)系可以查看vmx.c文件中static struct kvm_x86_ops vmx_x86_ops), vmx_handle_exit 調(diào)用kvm_vmx_exit_handlers[exit_reason](vcpu),該語(yǔ)句根據(jù)exit_reason調(diào)用不同的函數(shù),該數(shù)據(jù)結(jié)構(gòu)定義如下:
[cpp] ?view plaincopy
static?int?(*const?kvm_vmx_exit_handlers[])(struct?kvm_vcpu?*vcpu)?=?{?? ????[EXIT_REASON_EXCEPTION_NMI]???????????=?handle_exception,?? ????[EXIT_REASON_EXTERNAL_INTERRUPT]??????=?handle_external_interrupt,?? ????[EXIT_REASON_TRIPLE_FAULT]????????????=?handle_triple_fault,?? ????[EXIT_REASON_NMI_WINDOW]??????????=?handle_nmi_window,?? ????[EXIT_REASON_IO_INSTRUCTION]??????????=?handle_io,?? ????[EXIT_REASON_CR_ACCESS]???????????????=?handle_cr,?? ????[EXIT_REASON_DR_ACCESS]???????????????=?handle_dr,?? ????[EXIT_REASON_CPUID]???????????????????=?handle_cpuid,?? ????[EXIT_REASON_MSR_READ]????????????????=?handle_rdmsr,?? ????[EXIT_REASON_MSR_WRITE]???????????????=?handle_wrmsr,?? ????[EXIT_REASON_PENDING_INTERRUPT]???????=?handle_interrupt_window,?? ????[EXIT_REASON_HLT]?????????????????????=?handle_halt,?? ????[EXIT_REASON_INVD]????????????=?handle_invd,?? ????[EXIT_REASON_INVLPG]??????????????=?handle_invlpg,?? ????[EXIT_REASON_RDPMC]???????????????????=?handle_rdpmc,?? ????[EXIT_REASON_VMCALL]??????????????????=?handle_vmcall,?? ????[EXIT_REASON_VMCLEAR]?????????????????=?handle_vmclear,?? ????[EXIT_REASON_VMLAUNCH]????????????????=?handle_vmlaunch,?? ????[EXIT_REASON_VMPTRLD]?????????????????=?handle_vmptrld,?? ????[EXIT_REASON_VMPTRST]?????????????????=?handle_vmptrst,?? ????[EXIT_REASON_VMREAD]??????????????????=?handle_vmread,?? ????[EXIT_REASON_VMRESUME]????????????????=?handle_vmresume,?? ????[EXIT_REASON_VMWRITE]?????????????????=?handle_vmwrite,?? ????[EXIT_REASON_VMOFF]???????????????????=?handle_vmoff,?? ????[EXIT_REASON_VMON]????????????????????=?handle_vmon,?? ????[EXIT_REASON_TPR_BELOW_THRESHOLD]?????=?handle_tpr_below_threshold,?? ????[EXIT_REASON_APIC_ACCESS]?????????????=?handle_apic_access,?? ????[EXIT_REASON_WBINVD]??????????????????=?handle_wbinvd,?? ????[EXIT_REASON_XSETBV]??????????????????=?handle_xsetbv,?? ????[EXIT_REASON_TASK_SWITCH]?????????????=?handle_task_switch,?? ????[EXIT_REASON_MCE_DURING_VMENTRY]??????=?handle_machine_check,?? ????[EXIT_REASON_EPT_VIOLATION]???????=?handle_ept_violation,?? ????[EXIT_REASON_EPT_MISCONFIG]???????????=?handle_ept_misconfig,?? ????[EXIT_REASON_PAUSE_INSTRUCTION]???????=?handle_pause,?? ????[EXIT_REASON_MWAIT_INSTRUCTION]???????=?handle_invalid_op,?? ????[EXIT_REASON_MONITOR_INSTRUCTION]?????=?handle_invalid_op,?? };?? 如果是因?yàn)镮O原因?qū)е碌膙m exit,則調(diào)用的處理函數(shù)為handle_io,handle_io的處理可以查看(http://blog.csdn.net/fanwenyi/article/details/12748613), 該過(guò)程結(jié)束之后需要qemu去處理IO,這時(shí)候會(huì)返回到qemu, 在kvm_cpu_exec中繼續(xù)執(zhí)行下去,看上面kvm_cpu_exec的代碼,如果是因?yàn)镮O原因返回到qemu,會(huì)調(diào)用kvm_handle_io函數(shù).
[cpp] ?view plaincopy
switch?(run->exit_reason)?{?? ????????case?KVM_EXIT_IO:?? ????????????DPRINTF("handle_io\n");?? ????????????kvm_handle_io(run->io.port,?? ??????????????????????????(uint8_t?*)run?+?run->io.data_offset,?? ??????????????????????????run->io.direction,?? ??????????????????????????run->io.size,?? ??????????????????????????run->io.count);?? ????????????ret?=?0;?? ????????????break;?? kvm_handle_io調(diào)用cpu_outb, cpu_outw等指令處理IO操作.
?
? ? 假設(shè)虛擬機(jī)是用raw格式的磁盤(pán),則IO在qemu中處理時(shí)經(jīng)過(guò)的函數(shù)棧如下所示:
[cpp] ?view plaincopy
#0?bdrv_aio_writev?(bs=0x55555629e9b0,?sector_num=870456,??? qiov=0x555556715ab0,?nb_sectors=1,??? cb=0x55555570161b?<ide_sector_write_cb>,?opaque=0x5555567157b8)?? at?block.c:3408?? #1?0x0000555555701960?in?ide_sector_write?(s=0x5555567157b8)?? at?hw/ide/core.c:798?? #2?0x00005555557047ae?in?ide_data_writew?(opaque=0x555556715740,?addr=496,??? val=8995)?at?hw/ide/core.c:1907?? #3?0x00005555558d9e4c?in?portio_write?(opaque=0x5555565c0670,?addr=0,??? data=8995,?size=2)?at?/home/dashu/kvm/qemu/qemu-dev-zwu/ioport.c:174?? #4?0x00005555558e13d5?in?memory_region_write_accessor?(mr=0x5555565c0670,??? addr=0,?value=0x7fffb4dbd528,?size=2,?shift=0,?mask=65535)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/memory.c:440?? #5?0x00005555558e151d?in?access_with_adjusted_size?(addr=0,??? value=0x7fffb4dbd528,?size=2,?access_size_min=1,?access_size_max=4,??? access=0x5555558e1341?<memory_region_write_accessor>,?mr=0x5555565c0670)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/memory.c:477?? #6?0x00005555558e3dfb?in?memory_region_dispatch_write?(mr=0x5555565c0670,??? addr=0,?data=8995,?size=2)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/memory.c:984?? #7?0x00005555558e7384?in?io_mem_write?(mr=0x5555565c0670,?addr=0,?val=8995,??? size=2)?at?/home/dashu/kvm/qemu/qemu-dev-zwu/memory.c:1748?? #8?0x000055555586a18e?in?address_space_rw?(as=0x555556216d80,?addr=496,??? buf=0x7fffb4dbd670?"##",?len=2,?is_write=true)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/exec.c:1968?? #9?0x000055555586a474?in?address_space_write?(as=0x555556216d80,?addr=496,??? buf=0x7fffb4dbd670?"##",?len=2)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/exec.c:2030?? #10?0x00005555558d98c9?in?cpu_outw?(addr=496,?val=8995)?? at?/home/dashu/kvm/qemu/qemu-dev-zwu/ioport.c:61?? bdrv_aio_writev最終調(diào)用bdrv_co_aio_rw_vector函數(shù), 該函數(shù)調(diào)用co = qemu_coroutine_create(bdrv_co_do_rw) 創(chuàng)建一個(gè)協(xié)程去執(zhí)行bdrv_co_do_rw函數(shù),bdrv_co_wo_rw函數(shù)的函數(shù)棧如下:
[cpp] ?view plaincopy
#1?0x000055555563653c?in?paio_submit?(bs=0x5555562a13d0,?fd=10,?sector_num=2,??? qiov=0x555556715ab0,?nb_sectors=1,??? cb=0x5555556028b1?<bdrv_co_io_em_complete>,?opaque=0x555556964e30,?type=1)?? at?block/raw-posix.c:825?? #2?0x0000555555636659?in?raw_aio_submit?(bs=0x5555562a13d0,?sector_num=2,??? qiov=0x555556715ab0,?nb_sectors=1,??? cb=0x5555556028b1?<bdrv_co_io_em_complete>,?opaque=0x555556964e30,?type=1)?? at?block/raw-posix.c:853?? #3?0x00005555556366c9?in?raw_aio_readv?(bs=0x5555562a13d0,?sector_num=2,??? qiov=0x555556715ab0,?nb_sectors=1,??? cb=0x5555556028b1?<bdrv_co_io_em_complete>,?opaque=0x555556964e30)?? at?block/raw-posix.c:861?? #4?0x00005555556029b8?in?bdrv_co_io_em?(bs=0x5555562a13d0,?sector_num=2,??? nb_sectors=1,?iov=0x555556715ab0,?is_write=false)?at?block.c:4038?? #5?0x0000555555602a49?in?bdrv_co_readv_em?(bs=0x5555562a13d0,?sector_num=2,??? nb_sectors=1,?iov=0x555556715ab0)?at?block.c:4055?? #6?0x00005555555fed61?in?bdrv_co_do_readv?(bs=0x5555562a13d0,?sector_num=2,??? nb_sectors=1,?qiov=0x555556715ab0,?flags=0)?at?block.c:2547?? #7?0x00005555555fee03?in?bdrv_co_readv?(bs=0x5555562a13d0,?sector_num=2,??? nb_sectors=1,?qiov=0x555556715ab0)?at?block.c:2573?? #8?0x0000555555637d8c?in?raw_co_readv?(bs=0x55555629e9b0,?sector_num=2,??? nb_sectors=1,?qiov=0x555556715ab0)?at?block/raw.c:47?? #9?0x00005555555fed61?in?bdrv_co_do_readv?(bs=0x55555629e9b0,?sector_num=2,??? nb_sectors=1,?qiov=0x555556715ab0,?flags=0)?at?block.c:2547?? #10?0x00005555556023af?in?bdrv_co_do_rw??? 最終在paio_summit中會(huì)往線程池中提交一個(gè)請(qǐng)求thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque), 由調(diào)度器去執(zhí)行aio_worker函數(shù),aio_worker是真正做IO操作的函數(shù),它通過(guò)pwrite和pread去讀取磁盤(pán).
?
? ? 當(dāng)qemu完成IO操作后,會(huì)在kvm_cpu_exec函數(shù)的循環(huán)中,調(diào)用kvm_vcpu_ioctl重新進(jìn)入kvm.
? ? 以上闡述了IO操作在kvm和qemu中處理的整個(gè)過(guò)程.
?
參考資料:
1. kvm代碼解析連載(二):io的虛擬化:http://blog.csdn.net/fanwenyi/article/details/12748613
總結(jié)
以上是生活随笔 為你收集整理的KVM虚拟机IO处理过程(二) ----QEMU/KVM I/O 处理过程 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。