Klemens Nanni <k...@openbsd.org> writes:
> kern.version=OpenBSD 7.4-current (GENERIC.MP) #1667: Wed Feb 7 20:09:35 MST > 2024 > dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP > > This boots fine: > > # cat /tmp/vm.conf > vm foo { > disable > disk /tmp/linux.qcow2 > } > # `which vmd` > # vmctl start -c foo > Welcome to Alpine Linux 3.19 > Kernel 6.6.11-0-virt on an x86_64 (/dev/ttyS0) > > foo login: > > This terminates the VM immediately after startup: > > # cat /tmp/vm.conf > vm foo { > disable > disk /tmp/linux.qcow2 > interface > } > # `which vmd` -dvv > > vmd: startup > vmd: vm_register: registering vm 1 > vmd: /tmp/vm.conf:5: vm "foo" registered (disabled) > vmd: vmd_configure: setting staggered start configuration to parallelism: 12 > and delay: 30 > vmd: vmd_configure: starting vms in staggered fashion > vmd: start_vm_batch: starting batch of 12 vms > vmd: start_vm_batch: not starting vm foo (disabled) > vmd: start_vm_batch: done starting vms > priv: config_getconfig: priv retrieving config > agentx: config_getconfig: agentx retrieving config > vmm: config_getconfig: vmm retrieving config > control: config_getconfig: control retrieving config > > # vmctl start -c foo > > vmd: vm_opentty: vm foo tty /dev/ttyp7 uid 0 gid 4 mode 620 > vmm: vm_register: registering vm 1 > vmd: vm_priv_ifconfig: interface tap0 description vm1-if0-foo > vmd: started foo (vm 1) successfully, tty /dev/ttyp7 > vm/foo: loadfile_bios: loaded BIOS image > vm/foo: pic_set_elcr: setting level triggered mode for irq 3 > vm/foo: pic_set_elcr: setting level triggered mode for irq 5 > vm/foo: virtio_init: vm "foo" vio0 lladdr fe:e1:bb:d1:ec:81 > vm/foo: pic_set_elcr: setting level triggered mode for irq 6 > vm/foo: foo: launching vioblk0 > vm/foo: virtio_dev_launch: sending 'd' type device struct > vm/foo: virtio_dev_launch: sending vm message for 'foo' > vm/foo/vioblk: vioblk_main: got viblk dev. num disk fds = 2, sync fd = 17, > async fd = 19, capacity = 0 seg_max = 126, vmm fd = 5 > vm/foo/vioblk0: qc2_open: qcow2 disk version 3 size 10737418240 end > 7340359680 snap 0 > vm/foo/vioblk0: qc2_open: qcow2 disk version 3 size 10737418240 end > 1433206784 snap 0 > vm/foo/vioblk0: vioblk_main: initialized vioblk0 with qcow2 image > (capacity=20971520) > vm/foo/vioblk0: vioblk_main: wiring in async vm event handler (fd=19) > vm/foo/vioblk0: vm_device_pipe: initializing 'd' device pipe (fd=19) > vm/foo/vioblk0: vioblk_main: wiring in sync channel handler (fd=17) > vm/foo/vioblk0: vioblk_main: telling vm foo device is ready > vm/foo/vioblk0: vioblk_main: sending heartbeat > vm/foo: virtio_dev_launch: receiving reply > vm/foo: virtio_dev_launch: device reports ready via sync channel > vm/foo: vm_device_pipe: initializing 'd' device pipe (fd=18) > vm/foo: foo: launching vionet0 > vm/foo: virtio_dev_launch: sending 'n' type device struct > vmm: vmm_sighdlr: handling signal 20 > vmm: vmm_sighdlr: terminated vm foo (id 1) > vmm: vm_remove: vmm vmm_sighdlr removing vm 1 from running config > vmm: vm_stop: vmm vmm_sighdlr stopping vm 1 > vmd: vm_stop: vmd vmd_dispatch_vmm stopping vm 1 > vm/foo/vionet: failed to receive vionet: Bad file descriptor > vm/foo/vioblk0: handle_sync_io: vioblk pipe dead (EV_READ) > vm/foo/vioblk0: dev_dispatch_vm: pipe dead (EV_READ) > > Connected to /dev/ttyp7 (speed 115200) > > [EOT] Try this diff. There was an issue in the order of closing disk fds. I also noticed we're not closing the sockets when closing the data fds, so that's added into virtio_dev_closefds(). With this i can boot a guest that uses a network interface and a qcow2 disk image with a base image. diff refs/heads/master refs/heads/vmd-fd-fix commit - 06bc238730aac28903aeab0d96b2427760b0110a commit + 8e46c12aa617cf136fdb3557f0177d41adb4d9d9 blob - afe3dd8f7a48cde226a4438567a8a3eb9dac2dce blob + ce052097a463bed0e75775d7acb2f036ca111572 --- usr.sbin/vmd/virtio.c +++ usr.sbin/vmd/virtio.c @@ -1301,8 +1301,8 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev { char *nargv[12], num[32], vmm_fd[32], vm_name[VM_NAME_MAX], t[2]; pid_t dev_pid; - int data_fds[VM_MAX_BASE_PER_DISK], sync_fds[2], async_fds[2], ret = 0; - size_t i, data_fds_sz, sz = 0; + int sync_fds[2], async_fds[2], ret = 0; + size_t sz = 0; struct viodev_msg msg; struct virtio_dev *dev_entry; struct imsg imsg; @@ -1310,14 +1310,10 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev switch (dev->dev_type) { case VMD_DEVTYPE_NET: - data_fds[0] = dev->vionet.data_fd; - data_fds_sz = 1; log_debug("%s: launching vionet%d", vm->vm_params.vmc_params.vcp_name, dev->vionet.idx); break; case VMD_DEVTYPE_DISK: - memcpy(&data_fds, dev->vioblk.disk_fd, sizeof(data_fds)); - data_fds_sz = dev->vioblk.ndisk_fd; log_debug("%s: launching vioblk%d", vm->vm_params.vmc_params.vcp_name, dev->vioblk.idx); break; @@ -1359,10 +1355,6 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev dev->sync_fd = sync_fds[1]; dev->async_fd = async_fds[1]; - /* Close data fds. Only the child device needs them now. */ - for (i = 0; i < data_fds_sz; i++) - close_fd(data_fds[i]); - /* 1. Send over our configured device. */ log_debug("%s: sending '%c' type device struct", __func__, dev->dev_type); @@ -1373,6 +1365,13 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev goto err; } + /* Close data fds. Only the child device needs them now. */ + if (virtio_dev_closefds(dev) == -1) { + log_warnx("%s: failed to close device data fds", + __func__); + goto err; + } + /* 2. Send over details on the VM (including memory fds). */ log_debug("%s: sending vm message for '%s'", __func__, vm->vm_params.vmc_params.vcp_name); @@ -1775,5 +1774,10 @@ virtio_dev_closefds(struct virtio_dev *dev) return (-1); } + close_fd(dev->async_fd); + dev->async_fd = -1; + close_fd(dev->sync_fd); + dev->sync_fd = -1; + return (0); }