This was needed for a test case only, but we can easily copy the data
needed.
The alternatives are:
- keep things as is (and have cgroups depend on
runc/libcontainer/specconv);
- remove this test case;
- move AllowedDevices to cgroups/devices/config.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Instead, we can just do filepath.Clean("/"+path) here.
While at it, add a comment telling why this is needed and important.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The code which determines inner cgroup path from cgroup config is
identical in fs and fs2 drivers, and it is using utils.CleanPath.
In preparation to move libcontainer/cgroups to a separate repo,
we have to get rid of libcontainer/utils dependency. So,
- copy the utils.CleanPath implementation to internal/path;
- consolidate the two innerPath implementations to internal/path.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The _defaultDirPath was only used for testing, and the test case
is quite easy to adopt to defaultDirPath.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
We were using utils.ProcThreadSelf since commit 8e8b136c,
which provides two things:
1. locking the OS tread;
2. fallback to /proc/self/task/$TID when /proc/thread-self
is not available (kernel < 3.17).
Now, (1) is not needed since we only call readlink and not perform any
file data operation, and (2) is not needed here as this code is
only running when openat2 syscall is available, meaning kernel >= v5.6.
Also, check the error from readlink, so when it fails, we do not try to
enhance the error message.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.CutPrefix (available since Go 1.20) instead of
strings.HasPrefix and/or strings.TrimPrefix makes the code
a tad more straightforward.
No functional change.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
1. GetCgroupParamUint: drop strings.TrimSpace since it was already
done by GetCgroupParamString.
2. GetCgroupParamInt: use GetCgroupParamString, drop strings.TrimSpace.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
It makes sense to report an error if a key or a value is empty,
as we don't expect anything like this.
Reported-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.CutPrefix (added in Go 1.20, see [1]) results in faster and
cleaner code with less allocations (as the code only allocates memory
for the value, and does it once).
While at it, improve the function documentation.
[1]: https://github.com/golang/go/issues/42537
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.Cut (added in Go 1.18, see [1]) results in faster and
cleaner code with less allocations (as we're not using a slice).
Also, use switch in parseRdmaKV.
[1]: https://github.com/golang/go/issues/46336
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.Cut (added in Go 1.18, see [1]) results in faster and
cleaner code with less allocations (as we're not using a slice).
This code is tested by TestStatCPUPSI.
[1]: https://github.com/golang/go/issues/46336
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.Cut (added in Go 1.18, see [1]) results in faster and
cleaner code with less allocations (as we're not using a slice).
The code is tested by testCgroupResourcesUnified.
[1]: https://github.com/golang/go/issues/46336
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
For cgroup v2, we always expect /proc/$PID/cgroup contents like this:
> 0::/user.slice/user-1000.slice/user@1000.service/app.slice/vte-spawn-f71c3fb8-519d-4e2d-b13e-9252594b1e05.scope
So, it does not make sense to parse it using strings.Split, we can just
cut the prefix and return the rest.
Code tested by TestParseCgroupFromReader.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Remove extra global constants that are only used in a single place and
make it harder to read the code.
Rename nanosecondsInSecond -> nsInSec.
This code is tested by unit tests.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using strings.Cut (added in Go 1.18, see [1]) results in faster and
cleaner code with less allocations (as we're not using a slice). This
also drops the check for extra dash (we're unlikely to get it from the
kernel anyway).
While at it, rename min/max -> from/to to avoid collision with Go
min/max builtins.
This code is tested by TestCPUSetStats* tests.
[1]: https://github.com/golang/go/issues/46336
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Use the old package name as an alias to minimize the patch.
No functional change; this just eliminates a bunch of deprecation
warnings.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Currently, libcontainer/devices contains two things:
1. Device-related configuration data structures and accompanying
methods. Those are used by runc itself, mostly by libct/cgroups.
2. A few functions (HostDevices, DeviceFromPath, GetDevices).
Those are not used by runc directly, but have some external users
(cri-o, microsoft/hcsshim), and they also have a few forks
(containerd/pkg/oci, podman/pkg/util).
This commit moves (1) to a new separate package, config (under
libcontainer/cgroups/devices), adding a backward-compatible aliases
(marked as deprecated so we will be able to remove those later).
Alas it's not possible to move this to libcontainer/cgroups directly
because some IDs (Type, Rule, Permissions) are too generic, and renaming
them (to DeviceType, DeviceRule, DevicePermissions) will break backward
compatibility (mostly due to Rule being embedded into Device).
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Since v1.2.0 was released, a number of users complained that the removal
of tun/tap device access from the default device ruleset is causing a
regression in their workloads.
Additionally, it seems that some upper-level orchestration tools
(Docker Swarm, Kubernetes) makes it either impossible or cumbersome
to supply additional device rules.
While it's probably not quite right to have /dev/net/tun in a default
device list, it was there from the very beginning, and users rely on it.
Let's keep it there for the sake of backward compatibility.
This reverts commit 2ce40b6ad7.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
We have quite a few external users of libcontainer/cgroups packages,
and they all have to depend on libcontainer/configs as well.
Let's move cgroup-related configuration to libcontainer/croups.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
These:
> Error: libcontainer/cgroups/fs2/cpu.go:15:6: var-naming: func isCpuSet should be isCPUSet (revive)
> func isCpuSet(r *cgroups.Resources) bool {
> ^
> Error: libcontainer/cgroups/fs2/cpu.go:19:6: var-naming: func setCpu should be setCPU (revive)
> func setCpu(dirPath string, r *cgroups.Resources) error {
> ^
They are going to be shown after next commits because of linter-extra CI
job (which, due to major changes, now thinks it's a new code so extra
linters apply).
Fixing it beforehand.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
If we get an unexpected error here, it is probably because of a library
or kernel change that could cause our detection logic to be invalid. As
a result, these warnings should be louder so users have a chance to tell
us about them sooner (or so we might notice them before doing a release,
as happened with the 1.2.0 regression).
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
It is possible for LinkAttachProgram to return ErrNotSupported if
program attachment is not supported at all (which doesn't matter in this
case), but it seems possible that upstream will start returning
ErrNotSupported for BPF_F_REPLACE at some point so it's best to make
sure we don't cause additional regressions here.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
In v0.13.0, cilium/ebpf stopped supporting setting BPF_F_REPLACE as an
explicit flag and instead requires us to use link.Anchor to specify
where the program should be attached.
Commit 216175a9ca ("Upgrade Cilium's eBPF library version to 0.16")
did update this correctly for the actual attaching logic, but when
checking for kernel support we still passed BPF_F_REPLACE. This would
result in a generic error being returned, which our feature-support
checking logic would treat as being an error the indicates that
BPF_F_REPLACE *is* supported, resulting in a regression on pre-5.6
kernels.
It turns out that our debug logging saying that this unexpected error
was happening was being output as a result of this change, but nobody
noticed...
Fixes: 216175a9ca ("Upgrade Cilium's eBPF library version to 0.16")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
If the sub-cgroup RemovePath has failed for any reason, return the
error right away. This way, we don't have to check for err != nil
before retrying rmdir.
This is a cosmetic change and should not change any functionality.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
An issue with runc 1.2.0 was reported to buildkit, in which
runc delete returns with an error, with the log saying:
> unable to destroy container: unable to remove container's cgroup: open /sys/fs/cgroup/snschvixiy3s74w74fjantrdg: no such file or directory
Apparently, what happens is runc is running with no cgroup access
(because /sys/fs/cgroup is mounted read-only). In this case error to
create a cgroup path (in runc create/run) is ignored, but cgroup removal
(in runc delete) is not.
This is caused by commit d3d7f7d, which changes the cgroup removal
logic in RemovePath. In the current code, if the initial rmdir has
failed (in this case with EROFS), but the subsequent os.ReadDir returns
ENOENT, it is returned (instead of being ignored -- as the path does not
exist and so there is nothing to remove).
Here is the minimal fix for the issue.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This allows to do
runc update $ID --memory=-1 --memory-swap=$VAL
for cgroup v2, i.e. set memory to unlimited and swap to a specific
value.
This was not possible because ConvertMemorySwapToCgroupV2Value rejected
memory=-1 ("unlimited"). In a hindsight, it was a mistake, because if
memory limit is unlimited, we should treat memory+swap limit as just swap
limit.
Revise the unit test; add description to each case.
Fixes: c86be8a2 ("cgroupv2: fix setting MemorySwap")
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Improve readability of ConvertMemorySwapToCgroupV2Value by switching
from a bunch of if statements to a switch, and adding a comment
describing each case.
No functional change.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The userns package was moved to the moby/sys/userns module
at commit 3778ae603c.
This patch deprecates the old location, and adds it as an alias
for the moby/sys/userns package.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Initially, this was a commit to switch from strings.Fields to
strings.SplitN in getCpuUsageBreakdown, since strings.Fields
was probably slower than strings.SplitN in some old Go versions.
Afterwards, strings.Cut was also considered for potential
speed improvements.
After writing a benchmark test, we learned that:
- strings.Fields performance is now adequate;
- strings.SplitN is slower than strings.Fields;
- strings.Cut had <5% performance gain from strings.Fields;
So, remove the TODO and keep the benchmark test.
Signed-off-by: Stavros Panakakis <stavrospanakakis@gmail.com>
Shared pid namespace means `runc kill` (or `runc delete -f`) have to
kill all container processes, not just init. To do so, it needs a cgroup
to read the PIDs from.
If there is no cgroup, processes will be leaked, and so such
configuration is bad and should not be allowed. To keep backward
compatibility, though, let's merely warn about this for now.
Alas, the only way to know if cgroup access is available is by returning
an error from Manager.Apply. Amend fs cgroup managers to do so (systemd
doesn't need it, since v1 can't work with rootless, and cgroup v2 does
not have a special rootless case).
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The warnings fixed were:
libcontainer/configs/config_test.go:205:12: printf: non-constant format string in call to (*testing.common).Errorf (govet)
t.Errorf(fmt.Sprintf("Expected error to not occur but it was %+v", err))
^
libcontainer/cgroups/fs/blkio_test.go:481:13: printf: non-constant format string in call to (*testing.common).Errorf (govet)
t.Errorf(fmt.Sprintf("test case '%s' failed unexpectedly: %s", testCase.desc, err))
^
libcontainer/cgroups/fs/blkio_test.go:595:13: printf: non-constant format string in call to (*testing.common).Errorf (govet)
t.Errorf(fmt.Sprintf("test case '%s' failed unexpectedly: %s", testCase.desc, err))
^
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
There's too much logic here figuring out which CPUs to use. Runc is a
low level tool and is not supposed to be that "smart". What's worse,
this logic is executed on every exec, making it slower. Some of the
logic in (*setnsProcess).start is executed even if no annotation is set,
thus making ALL execs slow.
Also, this should be a property of a process, rather than annotation.
The plan is to rework this.
This reverts commit afc23e3397.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
It has been pointed out that some controllers can not accept multiple
lines of output at once. In particular, io.max can only set one device
at a time.
Practically, the only multi-line resource values we can get come from
unified.* -- let's write those line by line.
Add a test case.
Reported-by: Tao Shen <shentaoskyking@gmail.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
When swap is being disabled (as set to 0), or set to max, ignore
non-existent memory.swap.max cgroup file.
If swap is being set explicitly to some value, do return an error like
before.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This test panics if userns is detected (such as when run in a rootless
docker container) because SetV1 does nothing in this case.
We could fix the panic, but it doesn't make sense to run the test at
all.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The issue is the same as in commit 1b2adcf but for RT scheduler;
the fix is also the same.
Test case by ls-ggg.
Co-authored-by: ls-ggg <335814617@qq.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
If CPU burst knob is non-existent, the current implementation (added in
commit e1584831) still tries to set it again after setting the new CPU
quota, which is useless (and we have to ignore ENOENT again).
Fix this.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Commit b6967fa84c moved the functionality of managing cgroup devices
into a separate package, and decoupled libcontainer/cgroups from it.
Yet, some software (e.g. cadvisor) may need to use libcontainer package,
which imports libcontainer/cgroups/devices, thus making it impossible to
use libcontainer without bringing in cgroup/devices dependency.
In fact, we only need to manage devices in runc binary, so move the
import to main.go.
The need to import libct/cg/dev in order to manage devices is already
documented in libcontainer/cgroups, but let's
- update that documentation;
- add a similar note to libcontainer/cgroups/systemd;
- add a note to libct README.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This handles a corner case when joining a container having all
the processes running exclusively on isolated CPU cores to force
the kernel to schedule runc process on the first CPU core within the
cgroups cpuset.
The introduction of the kernel commit
46a87b3851f0d6eb05e6d83d5c5a30df0eca8f76 has affected this deterministic
scheduling behavior by distributing tasks across CPU cores within the
cgroups cpuset. Some intensive real-time application are relying on this
deterministic behavior and use the first CPU core to run a slow thread
while other CPU cores are fully used by real-time threads with SCHED_FIFO
policy. Such applications prevents runc process from joining a container
when the runc process is randomly scheduled on a CPU core owned by a
real-time thread.
Introduces isolated CPU affinity transition OCI runtime annotation
org.opencontainers.runc.exec.isolated-cpu-affinity-transition to restore
the behavior during runc exec.
Fix issue with kernel >= 6.2 not resetting CPU affinity for container processes.
Signed-off-by: Cédric Clerget <cedric.clerget@gmail.com>