Skip to content
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

Add support for creating and mounting merged CIMs. #2123

Closed
wants to merge 1 commit into from

Conversation

ambarve
Copy link
Contributor

@ambarve ambarve commented Apr 30, 2024

CimFS supports merging CIMs and then mounting those merged CIMs as an alternative to creating forked CIMs. Advantage of merging CIMs that each CIM can be stored in its own directory. Unlike forked ICMs there is no requirement that all CIMs need to be present in the same directory. This commit adds the Go wrappers and some tests for using the new CIM merging APIs.

@ambarve ambarve requested a review from a team as a code owner April 30, 2024 21:53
@ambarve ambarve force-pushed the cims_merged branch 2 times, most recently from 8d74e32 to 73c01f0 Compare May 1, 2024 17:45
defer winapi.CimCloseImage(cim.handle)

for _, lpath := range cimPaths {
if err := winapi.CimAddFsToMergedImage(cim.handle, lpath); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly does this do?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically I don't undestand what this step of adding merges to a cim file is for. I thought merging was purely a mount-time operation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two types of merged CIMs. On disk merge and in memory merge. What you are referring to is an in memory merge. However, with that we can't reuse an already merged CIM with multiple containers (every mount operation will create the merge). With an on disk merge, we create a merged CIM once (which basically just a CIM that contains metadata about underlying layer CIMs) and mount that merged CIM every time we start a container. CimAddFsToMergedImage call adds a CIM into such a merged CIM. Does that help?

@@ -62,6 +62,33 @@ func Create(imagePath string, oldFSName string, newFSName string) (_ *CimFsWrite
return &CimFsWriter{handle: handle, name: filepath.Join(imagePath, fsName)}, nil
}

// CreateMergedCim creates a new merged CIM from the CIMs provided in the `cimPaths` array. CIM at index 0 is
// considered to be the topmost CIM and the CIM at index `cimPath.length-1` is considered the base CIM
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be more untuitive to make cimPaths[0] the base CIM. Is there a reason we don't?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just how CimFS expects the layers to be added. The CimAddFstoMergedImage call expects that the topmost layer is added first and bottom most layer is added last. But I have updated the function to take cim paths in base to topmost order.

pkg/cimfs/mount_cim.go Outdated Show resolved Hide resolved
if err := winapi.CimMergeMountImage(uint32(len(cimsToMerge)), &cimsToMerge[0], mountFlags, &volumeGUID); err != nil {
return "", &MountError{Cim: mergedCimPath, Op: "MountMerged", Err: err}
}
return fmt.Sprintf("\\\\?\\Volume{%s}\\", volumeGUID.String()), nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use backticks for your string literal, you don't need to escape backslashes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally just prefer double quotes since backticks are easy to confuse with single quotes. Since rest of the file is already using double quotes, let us keep them here too?

// MountMergedCims mounts the given merged CIM (usually created with `CreateMergedCim`) at the a volume with
// given GUID. The `cimPaths` MUST be identical to the `cimPaths` passed to `CreateMergedCim` when creating
// this merged CIM.
func MountMergedCims(cimPaths []string, mergedCimPath string, mountFlags uint32, volumeGUID guid.GUID) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My previous impression of merged cims was that each cim could be mounted at a specific subdir in the filesystem. Is that not the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't need to explicitly mount individual CIMs, we just have to mount the final merged CIM.

// MountMergedCims mounts the given merged CIM (usually created with `CreateMergedCim`) at the a volume with
// given GUID. The `cimPaths` MUST be identical to the `cimPaths` passed to `CreateMergedCim` when creating
// this merged CIM.
func MountMergedCims(cimPaths []string, mergedCimPath string, mountFlags uint32, volumeGUID guid.GUID) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are any flags currently supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the standard mount flags that are already defined here are supported. I will add two more flags to this for blocked CIMs when I open that PR.

//sys CimMountImage(imagePath string, fsName string, flags uint32, volumeID *g) (hr error) = cimfs.CimMountImage?
//sys CimDismountImage(volumeID *g) (hr error) = cimfs.CimDismountImage?

//sys CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimfs.CimCreateImage?
//sys CimCloseImage(cimFSHandle FsHandle) = cimfs.CimCloseImage?
//sys CimCloseImage(cimFSHandle FsHandle) = cimfs.CimCloseImage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be good to add ? to the end here, in case it's attempted on a build without the DLL, it will error instead of panicking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think there is a bug in the mkwinsyscall code where if the function has void return and you put a ?, it will still generate a return value for the syscall. I couldn't find a fix for that after a cursory look, so I changed it here. We can make a fix to mkwinsyscall later on and then update this.

CimFS supports merging CIMs and then mounting those merged CIMs as an alternative to creating forked
CIMs. Advantage of merging CIMs that each CIM can be stored in its own directory. Unlike forked ICMs there is
no requirement that all CIMs need to be present in the same directory. This commit adds the Go wrappers and
some tests for using the new CIM merging APIs.

Also, fixes a bug related to the return value of CimCloseImage API. This API has void return so we shouldn't
be returning anything in our wrapper.

Signed-off-by: Amit Barve <ambarve@microsoft.com>
@ambarve
Copy link
Contributor Author

ambarve commented May 28, 2024

Closing this as CimFS APIs for mounting & merging block CIMs have changed. I will open a new PR with the updated APIs.

@ambarve ambarve closed this May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants