Skip to content

Add cgroup v2 support while maintaining v1 compatibility#2632

Open
jiechen0826 wants to merge 9 commits intomicrosoft:mainfrom
jiechen0826:cgroup-v2-clean
Open

Add cgroup v2 support while maintaining v1 compatibility#2632
jiechen0826 wants to merge 9 commits intomicrosoft:mainfrom
jiechen0826:cgroup-v2-clean

Conversation

@jiechen0826
Copy link
Contributor

This pull request introduces comprehensive improvements to cgroup (control group) initialization and management, especially around supporting both cgroup v1 and v2, and adds extensive testing for cgroup resource handling and memory event monitoring. It also updates several dependencies to newer versions for improved compatibility and stability.

Cgroup Initialization and Detection Improvements:

  • Refactored init/init.c to robustly detect and initialize cgroup v1 or v2 at boot. The system now checks for kernel parameters disabling cgroup v2, attempts a test mount to verify v2 availability, and mounts tmpfs for v1 only if needed. This ensures correct cgroup setup based on the environment, with improved logging for troubleshooting.

Cross-distribution compatibility:

  • Automatic cgroup version detection: The implementation tests cgroup v2 availability by attempting a test mount and checking for controllers
    • Yocto: Uses cgroup v1 due to kernel configuration (v2 not available)
    • Azure Linux: Uses cgroup v2 if available and working, otherwise falls back to v1
    • Ubuntu: Uses cgroup v2 (available and working by default)
  • Kernel parameter override: All distributions can use cgroup_no_v2=all kernel parameter to force cgroup v1 usage, which is properly detected and respected
  • The implementation provides automatic fallback from v2 to v1 when v2 is unavailable, disabled, or non-functional, ensuring compatibility across all supported distributions without requiring distribution-specific code paths

Testing Enhancements for Cgroup Management:

  • Added cmd/gcs/cgroup_manager_test.go with tests covering interface compatibility, resource conversion, cgroup version detection, error handling for invalid paths and permissions, and edge cases for resource limits and stats conversion.
  • Added cmd/gcs/memory_event_test.go with tests for cgroup v2 memory event monitoring, OOM event file descriptors, memory threshold detection, error handling, and resource creation scenarios.

Dependency and Compatibility Updates:

  • Updated go.mod to newer versions of several dependencies, including containerd/cgroups, containerd/containerd, opencontainers/runtime-spec, urfave/cli/v2, and others, improving compatibility with recent upstream changes and bug fixes.
  • Added cgroup v2 imports to internal/guest/runtime/hcsv2/container.go to support the new functionality.

Other Codebase Improvements:

  • Included missing header <dirent.h> in init/init.c for directory operations.
  • Added forward declarations and improved code organization in init/init.c for better maintainability.

These changes collectively improve the reliability and test coverage of cgroup management, ensure compatibility with modern Linux systems, and lay the groundwork for future enhancements.

@jiechen0826 jiechen0826 requested a review from a team as a code owner March 17, 2026 18:01
Copy link
Contributor

Choose a reason for hiding this comment

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

we already have these in go.mod via tool directives.
also, why do we need the "github.com/containerd/containerd/v2/pkg/oci" import? it doest look like its being used anywhere

Comment on lines +13 to +21
func TestCgroupManagerInterface_Compatibility(t *testing.T) {
// Test that both managers implement the CgroupManager interface
var v1mgr CgroupManager = &V1Manager{}
var v2mgr CgroupManager = &V2Manager{path: "/test/path"}

// Test that both managers implement the interface
_ = v1mgr
_ = v2mgr
}
Copy link
Contributor

Choose a reason for hiding this comment

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

in main.go:

var _ CgroupManager = &V1Manager{}
var _ CgroupManager = &V2Manager{}

return false
}

// CgroupManager provides a unified interface for cgroup v1 and v2 operations
Copy link
Contributor

Choose a reason for hiding this comment

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

probably best to move the CgroupManager code to internal/guest/cgroup (or something similarly named)

}

