77
88 "github.com/kernel/hypeman/lib/forkvm"
99 "github.com/kernel/hypeman/lib/hypervisor"
10+ "go.opentelemetry.io/otel"
11+ "go.opentelemetry.io/otel/attribute"
12+ "go.opentelemetry.io/otel/trace"
1013)
1114
1215func withSnapshotSourceAliasReadLock (run func () error ) error {
@@ -16,13 +19,19 @@ func withSnapshotSourceAliasReadLock(run func() error) error {
1619}
1720
1821func prepareForkWithAliasReadLock (ctx context.Context , starter hypervisor.VMStarter , req hypervisor.ForkPrepareRequest ) (hypervisor.ForkPrepareResult , error ) {
22+ ctx , span := startInstancesSpan (ctx , otel .Tracer ("hypeman/instances" ), "instances.snapshot_alias.prepare_fork" ,
23+ attribute .String ("operation" , "snapshot_alias_prepare_fork" ),
24+ )
25+ var retErr error
26+ defer func () { finishInstancesSpan (span , retErr ) }()
27+
1928 var result hypervisor.ForkPrepareResult
20- err : = withSnapshotSourceAliasReadLock (func () error {
29+ retErr = withSnapshotSourceAliasReadLock (func () error {
2130 var err error
2231 result , err = starter .PrepareFork (ctx , req )
2332 return err
2433 })
25- return result , err
34+ return result , retErr
2635}
2736
2837func copyGuestDirectoryWithAliasReadLock (srcDir , dstDir string ) error {
@@ -32,16 +41,42 @@ func copyGuestDirectoryWithAliasReadLock(srcDir, dstDir string) error {
3241}
3342
3443func (m * manager ) copyForkSourceGuestDirectory (ctx context.Context , sourceState State , sourceID string , stored * StoredMetadata , srcDir , dstDir , deferredSnapshotMemoryPath string ) error {
44+ ctx , span := m .tracerOrDefault ().Start (ctx , "instances.fork.copy_guest_directory" ,
45+ trace .WithAttributes (
46+ attribute .String ("operation" , "fork_copy_guest_directory" ),
47+ attribute .String ("instance_id" , sourceID ),
48+ attribute .String ("source_state" , string (sourceState )),
49+ attribute .Bool ("deferred_snapshot_memory" , deferredSnapshotMemoryPath != "" ),
50+ ),
51+ )
52+ var retErr error
53+ defer func () { finishInstancesSpan (span , retErr ) }()
54+
3555 if sourceState == StateStandby {
36- if err := m .ensureSnapshotMemoryReady (ctx , m .paths .InstanceSnapshotLatest (sourceID ), m .snapshotJobKeyForInstance (sourceID ), stored .HypervisorType ); err != nil {
37- return fmt .Errorf ("prepare standby snapshot for fork: %w" , err )
56+ readyCtx , readyDone := m .startLifecycleStep (ctx , "instances.fork.copy_guest_directory.ensure_snapshot_memory_ready" ,
57+ attribute .String ("operation" , "fork_copy_ensure_snapshot_memory_ready" ),
58+ attribute .String ("instance_id" , sourceID ),
59+ attribute .String ("hypervisor" , string (stored .HypervisorType )),
60+ )
61+ if err := m .ensureSnapshotMemoryReady (readyCtx , m .paths .InstanceSnapshotLatest (sourceID ), m .snapshotJobKeyForInstance (sourceID ), stored .HypervisorType ); err != nil {
62+ readyDone (err )
63+ retErr = fmt .Errorf ("prepare standby snapshot for fork: %w" , err )
64+ return retErr
3865 }
66+ readyDone (nil )
3967 }
68+
4069 copyOptions := forkvm.CopyOptions {}
4170 if deferredSnapshotMemoryPath != "" {
4271 copyOptions .SkipRelativePaths = map [string ]struct {}{firecrackerSnapshotMemoryRelPath : {}}
4372 }
44- return withSnapshotSourceAliasReadLock (func () error {
73+
74+ _ , cloneDone := m .startLifecycleStep (ctx , "instances.fork.copy_guest_directory.clone" ,
75+ attribute .String ("operation" , "fork_copy_guest_directory_clone" ),
76+ attribute .String ("instance_id" , sourceID ),
77+ attribute .Bool ("deferred_snapshot_memory" , deferredSnapshotMemoryPath != "" ),
78+ )
79+ retErr = withSnapshotSourceAliasReadLock (func () error {
4580 if err := forkvm .CopyGuestDirectoryWithOptions (srcDir , dstDir , copyOptions ); err != nil {
4681 if errors .Is (err , forkvm .ErrSparseCopyUnsupported ) {
4782 return fmt .Errorf ("fork requires sparse-capable filesystem (SEEK_DATA/SEEK_HOLE unsupported): %w" , err )
@@ -50,17 +85,45 @@ func (m *manager) copyForkSourceGuestDirectory(ctx context.Context, sourceState
5085 }
5186 return nil
5287 })
88+ cloneDone (retErr )
89+ return retErr
5390}
5491
5592func (m * manager ) copySnapshotGuestDirectoryForFork (ctx context.Context , snapshotID string , hvType hypervisor.Type , dstDir , deferredSnapshotMemoryPath string ) error {
56- if err := m .ensureSnapshotMemoryReady (ctx , m .paths .SnapshotGuestDir (snapshotID ), "" , hvType ); err != nil {
57- return fmt .Errorf ("prepare snapshot memory for fork: %w" , err )
93+ ctx , span := m .tracerOrDefault ().Start (ctx , "instances.snapshot.copy_guest_directory" ,
94+ trace .WithAttributes (
95+ attribute .String ("operation" , "snapshot_copy_guest_directory" ),
96+ attribute .String ("snapshot_id" , snapshotID ),
97+ attribute .String ("hypervisor" , string (hvType )),
98+ attribute .Bool ("deferred_snapshot_memory" , deferredSnapshotMemoryPath != "" ),
99+ ),
100+ )
101+ var retErr error
102+ defer func () { finishInstancesSpan (span , retErr ) }()
103+
104+ readyCtx , readyDone := m .startLifecycleStep (ctx , "instances.snapshot.copy_guest_directory.ensure_snapshot_memory_ready" ,
105+ attribute .String ("operation" , "snapshot_copy_ensure_snapshot_memory_ready" ),
106+ attribute .String ("snapshot_id" , snapshotID ),
107+ attribute .String ("hypervisor" , string (hvType )),
108+ )
109+ if err := m .ensureSnapshotMemoryReady (readyCtx , m .paths .SnapshotGuestDir (snapshotID ), "" , hvType ); err != nil {
110+ readyDone (err )
111+ retErr = fmt .Errorf ("prepare snapshot memory for fork: %w" , err )
112+ return retErr
58113 }
114+ readyDone (nil )
115+
59116 copyOptions := forkvm.CopyOptions {}
60117 if deferredSnapshotMemoryPath != "" {
61118 copyOptions .SkipRelativePaths = map [string ]struct {}{firecrackerSnapshotMemoryRelPath : {}}
62119 }
63- return withSnapshotSourceAliasReadLock (func () error {
120+
121+ _ , cloneDone := m .startLifecycleStep (ctx , "instances.snapshot.copy_guest_directory.clone" ,
122+ attribute .String ("operation" , "snapshot_copy_guest_directory_clone" ),
123+ attribute .String ("snapshot_id" , snapshotID ),
124+ attribute .Bool ("deferred_snapshot_memory" , deferredSnapshotMemoryPath != "" ),
125+ )
126+ retErr = withSnapshotSourceAliasReadLock (func () error {
64127 if err := forkvm .CopyGuestDirectoryWithOptions (m .paths .SnapshotGuestDir (snapshotID ), dstDir , copyOptions ); err != nil {
65128 if errors .Is (err , forkvm .ErrSparseCopyUnsupported ) {
66129 return fmt .Errorf ("fork from snapshot requires sparse-capable filesystem (SEEK_DATA/SEEK_HOLE unsupported): %w" , err )
@@ -69,4 +132,6 @@ func (m *manager) copySnapshotGuestDirectoryForFork(ctx context.Context, snapsho
69132 }
70133 return nil
71134 })
135+ cloneDone (retErr )
136+ return retErr
72137}
0 commit comments