@@ -167,3 +167,115 @@ function check_exec_debug() {
167167 [[ " ${output} " == * " level=debug" * ]]
168168 check_exec_debug " $output "
169169}
170+
171+ @test " runc exec --cgroup sub-cgroups [v1]" {
172+ requires root cgroups_v1 cgroupns
173+
174+ set_cgroups_path
175+ set_cgroup_mount_writable
176+ # Enable CGROUPNS (to simplify test case working with cgroup paths).
177+ update_config ' .linux.namespaces += [{"type": "cgroup"}]'
178+
179+ __runc run -d --console-socket " $CONSOLE_SOCKET " test_busybox
180+ testcontainer test_busybox running
181+
182+ # Check we can't join non-existing subcgroup.
183+ runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
184+ [ " $status " -ne 0 ]
185+ [[ " $output " == * " adding pid " * " /nonexistent/cgroup.procs: no such file " * ]]
186+
187+ # Check we can't join non-existing subcgroup (for a particular controller).
188+ runc exec --cgroup cpu:nonexistent test_busybox cat /proc/self/cgroup
189+ [ " $status " -ne 0 ]
190+ [[ " $output " == * " adding pid " * " /nonexistent/cgroup.procs: no such file " * ]]
191+
192+ # Check we can't specify non-existant controller.
193+ runc exec --cgroup whaaat:/ test_busybox true
194+ [ " $status " -ne 0 ]
195+ [[ " $output " == * " unknown controller " * ]]
196+
197+ # Check we can join top-level cgroup (implicit).
198+ runc exec test_busybox sh -euc " ! grep -v ':/$' /proc/self/cgroup"
199+ [ " $status " -eq 0 ]
200+ [ " $output " = " " ]
201+
202+ # Check we can join top-level cgroup (explicit).
203+ runc exec --cgroup / test_busybox sh -euc " ! grep -v ':/$' /proc/self/cgroup"
204+ [ " $status " -eq 0 ]
205+ [ " $output " = " " ]
206+
207+ # Create a few subcgroups.
208+ runc exec test_busybox sh -euc " mkdir -p /sys/fs/cgroup/memory/submem /sys/fs/cgroup/cpu/subcpu /sys/fs/cgroup/cpuacct/subcpu"
209+ [ " $status " -eq 0 ]
210+
211+ # Check that explicit --cgroup works.
212+ runc exec --cgroup memory:submem --cgroup cpu,cpuacct:subcpu test_busybox cat /proc/self/cgroup
213+ [ " $status " -eq 0 ]
214+ [[ " $output " == * " :memory:/submem" * ]]
215+ [[ " $output " == * " :cpu" * " :/subcpu" * ]]
216+ }
217+
218+ @test " runc exec --cgroup subcgroup [v2]" {
219+ requires root cgroups_v2
220+
221+ set_cgroups_path
222+ set_cgroup_mount_writable
223+
224+ __runc run -d --console-socket " $CONSOLE_SOCKET " test_busybox
225+ testcontainer test_busybox running
226+
227+ # Check we can't join non-existing subcgroup.
228+ runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
229+ [ " $status " -ne 0 ]
230+ [[ " $output " == * " adding pid " * " /nonexistent/cgroup.procs: no such file " * ]]
231+
232+ # Check we can join top-level cgroup (implicit).
233+ runc exec test_busybox grep ' ^0::/$' /proc/self/cgroup
234+ [ " $status " -eq 0 ]
235+
236+ # Check we can join top-level cgroup (explicit).
237+ runc exec --cgroup / test_busybox grep ' ^0::/$' /proc/self/cgroup
238+ [ " $status " -eq 0 ]
239+
240+ # Now move "init" to a subcgroup, and check it was moved.
241+ runc exec test_busybox sh -euc " mkdir /sys/fs/cgroup/foobar \
242+ && echo 1 > /sys/fs/cgroup/foobar/cgroup.procs \
243+ && grep -w foobar /proc/1/cgroup"
244+ [ " $status " -eq 0 ]
245+
246+ # The following part is taken from
247+ # @test "runc exec (cgroup v2 + init process in non-root cgroup) succeeds"
248+
249+ # The init process is now in "/foo", but an exec process can still
250+ # join "/" because we haven't enabled any domain controller yet.
251+ runc exec test_busybox grep ' ^0::/$' /proc/self/cgroup
252+ [ " $status " -eq 0 ]
253+
254+ # Turn on a domain controller (memory).
255+ runc exec test_busybox sh -euc ' echo $$ > /sys/fs/cgroup/foobar/cgroup.procs; echo +memory > /sys/fs/cgroup/cgroup.subtree_control'
256+ [ " $status " -eq 0 ]
257+
258+ # An exec process can no longer join "/" after turning on a domain
259+ # controller. Check that cgroup v2 fallback to init cgroup works.
260+ runc exec test_busybox sh -euc " cat /proc/self/cgroup && grep '^0::/foobar$' /proc/self/cgroup"
261+ [ " $status " -eq 0 ]
262+
263+ # Check that --cgroup / disables the init cgroup fallback.
264+ runc exec --cgroup / test_busybox true
265+ [ " $status " -ne 0 ]
266+ [[ " $output " == * " adding pid " * " to cgroups" * " /cgroup.procs: device or resource busy" * ]]
267+
268+ # Check that explicit --cgroup foobar works.
269+ runc exec --cgroup foobar test_busybox grep ' ^0::/foobar$' /proc/self/cgroup
270+ [ " $status " -eq 0 ]
271+
272+ # Check all processes is in foobar (this check is redundant).
273+ runc exec --cgroup foobar test_busybox sh -euc ' ! grep -vwH foobar /proc/*/cgroup'
274+ [ " $status " -eq 0 ]
275+
276+ # Add a second subcgroup, check we're in it.
277+ runc exec --cgroup foobar test_busybox mkdir /sys/fs/cgroup/second
278+ [ " $status " -eq 0 ]
279+ runc exec --cgroup second test_busybox grep -w second /proc/self/cgroup
280+ [ " $status " -eq 0 ]
281+ }
0 commit comments