ioctl KVM_RUN 在什么情况下返回?

Pap*_*ika 2 c linux kvm qemu virtual-machine

https://github.com/qemu/qemu/blob/stable-4.2/cpus.c#L1290中有 Qemu 非常重要的一部分。我猜这是 KVM 上 CPU 的事件循环。

这是代码:

static void *qemu_kvm_cpu_thread_fn(void *arg)
{
    CPUState *cpu = arg;
    int r;

    rcu_register_thread();

    qemu_mutex_lock_iothread();
    qemu_thread_get_self(cpu->thread);
    cpu->thread_id = qemu_get_thread_id();
    cpu->can_do_io = 1;
    current_cpu = cpu;

    r = kvm_init_vcpu(cpu);
    if (r < 0) {
        error_report("kvm_init_vcpu failed: %s", strerror(-r));
        exit(1);
    }

    kvm_init_cpu_signals(cpu);

    /* signal CPU creation */
    cpu->created = true;
    qemu_cond_signal(&qemu_cpu_cond);
    qemu_guest_random_seed_thread_part2(cpu->random_seed);

    do {
        if (cpu_can_run(cpu)) {
            r = kvm_cpu_exec(cpu);
            if (r == EXCP_DEBUG) {
                cpu_handle_guest_debug(cpu);
            }
        }
        qemu_wait_io_event(cpu);
    } while (!cpu->unplug || cpu_can_run(cpu));

    qemu_kvm_destroy_vcpu(cpu);
    cpu->created = false;
    qemu_cond_signal(&qemu_cpu_cond);
    qemu_mutex_unlock_iothread();
    rcu_unregister_thread();
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

我对do循环感兴趣。kvm_cpu_exec它在循环中调用,其定义如下:https: //github.com/qemu/qemu/blob/stable-4.2/accel/kvm/kvm-all.c#L2285

在某一时刻kvm_cpu_exec,它调用run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);,它调用KVM_RUN此处记录的 ioctl: https: //www.kernel.org/doc/Documentation/virtual/kvm/api.txt

4.10 KVM_运行

功能:基本
架构:全部
类型:vcpu ioctl
参数:无
返回:成功时返回 0,错误时返回 -1
错误:
EINTR:未屏蔽的信号正在等待处理

此 ioctl 用于运行来宾虚拟 cpu。虽然没有
显式参数,但有一个隐式参数块,可以
通过 mmap() 偏移量 0 处的 vcpu fd 获得,其大小由
KVM_GET_VCPU_MMAP_SIZE 指定。参数块的格式为“struct
kvm_run”(见下文)。

我很难理解这个ioctl是否会阻止执行?什么情况下会返回?

我想了解一下正在发生的事情的背景。鉴于这一行qemu_wait_io_event(cpu),至少看起来ioctl会在每次从 CPU 读取/写入事件时返回。我不知道,我很困惑。

Pet*_*ell 5

KVM API 设计要求 VM 中的每个虚拟 CPU 在程序中都有一个关联的用户空间线程,例如控制该 VM 的 QEMU(该程序通常称为“虚拟机监视器”或 VMM,并且不必是QEMU;其他示例有 kvmtool 和 firecracker)。

该线程的行为类似于 QEMU 中的普通用户空间线程,直到它发出 KVM_RUN ioctl。此时,内核使用该线程在与该线程关联的 vCPU 上执行来宾代码。这将持续下去,直到遇到某些条件,这意味着来宾执行无法继续进行。(一个常见的情况是“来宾对 QEMU 模拟的设备进行了内存访问”。)此时,内核停止在此线程上运行来宾代码,而是使其从 KVM_RUN ioctl 返回。然后,QEMU 中的代码查看返回代码等,以找出为什么它重新获得控制权,处理任何情况,并循环返回以再次调用 KVM_RUN 以要求内核继续运行来宾代码。

通常,在运行虚拟机时,您会看到几乎所有时间线程都在 KVM_RUN ioctl 内,运行真正的来宾代码。有时执行会返回,QEMU 将花费尽可能少的时间做它需要做的事情,然后它循环并再次运行客户代码。提高VM效率的一种方法是尝试确保这些“VM出口”的数量尽可能低(例如,通过仔细选择为客户提供何种类型的网络或块设备)。