Fix race conditions in hyperv readiness checking

- Listen before starting the vm
- Fix a device race caused by lazy hv_vsock init by waiting on network manager

[NO NEW TESTS NEEDED]

Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:
Jason T. Greene
2024-02-23 20:27:02 -06:00
parent 5a844511c8
commit b68d3c7a0e
3 changed files with 19 additions and 12 deletions

View File

@ -215,8 +215,15 @@ func (h HyperVStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func(
callbackFuncs.Add(rmIgnCallbackFunc)
}
waitReady, listener, err := mc.HyperVHypervisor.ReadyVsock.ListenSetupWait()
if err != nil {
return nil, nil, err
}
err = vm.Start()
if err != nil {
// cleanup the pending listener
_ = listener.Close()
return nil, nil, err
}
@ -225,7 +232,7 @@ func (h HyperVStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func(
}
callbackFuncs.Add(startCallback)
return nil, mc.HyperVHypervisor.ReadyVsock.Listen, err
return nil, waitReady, err
}
// State is returns the state as a define.status. for hyperv, state differs from others because

View File

@ -5,6 +5,7 @@ package vsock
import (
"errors"
"fmt"
"io"
"net"
"strings"
@ -258,21 +259,18 @@ func (hv *HVSockRegistryEntry) Listener() (net.Listener, error) {
return listener, nil
}
// Listen is used on the windows side to listen for anything to come
// over the hvsock as a signal the vm is booted
func (hv *HVSockRegistryEntry) Listen() error {
// ListenSetupWait creates an hvsock on the windows side and returns
// a wait function that, when called, blocks until it receives a ready
// notification on the vsock
func (hv *HVSockRegistryEntry) ListenSetupWait() (func() error, io.Closer, error) {
listener, err := hv.Listener()
if err != nil {
return err
return nil, nil, err
}
defer func() {
if err := listener.Close(); err != nil {
logrus.Error(err)
}
}()
errChan := make(chan error)
go sockets.ListenAndWaitOnSocket(errChan, listener)
return <-errChan
return func() error {
return <-errChan
}, listener, nil
}

View File

@ -28,7 +28,9 @@ func CreateReadyUnitFile(provider define.VMType, opts *ReadyUnitOpts) (string, e
if opts == nil || opts.Port == 0 {
return "", errors.New("no port provided for hyperv ready unit")
}
readyUnit.Add("Unit", "Requires", "sys-devices-virtual-net-vsock0.device")
readyUnit.Add("Unit", "After", "systemd-user-sessions.service")
readyUnit.Add("Unit", "After", "vsock-network.service")
readyUnit.Add("Service", "ExecStart", fmt.Sprintf("/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:%d'", opts.Port))
case define.WSLVirt: // WSL does not use ignition
return "", nil