(config: &VmLaunchConfig)
| 652 | } |
| 653 | |
| 654 | fn run_libkrun_vm(config: &VmLaunchConfig) -> Result<(), String> { |
| 655 | if let Some(kernel_image) = &config.kernel_image { |
| 656 | return Err(format!( |
| 657 | "selected kernel image is not supported by this VM backend: {}", |
| 658 | kernel_image.display() |
| 659 | )); |
| 660 | } |
| 661 | if !config.root_disk.is_file() { |
| 662 | return Err(format!( |
| 663 | "root disk image not found: {}", |
| 664 | config.root_disk.display() |
| 665 | )); |
| 666 | } |
| 667 | if !config.overlay_disk.is_file() { |
| 668 | return Err(format!( |
| 669 | "overlay disk image not found: {}", |
| 670 | config.overlay_disk.display() |
| 671 | )); |
| 672 | } |
| 673 | if let Some(image_disk) = &config.image_disk |
| 674 | && !image_disk.is_file() |
| 675 | { |
| 676 | return Err(format!("image disk not found: {}", image_disk.display())); |
| 677 | } |
| 678 | |
| 679 | // Arm procguard first, BEFORE we spawn gvproxy or fork libkrun, so |
| 680 | // that the launcher can't be orphaned during setup. The cleanup |
| 681 | // callback reads the GVPROXY_PID atomic (initially 0 — no-op) and |
| 682 | // the CHILD_PID atomic (the libkrun fork), so it stays correct as |
| 683 | // those slots get populated later in this function. Only ONE arm |
| 684 | // per process: racing two watchers for the same NOTE_EXIT event |
| 685 | // would cause whichever wins to skip the cleanup. |
| 686 | if let Err(err) = procguard::die_with_parent_cleanup(procguard_kill_children) { |
| 687 | return Err(format!("procguard arm failed: {err}")); |
| 688 | } |
| 689 | |
| 690 | #[cfg(target_os = "linux")] |
| 691 | check_kvm_access()?; |
| 692 | |
| 693 | let runtime_dir = configured_runtime_dir()?; |
| 694 | validate_runtime_dir(&runtime_dir)?; |
| 695 | configure_runtime_loader_env(&runtime_dir)?; |
| 696 | raise_nofile_limit(); |
| 697 | |
| 698 | let vm = VmContext::create(&runtime_dir, config.log_level)?; |
| 699 | vm.set_vm_config(config.vcpus, config.mem_mib)?; |
| 700 | vm.set_disks( |
| 701 | &config.root_disk, |
| 702 | &config.overlay_disk, |
| 703 | config.image_disk.as_deref(), |
| 704 | )?; |
| 705 | vm.set_workdir(&config.workdir)?; |
| 706 | |
| 707 | // Run gvproxy strictly as the guest's virtual NIC / DHCP / router. |
| 708 | // |
| 709 | // After the supervisor-initiated relay migration (#867), the driver |
| 710 | // no longer forwards any host-side ports into the guest — all ingress |
| 711 | // traffic for SSH and exec rides the outbound `ConnectSupervisor` |
no test coverage detected