]> git.ipfire.org Git - people/arne_f/kernel.git/commit
cgroup/pids: turn cgroup_subsys->free() into cgroup_subsys->release() to fix the...
authorOleg Nesterov <oleg@redhat.com>
Mon, 28 Jan 2019 16:00:13 +0000 (17:00 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Apr 2019 20:31:37 +0000 (22:31 +0200)
commitf3b3b5434752a86b5dd848081a648f7412e0560b
tree533bcff4501c1c24035b9cae471b250a61cbe817
parent46b2c037b245f819841d03e323092105f5dd59f2
cgroup/pids: turn cgroup_subsys->free() into cgroup_subsys->release() to fix the accounting

[ Upstream commit 51bee5abeab2058ea5813c5615d6197a23dbf041 ]

The only user of cgroup_subsys->free() callback is pids_cgrp_subsys which
needs pids_free() to uncharge the pid.

However, ->free() is called from __put_task_struct()->cgroup_free() and this
is too late. Even the trivial program which does

for (;;) {
int pid = fork();
assert(pid >= 0);
if (pid)
wait(NULL);
else
exit(0);
}

can run out of limits because release_task()->call_rcu(delayed_put_task_struct)
implies an RCU gp after the task/pid goes away and before the final put().

Test-case:

mkdir -p /tmp/CG
mount -t cgroup2 none /tmp/CG
echo '+pids' > /tmp/CG/cgroup.subtree_control

mkdir /tmp/CG/PID
echo 2 > /tmp/CG/PID/pids.max

perl -e 'while ($p = fork) { wait; } $p // die "fork failed: $!\n"' &
echo $! > /tmp/CG/PID/cgroup.procs

Without this patch the forking process fails soon after migration.

Rename cgroup_subsys->free() to cgroup_subsys->release() and move the callsite
into the new helper, cgroup_release(), called by release_task() which actually
frees the pid(s).

Reported-by: Herton R. Krzesinski <hkrzesin@redhat.com>
Reported-by: Jan Stancek <jstancek@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/cgroup-defs.h
include/linux/cgroup.h
kernel/cgroup/cgroup.c
kernel/cgroup/pids.c
kernel/exit.c