Skip to content

Commit f2de223

Browse files
committed
introduce lock in guestmanager to address concurrency at bottom layer
Signed-off-by: Harsh Rawat <harshrawat@microsoft.com>
1 parent 3adc5c9 commit f2de223

3 files changed

Lines changed: 40 additions & 15 deletions

File tree

internal/vm/guestmanager/guest.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package guestmanager
55
import (
66
"context"
77
"fmt"
8+
"sync"
89

910
"github.com/Microsoft/hcsshim/internal/gcs"
1011
"github.com/Microsoft/hcsshim/internal/log"
@@ -18,6 +19,13 @@ import (
1819

1920
// Guest manages the GCS connection and guest-side operations for a utility VM.
2021
type Guest struct {
22+
// mu serializes all operations that interact with the guest connection (gc).
23+
// This prevents parallel operations on the guest from racing on the GCS connection.
24+
mu sync.RWMutex
25+
26+
// gcsServiceID is the GUID that the guest uses to connect to GCS.
27+
gcsServiceID guid.GUID
28+
2129
log *logrus.Entry
2230
// uvm is the utility VM that this GuestManager is managing.
2331
// We restrict access to just lifetime manager and VMSocket manager.
@@ -55,6 +63,20 @@ func WithInitializationState(state *gcs.InitialGuestState) ConfigOption {
5563

5664
// CreateConnection accepts the GCS connection and performs initial setup.
5765
func (gm *Guest) CreateConnection(ctx context.Context, GCSServiceID guid.GUID, opts ...ConfigOption) error {
66+
gm.mu.Lock()
67+
defer gm.mu.Unlock()
68+
69+
// Return early if a connection is already active.
70+
if gm.gc != nil {
71+
// If the caller tried to connect to a different GCS service then error out.
72+
if gm.gcsServiceID != GCSServiceID {
73+
return fmt.Errorf("gcs service id mismatch: expected %s, got %s", gm.gcsServiceID, GCSServiceID)
74+
}
75+
return nil
76+
}
77+
78+
gm.gcsServiceID = GCSServiceID
79+
5880
// The guest needs to connect to predefined GCS port.
5981
// The host must already be listening on these port before the guest attempts to connect,
6082
// otherwise the connection would fail.
@@ -97,6 +119,9 @@ func (gm *Guest) CreateConnection(ctx context.Context, GCSServiceID guid.GUID, o
97119

98120
// CloseConnection closes any active GCS connection and listener.
99121
func (gm *Guest) CloseConnection() error {
122+
gm.mu.Lock()
123+
defer gm.mu.Unlock()
124+
100125
var err error
101126

102127
if gm.gc != nil {

internal/vm/guestmanager/manager.go

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88

99
"github.com/Microsoft/hcsshim/internal/cmd"
10-
"github.com/Microsoft/hcsshim/internal/cow"
1110
"github.com/Microsoft/hcsshim/internal/gcs"
1211

1312
"github.com/Microsoft/go-winio/pkg/guid"
@@ -26,10 +25,6 @@ type Manager interface {
2625
// Once the container is created, it can be managed using the returned `gcs.Container` interface.
2726
// `gcs.Container` uses the underlying guest connection to issue commands to the guest.
2827
CreateContainer(ctx context.Context, cid string, config interface{}) (*gcs.Container, error)
29-
// CreateProcess creates a process in the guest.
30-
// Once the process is created, it can be managed using the returned `cow.Process` interface.
31-
// `cow.Process` uses the underlying guest connection to issue commands to the guest.
32-
CreateProcess(ctx context.Context, settings interface{}) (cow.Process, error)
3328
// DumpStacks requests a stack dump from the guest and returns it as a string.
3429
DumpStacks(ctx context.Context) (string, error)
3530
// DeleteContainerState removes persisted state for the container identified by `cid` from the guest.
@@ -42,11 +37,17 @@ var _ Manager = (*Guest)(nil)
4237

4338
// Capabilities returns the capabilities of the guest connection.
4439
func (gm *Guest) Capabilities() gcs.GuestDefinedCapabilities {
40+
gm.mu.RLock()
41+
defer gm.mu.RUnlock()
42+
4543
return gm.gc.Capabilities()
4644
}
4745

4846
// CreateContainer creates a container in the guest with the given ID and config.
4947
func (gm *Guest) CreateContainer(ctx context.Context, cid string, config interface{}) (*gcs.Container, error) {
48+
gm.mu.Lock()
49+
defer gm.mu.Unlock()
50+
5051
c, err := gm.gc.CreateContainer(ctx, cid, config)
5152
if err != nil {
5253
return nil, fmt.Errorf("failed to create container %s: %w", cid, err)
@@ -55,18 +56,11 @@ func (gm *Guest) CreateContainer(ctx context.Context, cid string, config interfa
5556
return c, nil
5657
}
5758

58-
// CreateProcess creates a process in the guest using the provided settings.
59-
func (gm *Guest) CreateProcess(ctx context.Context, settings interface{}) (cow.Process, error) {
60-
p, err := gm.gc.CreateProcess(ctx, settings)
61-
if err != nil {
62-
return nil, fmt.Errorf("failed to create process: %w", err)
63-
}
64-
65-
return p, nil
66-
}
67-
6859
// DumpStacks requests a stack dump from the guest and returns it as a string.
6960
func (gm *Guest) DumpStacks(ctx context.Context) (string, error) {
61+
gm.mu.Lock()
62+
defer gm.mu.Unlock()
63+
7064
dump, err := gm.gc.DumpStacks(ctx)
7165
if err != nil {
7266
return "", fmt.Errorf("failed to dump stacks: %w", err)
@@ -77,6 +71,9 @@ func (gm *Guest) DumpStacks(ctx context.Context) (string, error) {
7771

7872
// DeleteContainerState removes persisted state for the container identified by cid from the guest.
7973
func (gm *Guest) DeleteContainerState(ctx context.Context, cid string) error {
74+
gm.mu.Lock()
75+
defer gm.mu.Unlock()
76+
8077
err := gm.gc.DeleteContainerState(ctx, cid)
8178
if err != nil {
8279
return fmt.Errorf("failed to delete container state for container %s: %w", cid, err)

internal/vm/guestmanager/request_helpers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ var errGuestConnectionUnavailable = errors.New("guest connection not initialized
1212
// modify sends a guest modification request via the guest connection.
1313
// This is a helper method to avoid having to check for a nil guest connection in every method that needs to send a request.
1414
func (gm *Guest) modify(ctx context.Context, req interface{}) error {
15+
gm.mu.Lock()
16+
defer gm.mu.Unlock()
17+
1518
if gm.gc == nil {
1619
return errGuestConnectionUnavailable
1720
}

0 commit comments

Comments
 (0)