mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-03 04:16:42 +00:00
75 lines
2.2 KiB
Go
75 lines
2.2 KiB
Go
package systemd
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
dbus "github.com/godbus/dbus/v5"
|
|
|
|
"github.com/opencontainers/cgroups"
|
|
)
|
|
|
|
// freezeBeforeSet answers whether there is a need to freeze the cgroup before
|
|
// applying its systemd unit properties, and thaw after, while avoiding
|
|
// unnecessary freezer state changes.
|
|
//
|
|
// The reason why we have to freeze is that systemd's application of device
|
|
// rules is done disruptively, resulting in spurious errors to common devices
|
|
// (unlike our fs driver, they will happily write deny-all rules to running
|
|
// containers). So we have to freeze the container to avoid the container get
|
|
// an occasional "permission denied" error.
|
|
func (m *LegacyManager) freezeBeforeSet(unitName string, r *cgroups.Resources) (needsFreeze, needsThaw bool, err error) {
|
|
// Special case for SkipDevices, as used by Kubernetes to create pod
|
|
// cgroups with allow-all device policy).
|
|
if r.SkipDevices {
|
|
if r.SkipFreezeOnSet {
|
|
// Both needsFreeze and needsThaw are false.
|
|
return
|
|
}
|
|
|
|
// No need to freeze if SkipDevices is set, and either
|
|
// (1) systemd unit does not (yet) exist, or
|
|
// (2) it has DevicePolicy=auto and empty DeviceAllow list.
|
|
//
|
|
// Interestingly, (1) and (2) are the same here because
|
|
// a non-existent unit returns default properties,
|
|
// and settings in (2) are the defaults.
|
|
//
|
|
// Do not return errors from getUnitTypeProperty, as they alone
|
|
// should not prevent Set from working.
|
|
|
|
unitType := getUnitType(unitName)
|
|
|
|
devPolicy, e := getUnitTypeProperty(m.dbus, unitName, unitType, "DevicePolicy")
|
|
if e == nil && devPolicy.Value == dbus.MakeVariant("auto") {
|
|
devAllow, e := getUnitTypeProperty(m.dbus, unitName, unitType, "DeviceAllow")
|
|
if e == nil {
|
|
if rv := reflect.ValueOf(devAllow.Value.Value()); rv.Kind() == reflect.Slice && rv.Len() == 0 {
|
|
needsFreeze = false
|
|
needsThaw = false
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
needsFreeze = true
|
|
needsThaw = true
|
|
|
|
// Check the current freezer state.
|
|
freezerState, err := m.GetFreezerState()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if freezerState == cgroups.Frozen {
|
|
// Already frozen, and should stay frozen.
|
|
needsFreeze = false
|
|
needsThaw = false
|
|
}
|
|
|
|
if r.Freezer == cgroups.Frozen {
|
|
// Will be frozen anyway -- no need to thaw.
|
|
needsThaw = false
|
|
}
|
|
return
|
|
}
|