@@ -21,6 +21,24 @@ import (
2121 "gvisor.dev/gvisor/pkg/cleanup"
2222)
2323
24+ // Timeout constants for QEMU operations
25+ const (
26+ // socketWaitTimeout is how long to wait for QMP socket to become available after process start
27+ socketWaitTimeout = 10 * time .Second
28+
29+ // migrationTimeout is how long to wait for incoming migration to complete during restore
30+ migrationTimeout = 30 * time .Second
31+
32+ // migrationPollInterval is how often to poll migration status
33+ migrationPollInterval = 50 * time .Millisecond
34+
35+ // socketPollInterval is how often to check if socket is ready
36+ socketPollInterval = 50 * time .Millisecond
37+
38+ // socketDialTimeout is timeout for individual socket connection attempts
39+ socketDialTimeout = 100 * time .Millisecond
40+ )
41+
2442func init () {
2543 hypervisor .RegisterSocketName (hypervisor .TypeQEMU , "qemu.sock" )
2644}
@@ -94,6 +112,8 @@ func (s *Starter) GetVersion(p *paths.Paths) (string, error) {
94112// StartVM launches QEMU with the VM configuration and returns a Hypervisor client.
95113// QEMU receives all configuration via command-line arguments at process start.
96114func (s * Starter ) StartVM (ctx context.Context , p * paths.Paths , version string , socketPath string , config hypervisor.VMConfig ) (int , hypervisor.Hypervisor , error ) {
115+ log := logger .FromContext (ctx )
116+
97117 // Get binary path
98118 binaryPath , err := s .GetBinaryPath (p , version )
99119 if err != nil {
@@ -157,7 +177,7 @@ func (s *Starter) StartVM(ctx context.Context, p *paths.Paths, version string, s
157177 defer cu .Clean ()
158178
159179 // Wait for socket to be ready
160- if err := waitForSocket (socketPath , 10 * time . Second ); err != nil {
180+ if err := waitForSocket (socketPath , socketWaitTimeout ); err != nil {
161181 vmmLogPath := filepath .Join (logsDir , "vmm.log" )
162182 if logData , readErr := os .ReadFile (vmmLogPath ); readErr == nil && len (logData ) > 0 {
163183 return 0 , nil , fmt .Errorf ("%w; vmm.log: %s" , err , string (logData ))
@@ -175,7 +195,7 @@ func (s *Starter) StartVM(ctx context.Context, p *paths.Paths, version string, s
175195 // QEMU migration files only contain memory state, not device config
176196 if err := saveVMConfig (instanceDir , config ); err != nil {
177197 // Non-fatal - restore just won't work
178- // Log would be nice but we don't have logger here
198+ log . WarnContext ( ctx , "failed to save VM config for restore" , "error" , err )
179199 }
180200
181201 // Success - release cleanup to prevent killing the process
@@ -290,7 +310,7 @@ func (s *Starter) RestoreVM(ctx context.Context, p *paths.Paths, version string,
290310 // QEMU loads the migration data from the exec subprocess
291311 // After loading, VM is in paused state and ready for 'cont'
292312 migrationWaitStart := time .Now ()
293- if err := waitForMigrationComplete (hv .client , 30 * time . Second ); err != nil {
313+ if err := waitForMigrationComplete (hv .client , migrationTimeout ); err != nil {
294314 return 0 , nil , fmt .Errorf ("wait for migration: %w" , err )
295315 }
296316 log .DebugContext (ctx , "migration complete" , "duration_ms" , time .Since (migrationWaitStart ).Milliseconds ())
@@ -308,13 +328,13 @@ func waitForMigrationComplete(client *Client, timeout time.Duration) error {
308328 info , err := client .QueryMigration ()
309329 if err != nil {
310330 // Ignore errors during migration
311- time .Sleep (100 * time . Millisecond )
331+ time .Sleep (migrationPollInterval )
312332 continue
313333 }
314334
315335 if info .Status == nil {
316336 // No migration status yet, might be loading
317- time .Sleep (100 * time . Millisecond )
337+ time .Sleep (migrationPollInterval )
318338 continue
319339 }
320340
@@ -330,7 +350,7 @@ func waitForMigrationComplete(client *Client, timeout time.Duration) error {
330350 return nil
331351 }
332352
333- time .Sleep (100 * time . Millisecond )
353+ time .Sleep (migrationPollInterval )
334354 }
335355 return fmt .Errorf ("migration timeout" )
336356}
@@ -392,7 +412,7 @@ func qemuInstallHint() string {
392412
393413// isSocketInUse checks if a Unix socket is actively being used
394414func isSocketInUse (socketPath string ) bool {
395- conn , err := net .DialTimeout ("unix" , socketPath , 100 * time . Millisecond )
415+ conn , err := net .DialTimeout ("unix" , socketPath , socketDialTimeout )
396416 if err != nil {
397417 return false
398418 }
@@ -404,12 +424,12 @@ func isSocketInUse(socketPath string) bool {
404424func waitForSocket (socketPath string , timeout time.Duration ) error {
405425 deadline := time .Now ().Add (timeout )
406426 for time .Now ().Before (deadline ) {
407- conn , err := net .DialTimeout ("unix" , socketPath , 100 * time . Millisecond )
427+ conn , err := net .DialTimeout ("unix" , socketPath , socketDialTimeout )
408428 if err == nil {
409429 conn .Close ()
410430 return nil
411431 }
412- time .Sleep (50 * time . Millisecond )
432+ time .Sleep (socketPollInterval )
413433 }
414434 return fmt .Errorf ("timeout waiting for socket" )
415435}
0 commit comments