11package qemu
22
33import (
4- "fmt"
54 "sync"
65
76 "github.com/kernel/hypeman/lib/hypervisor"
@@ -28,11 +27,11 @@ func GetOrCreateForType(socketPath string, hypervisorType hypervisor.Type) (*QEM
2827 // Try read lock first for existing connection
2928 clientPool .RLock ()
3029 if client , ok := clientPool .clients [socketPath ]; ok {
31- clientPool . RUnlock ()
32- if client . hypervisorType != hypervisorType {
33- return nil , poolTypeMismatchError ( socketPath , client . hypervisorType , hypervisorType )
30+ if client . hypervisorType == hypervisorType {
31+ clientPool . RUnlock ()
32+ return client , nil
3433 }
35- return client , nil
34+ // Backend identity changed for this socket path. Recreate under write lock.
3635 }
3736 clientPool .RUnlock ()
3837
@@ -42,10 +41,11 @@ func GetOrCreateForType(socketPath string, hypervisorType hypervisor.Type) (*QEM
4241
4342 // Double-check after acquiring write lock
4443 if client , ok := clientPool .clients [socketPath ]; ok {
45- if client .hypervisorType ! = hypervisorType {
46- return nil , poolTypeMismatchError ( socketPath , client . hypervisorType , hypervisorType )
44+ if client .hypervisorType = = hypervisorType {
45+ return client , nil
4746 }
48- return client , nil
47+ // Stale pooled backend type for this socket path. Drop and reconnect.
48+ removeLocked (socketPath )
4949 }
5050
5151 // Create new client
@@ -58,20 +58,22 @@ func GetOrCreateForType(socketPath string, hypervisorType hypervisor.Type) (*QEM
5858 return client , nil
5959}
6060
61- func poolTypeMismatchError (socketPath string , cached , requested hypervisor.Type ) error {
62- return fmt .Errorf ("QEMU client for %s is pooled as hypervisor %s, not %s" , socketPath , cached , requested )
63- }
64-
6561// Remove closes and removes a client from the pool.
6662// Called automatically on errors to allow fresh reconnection.
6763// Close is done asynchronously to avoid blocking if the connection is in a bad state.
6864func Remove (socketPath string ) {
6965 clientPool .Lock ()
7066 defer clientPool .Unlock ()
67+ removeLocked (socketPath )
68+ }
7169
70+ // removeLocked removes an entry while clientPool lock is held.
71+ func removeLocked (socketPath string ) {
7272 if client , ok := clientPool .clients [socketPath ]; ok {
7373 delete (clientPool .clients , socketPath )
7474 // Close asynchronously to avoid blocking on stuck connections
75- go client .client .Close ()
75+ if client .client != nil {
76+ go client .client .Close ()
77+ }
7678 }
7779}
0 commit comments