-
Notifications
You must be signed in to change notification settings - Fork 280
[shimV2] add plan9 device controller #2641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rawahars
wants to merge
1
commit into
microsoft:main
Choose a base branch
from
rawahars:plan9-dev-controller
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+207
−11
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //go:build windows && !wcow | ||
|
|
||
| // Package plan9 provides a controller for managing Plan9 file-share devices | ||
| // attached to a Utility VM (UVM). | ||
| // | ||
| // It handles attaching and detaching Plan9 shares to the VM via HCS modify | ||
| // calls. Guest-side mount operations (mapped-directory requests) are handled | ||
| // separately by the mount controller. | ||
| // | ||
| // The [Controller] interface is the primary entry point, with [Manager] as its | ||
| // concrete implementation. A single [Manager] manages all Plan9 shares for a UVM. | ||
| // | ||
| // # Lifecycle | ||
| // | ||
| // [Manager] tracks active shares by name in an internal map. | ||
| // | ||
| // - [Controller.AddToVM] adds a share and records its name in the map. | ||
| // If the HCS call fails, the share is not recorded. | ||
| // - [Controller.RemoveFromVM] removes a share and deletes its name from the map. | ||
| // If the share is not in the map, the call is a no-op. | ||
| package plan9 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| //go:build windows && !wcow | ||
|
|
||
| package plan9 | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" | ||
| ) | ||
|
|
||
| // Controller manages the lifecycle of Plan9 shares attached to a UVM. | ||
| type Controller interface { | ||
| // AddToVM adds a Plan9 share to the host VM and returns the generated share name. | ||
| // Guest-side mount is handled separately by the mount controller. | ||
| AddToVM(ctx context.Context, opts *AddOptions) (string, error) | ||
|
|
||
| // RemoveFromVM removes a Plan9 share identified by shareName from the host VM. | ||
| RemoveFromVM(ctx context.Context, shareName string) error | ||
| } | ||
|
|
||
| // AddOptions holds the configuration required to add a Plan9 share to the VM. | ||
| type AddOptions struct { | ||
| // HostPath is the path on the host to share into the VM. | ||
| HostPath string | ||
|
|
||
| // ReadOnly indicates whether the share should be mounted read-only. | ||
| ReadOnly bool | ||
|
|
||
| // Restrict enables single-file mapping mode for the share. | ||
| Restrict bool | ||
|
|
||
| // AllowedNames is the list of file names allowed when Restrict is true. | ||
| AllowedNames []string | ||
| } | ||
|
|
||
| // vmPlan9Manager manages adding and removing Plan9 shares on the host VM. | ||
| // Implemented by [vmmanager.UtilityVM]. | ||
| type vmPlan9Manager interface { | ||
| // AddPlan9 adds a plan 9 share to a running Utility VM. | ||
| AddPlan9(ctx context.Context, settings hcsschema.Plan9Share) error | ||
|
|
||
| // RemovePlan9 removes a plan 9 share from a running Utility VM. | ||
| RemovePlan9(ctx context.Context, settings hcsschema.Plan9Share) error | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| //go:build windows && !wcow | ||
|
|
||
| package plan9 | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "strconv" | ||
| "sync" | ||
|
|
||
| "github.com/Microsoft/hcsshim/internal/hcs" | ||
| hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" | ||
| "github.com/Microsoft/hcsshim/internal/log" | ||
| "github.com/Microsoft/hcsshim/internal/logfields" | ||
| "github.com/Microsoft/hcsshim/internal/vm/vmutils" | ||
|
|
||
| "github.com/sirupsen/logrus" | ||
| ) | ||
|
|
||
| // share-flag constants used in Plan9 HCS requests. | ||
| // | ||
| // These are marked private in the HCS schema. When public variants become | ||
| // available, we should replace these. | ||
| const ( | ||
| shareFlagsReadOnly int32 = 0x00000001 | ||
| shareFlagsLinuxMetadata int32 = 0x00000004 | ||
| shareFlagsRestrictFileAccess int32 = 0x00000080 | ||
| ) | ||
|
|
||
| // Manager is the concrete implementation of [Controller]. | ||
| type Manager struct { | ||
| mu sync.Mutex | ||
|
|
||
| // shares is the set of currently configured Plan9 share names. | ||
| // Guarded by mu. | ||
| shares map[string]struct{} | ||
|
|
||
| // noWritableFileShares disallows adding writable Plan9 shares. | ||
| noWritableFileShares bool | ||
|
|
||
| // vmPlan9Mgr performs host-side Plan9 add/remove on the VM. | ||
| vmPlan9Mgr vmPlan9Manager | ||
|
|
||
| // nameCounter is the monotonically increasing index used to | ||
| // generate unique share names. Guarded by mu. | ||
| nameCounter uint64 | ||
| } | ||
|
|
||
| var _ Controller = (*Manager)(nil) | ||
|
|
||
| // New creates a ready-to-use [Manager]. | ||
| func New( | ||
| vmPlan9Mgr vmPlan9Manager, | ||
| noWritableFileShares bool, | ||
| ) *Manager { | ||
| return &Manager{ | ||
| vmPlan9Mgr: vmPlan9Mgr, | ||
| noWritableFileShares: noWritableFileShares, | ||
| shares: make(map[string]struct{}), | ||
| } | ||
| } | ||
|
|
||
| // AddToVM adds a Plan9 share to the host VM and returns the generated share name. | ||
| func (m *Manager) AddToVM(ctx context.Context, opts *AddOptions) (_ string, err error) { | ||
| m.mu.Lock() | ||
| defer m.mu.Unlock() | ||
|
|
||
| // Ensure that adding the share is allowed. | ||
| if !opts.ReadOnly && m.noWritableFileShares { | ||
| return "", fmt.Errorf("adding writable shares is denied: %w", hcs.ErrOperationDenied) | ||
| } | ||
|
|
||
| // Build the Plan9 share flags bitmask from the caller-provided options. | ||
| flags := shareFlagsLinuxMetadata | ||
| if opts.ReadOnly { | ||
| flags |= shareFlagsReadOnly | ||
| } | ||
| if opts.Restrict { | ||
| flags |= shareFlagsRestrictFileAccess | ||
| } | ||
|
|
||
| // Generate a unique share name from the nameCounter. | ||
| name := strconv.FormatUint(m.nameCounter, 10) | ||
| m.nameCounter++ | ||
|
|
||
| ctx, _ = log.WithContext(ctx, logrus.WithField("shareName", name)) | ||
|
|
||
| log.G(ctx).WithFields(logrus.Fields{ | ||
| logfields.HostPath: opts.HostPath, | ||
| logfields.ReadOnly: opts.ReadOnly, | ||
| "RestrictFileAccess": opts.Restrict, | ||
| "AllowedFiles": opts.AllowedNames, | ||
| }).Tracef("adding plan9 share to host VM") | ||
|
|
||
| // Call into HCS to add the Plan9 share to the VM. | ||
| if err := m.vmPlan9Mgr.AddPlan9(ctx, hcsschema.Plan9Share{ | ||
| Name: name, | ||
| AccessName: name, | ||
| Path: opts.HostPath, | ||
| Port: vmutils.Plan9Port, | ||
| Flags: flags, | ||
| AllowedFiles: opts.AllowedNames, | ||
| }); err != nil { | ||
| return "", fmt.Errorf("add plan9 share %s to host: %w", name, err) | ||
| } | ||
|
|
||
| m.shares[name] = struct{}{} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would imply that you end up overwriting the hcsschema with just one entry. I think you need to refcount here |
||
|
|
||
| log.G(ctx).Info("plan9 share added to host VM") | ||
|
|
||
| return name, nil | ||
| } | ||
|
|
||
| // RemoveFromVM removes the Plan9 share identified by shareName from the host VM. | ||
| func (m *Manager) RemoveFromVM(ctx context.Context, shareName string) error { | ||
| m.mu.Lock() | ||
| defer m.mu.Unlock() | ||
|
|
||
| ctx, _ = log.WithContext(ctx, logrus.WithField("shareName", shareName)) | ||
|
|
||
| if _, ok := m.shares[shareName]; !ok { | ||
| log.G(ctx).Debug("plan9 share not found, skipping removal") | ||
| return nil | ||
| } | ||
|
|
||
| log.G(ctx).Debug("starting plan9 share removal") | ||
|
|
||
| // Call into HCS to remove the share from the VM. | ||
| if err := m.vmPlan9Mgr.RemovePlan9(ctx, hcsschema.Plan9Share{ | ||
| Name: shareName, | ||
| AccessName: shareName, | ||
| Port: vmutils.Plan9Port, | ||
| }); err != nil { | ||
| return fmt.Errorf("remove plan9 share %s from host: %w", shareName, err) | ||
| } | ||
|
|
||
| delete(m.shares, shareName) | ||
|
|
||
| log.G(ctx).Info("plan9 share removed from host VM") | ||
|
|
||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the vdev already handles ref counting of share host path to options then we dont need it here. But I'm hesitating to think it would.
If you call AddPlan9 with identical specs what does it do? Or is that they always have a different nameCounter so they always have a different set of settings?