diff --git a/virtcontainers/qemu.go b/virtcontainers/qemu.go index 6494427607..de7e781bb6 100644 --- a/virtcontainers/qemu.go +++ b/virtcontainers/qemu.go @@ -25,9 +25,10 @@ import ( ) type qmpChannel struct { - ctx context.Context - path string - qmp *govmmQemu.QMP + ctx context.Context + path string + qmp *govmmQemu.QMP + disconn chan struct{} } // CPUDevice represents a CPU device which was hot-added in a running VM @@ -522,12 +523,15 @@ func (q *qemu) waitSandbox(timeout int) error { cfg := govmmQemu.QMPConfig{Logger: newQMPLogger()} var qmp *govmmQemu.QMP + var disconnectCh chan struct{} var ver *govmmQemu.QMPVersion var err error + // clear any possible old state before trying to connect again. + q.qmpShutdown() timeStart := time.Now() for { - disconnectCh := make(chan struct{}) + disconnectCh = make(chan struct{}) qmp, ver, err = govmmQemu.QMPStart(q.qmpMonitorCh.ctx, q.qmpMonitorCh.path, cfg, disconnectCh) if err == nil { break @@ -540,6 +544,7 @@ func (q *qemu) waitSandbox(timeout int) error { time.Sleep(time.Duration(50) * time.Millisecond) } q.qmpMonitorCh.qmp = qmp + q.qmpMonitorCh.disconn = disconnectCh defer q.qmpShutdown() qemuMajorVersion = ver.Major @@ -625,6 +630,7 @@ func (q *qemu) qmpSetup() error { return err } q.qmpMonitorCh.qmp = qmp + q.qmpMonitorCh.disconn = disconnectCh return nil } @@ -632,7 +638,11 @@ func (q *qemu) qmpSetup() error { func (q *qemu) qmpShutdown() { if q.qmpMonitorCh.qmp != nil { q.qmpMonitorCh.qmp.Shutdown() + // wait on disconnected channel to be sure that the qmp channel has + // been closed cleanly. + <-q.qmpMonitorCh.disconn q.qmpMonitorCh.qmp = nil + q.qmpMonitorCh.disconn = nil } } diff --git a/virtcontainers/qemu_test.go b/virtcontainers/qemu_test.go index 2d6d821556..277356e774 100644 --- a/virtcontainers/qemu_test.go +++ b/virtcontainers/qemu_test.go @@ -367,3 +367,18 @@ func TestHotplugUnsupportedDeviceType(t *testing.T) { _, err = q.hotplugRemoveDevice(&memoryDevice{0, 128}, fsDev) assert.Error(err) } + +func TestQMPSetupShutdown(t *testing.T) { + assert := assert.New(t) + + qemuConfig := newQemuConfig() + q := &qemu{ + config: qemuConfig, + } + + q.qmpShutdown() + + q.qmpMonitorCh.qmp = &govmmQemu.QMP{} + err := q.qmpSetup() + assert.Nil(err) +}