@@ -27,6 +27,8 @@ import (
2727 "sort"
2828 "strconv"
2929 "strings"
30+ "sync"
31+ "syscall"
3032
3133 "github.com/containerd/containerd/containers"
3234 "github.com/containerd/containerd/log"
@@ -36,6 +38,7 @@ import (
3638 runtimespec "github.com/opencontainers/runtime-spec/specs-go"
3739 "github.com/opencontainers/selinux/go-selinux/label"
3840 "github.com/pkg/errors"
41+ "github.com/sirupsen/logrus"
3942 "golang.org/x/sys/unix"
4043 runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
4144
@@ -405,7 +408,7 @@ func WithSelinuxLabels(process, mount string) oci.SpecOpts {
405408}
406409
407410// WithResources sets the provided resource restrictions
408- func WithResources (resources * runtime.LinuxContainerResources ) oci.SpecOpts {
411+ func WithResources (resources * runtime.LinuxContainerResources , tolerateMissingHugePagesCgroupController bool ) oci.SpecOpts {
409412 return func (ctx context.Context , client oci.Client , c * containers.Container , s * runtimespec.Spec ) (err error ) {
410413 if resources == nil {
411414 return nil
@@ -448,16 +451,93 @@ func WithResources(resources *runtime.LinuxContainerResources) oci.SpecOpts {
448451 if limit != 0 {
449452 s .Linux .Resources .Memory .Limit = & limit
450453 }
451- for _ , limit := range hugepages {
452- s .Linux .Resources .HugepageLimits = append (s .Linux .Resources .HugepageLimits , runtimespec.LinuxHugepageLimit {
453- Pagesize : limit .PageSize ,
454- Limit : limit .Limit ,
455- })
454+ if isHugePagesControllerPresent () {
455+ for _ , limit := range hugepages {
456+ s .Linux .Resources .HugepageLimits = append (s .Linux .Resources .HugepageLimits , runtimespec.LinuxHugepageLimit {
457+ Pagesize : limit .PageSize ,
458+ Limit : limit .Limit ,
459+ })
460+ }
461+ } else {
462+ if ! tolerateMissingHugePagesCgroupController {
463+ return errors .Errorf ("huge pages limits are specified but hugetlb cgroup controller is missing. " +
464+ "Please set tolerate_missing_hugepages_controller to `true` to ignore this error" )
465+ }
466+ logrus .Warn ("hugetlb cgroup controller is absent. skipping huge pages limits" )
456467 }
457468 return nil
458469 }
459470}
460471
472+ var (
473+ supportsHugetlbOnce sync.Once
474+ supportsHugetlb bool
475+ )
476+
477+ func isHugePagesControllerPresent () bool {
478+ supportsHugetlbOnce .Do (func () {
479+ supportsHugetlb = false
480+ if IsCgroup2UnifiedMode () {
481+ supportsHugetlb , _ = cgroupv2HasHugetlb ()
482+ } else {
483+ supportsHugetlb , _ = cgroupv1HasHugetlb ()
484+ }
485+ })
486+ return supportsHugetlb
487+ }
488+
489+ var (
490+ _cgroupv1HasHugetlbOnce sync.Once
491+ _cgroupv1HasHugetlb bool
492+ _cgroupv1HasHugetlbErr error
493+ _cgroupv2HasHugetlbOnce sync.Once
494+ _cgroupv2HasHugetlb bool
495+ _cgroupv2HasHugetlbErr error
496+ isUnifiedOnce sync.Once
497+ isUnified bool
498+ )
499+
500+ // cgroupv1HasHugetlb returns whether the hugetlb controller is present on
501+ // cgroup v1.
502+ func cgroupv1HasHugetlb () (bool , error ) {
503+ _cgroupv1HasHugetlbOnce .Do (func () {
504+ if _ , err := ioutil .ReadDir ("/sys/fs/cgroup/hugetlb" ); err != nil {
505+ _cgroupv1HasHugetlbErr = errors .Wrap (err , "readdir /sys/fs/cgroup/hugetlb" )
506+ _cgroupv1HasHugetlb = false
507+ } else {
508+ _cgroupv1HasHugetlbErr = nil
509+ _cgroupv1HasHugetlb = true
510+ }
511+ })
512+ return _cgroupv1HasHugetlb , _cgroupv1HasHugetlbErr
513+ }
514+
515+ // cgroupv2HasHugetlb returns whether the hugetlb controller is present on
516+ // cgroup v2.
517+ func cgroupv2HasHugetlb () (bool , error ) {
518+ _cgroupv2HasHugetlbOnce .Do (func () {
519+ controllers , err := ioutil .ReadFile ("/sys/fs/cgroup/cgroup.controllers" )
520+ if err != nil {
521+ _cgroupv2HasHugetlbErr = errors .Wrap (err , "read /sys/fs/cgroup/cgroup.controllers" )
522+ return
523+ }
524+ _cgroupv2HasHugetlb = strings .Contains (string (controllers ), "hugetlb" )
525+ })
526+ return _cgroupv2HasHugetlb , _cgroupv2HasHugetlbErr
527+ }
528+
529+ // IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode.
530+ func IsCgroup2UnifiedMode () bool {
531+ isUnifiedOnce .Do (func () {
532+ var st syscall.Statfs_t
533+ if err := syscall .Statfs ("/sys/fs/cgroup" , & st ); err != nil {
534+ panic ("cannot statfs cgroup root" )
535+ }
536+ isUnified = st .Type == unix .CGROUP2_SUPER_MAGIC
537+ })
538+ return isUnified
539+ }
540+
461541// WithOOMScoreAdj sets the oom score
462542func WithOOMScoreAdj (config * runtime.ContainerConfig , restrict bool ) oci.SpecOpts {
463543 return func (ctx context.Context , client oci.Client , c * containers.Container , s * runtimespec.Spec ) error {
0 commit comments