@@ -27,6 +27,7 @@ import (
27
27
"path/filepath"
28
28
"strconv"
29
29
"strings"
30
+ "sync"
30
31
"time"
31
32
32
33
"github.com/containerd/cgroups/v3/cgroup2/stats"
@@ -47,7 +48,12 @@ const (
47
48
defaultSlice = "system.slice"
48
49
)
49
50
50
- var canDelegate bool
51
+ var (
52
+ canDelegate bool
53
+
54
+ versionOnce sync.Once
55
+ version int
56
+ )
51
57
52
58
type Event struct {
53
59
Low uint64
@@ -876,6 +882,16 @@ func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, e
876
882
877
883
if resources .CPU != nil && resources .CPU .Max != "" {
878
884
quota , period := resources .CPU .Max .extractQuotaAndPeriod ()
885
+ if period != 0 {
886
+ // systemd only supports CPUQuotaPeriodUSec since v242
887
+ if sdVer := systemdVersion (conn ); sdVer >= 242 {
888
+ properties = append (properties , newSystemdProperty ("CPUQuotaPeriodUSec" , period ))
889
+ } else {
890
+ log .G (context .TODO ()).Debugf ("systemd v%d is too old to support CPUQuotaPeriodSec " +
891
+ " (setting will still be applied to cgroupfs)" , sdVer )
892
+ }
893
+ }
894
+
879
895
// cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
880
896
// corresponds to USEC_INFINITY in systemd
881
897
// if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
@@ -915,6 +931,41 @@ func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, e
915
931
}, nil
916
932
}
917
933
934
+ // Adapted from https://github.com/opencontainers/cgroups/blob/9657f5a18b8d60a0f39fbb34d0cb7771e28e6278/systemd/common.go#L245-L281
935
+ func systemdVersion (conn * systemdDbus.Conn ) int {
936
+ versionOnce .Do (func () {
937
+ version = - 1
938
+ verStr , err := conn .GetManagerProperty ("Version" )
939
+ if err == nil {
940
+ version , err = systemdVersionAtoi (verStr )
941
+ }
942
+
943
+ if err != nil {
944
+ log .G (context .TODO ()).WithError (err ).Error ("Unable to get systemd version" )
945
+ }
946
+ })
947
+
948
+ return version
949
+ }
950
+
951
+ func systemdVersionAtoi (str string ) (int , error ) {
952
+ // Unconditionally remove the leading prefix ("v).
953
+ str = strings .TrimLeft (str , `"v` )
954
+ // Match on the first integer we can grab.
955
+ for i := range len (str ) {
956
+ if str [i ] < '0' || str [i ] > '9' {
957
+ // First non-digit: cut the tail.
958
+ str = str [:i ]
959
+ break
960
+ }
961
+ }
962
+ ver , err := strconv .Atoi (str )
963
+ if err != nil {
964
+ return - 1 , fmt .Errorf ("can't parse version: %w" , err )
965
+ }
966
+ return ver , nil
967
+ }
968
+
918
969
func startUnit (conn * systemdDbus.Conn , group string , properties []systemdDbus.Property , ignoreExists bool ) error {
919
970
ctx := context .TODO ()
920
971
0 commit comments