// Try mounting cgroup v2 to see if it works
bool is_cgroup_v2_available() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
bool is_cgroup_v2_available() {
bool try_init_cgroups_v2() {

so that way we can remove void init_cgroups_v2()

#ifdef DEBUG
printf("init_cgroups\n");
#endif
dmesgInfo("Microsoft.hcsshim init: cgroup migration version starting\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

is this log needed? we already get cgroup info from init_cgroups

Comment on lines +42 to +50
func isCgroupV2() bool {
// Check if cgroup v2 was disabled via kernel parameter
if isCgroupV2DisabledByKernel() {
return false
}

_, err := os.Stat("/sys/fs/cgroup/cgroup.controllers")
return err == nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

semiduplicated by isCgroupV2 in internal/guest/runtime/hcsv2/container.go

}

// convertV2StatsToV1Stats converts cgroup v2 stats to v1 stats format
func convertV2StatsToV1Stats(v2Stats *cgroups2stats.Metrics) *cgroups1stats.Metrics {
Copy link
Contributor

Choose a reason for hiding this comment

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

(semi?) duplicated by convertV2StatsToV1 in internal/guest/runtime/hcsv2/container.go

NetworkNamespace string
CgroupPath string
CgroupControl cgroups.Cgroup
CgroupControl interface{} // Can be either cgroups.Cgroup (v1) or *cgroups2.Manager (v2)
Copy link
Contributor

Choose a reason for hiding this comment

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

we already have the CgroupManager defined in cmd/gcs/main.go (which we probably should extract and move elsewhere)
can we just rely on that here and for virtualPodsCgroupParent so we dont need to recreate and reimplement all the same manager creation and stat code?

Comment on lines +48 to +49
_, err := os.Stat("/sys/fs/cgroup/cgroup.controllers")
return err == nil
Copy link
Contributor

Choose a reason for hiding this comment

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

"github.com/containerd/cgroups/v3".Mode() == "github.com/containerd/cgroups/v3".Unified
(probably also want to return true for hybrid cgroup mode)

Signed-off-by: Jie Chen <jiechen3@microsoft.com>
- Remove unnecessary containerd/v2/pkg/oci import from tools.go
- Add missing protobuild dependencies
- Update vendor directory for CI compatibility

Addresses reviewer feedback on tools.go and fixes CI protobuf generation.
- Remove go.work.sum file causing vendor inconsistencies
- Fix tools.go imports per reviewer feedback (remove unused containerd/v2/pkg/oci)
- Regenerate vendor directory with GOWORK=off for consistency
- All golangci-lint errors resolved (0 issues)
- Protobuf generation working correctly

Addresses CI failures in verify-vendor, lint (linux), and protos jobs.
Addresses reviewer feedback on tools.go imports.

Signed-off-by: Jie Chen <jiechen0826@users.noreply.github.com>
Signed-off-by: Jie Chen <jiechen3@microsoft.com>
- Clean vendor directory and regenerate with GOWORK=off for CI consistency
- Update protobuf generated files via Update-Proto.ps1 script
- Regenerate syscalls and mocks via go generate
- Fix test/go.mod with go mod tidy

This resolves the verify-vendor, protos, and go-generate CI check failures.

Signed-off-by: Jie Chen <jiechen3@microsoft.com>
- Regenerated vendor/ directory using 'go mod vendor'
- Resolves 'go: inconsistent vendoring' errors in CI pipeline
- Fixes protos, Go Generate, verify-vendor, and Analyze jobs
- All core functionality (VMBus networking, cgroup v2) remains intact
- Add mkwinsyscall, goversioninfo, and mockgen tools to tools.go
- Update dependencies and vendor directory to include required tools
- This should fix CI failures in Go Generate job
- Change go:generate from 'go tool' to 'go run' syntax for mkwinsyscall calls
- This fixes CI failures in the 'go-gen' job where external tools cannot be invoked with 'go tool' syntax
- All mkwinsyscall calls now use proper 'go run' syntax that works with vendored dependencies
- Addresses PR microsoft#2632 CI pipeline failures

Files updated:
- computestorage/storage.go
- hcn/hcn.go
- hcsshim.go
- internal/hns/hns.go
- internal/interop/interop.go
- internal/regstate/regstate.go
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.

4 participants