cgroup: don't hold css_set_rwsem across css task iteration
authorTejun Heo <tj@kernel.org>
Thu, 15 Oct 2015 20:41:52 +0000 (16:41 -0400)
committerTejun Heo <tj@kernel.org>
Thu, 15 Oct 2015 20:41:52 +0000 (16:41 -0400)
commited27b9f7a17ddfbc007e16d4d11f33dff4fc2de7
tree4b9afcef40ee73ffae9999777c66c7b14febbb84
parentecb9d535df967b3ca565535e14456f612373bf5e
cgroup: don't hold css_set_rwsem across css task iteration

css_sets are synchronized through css_set_rwsem but the locking scheme
is kinda bizarre.  The hot paths - fork and exit - have to write lock
the rwsem making the rw part pointless; furthermore, many readers
already hold cgroup_mutex.

One of the readers is css task iteration.  It read locks the rwsem
over the entire duration of iteration.  This leads to silly locking
behavior.  When cpuset tries to migrate processes of a cgroup to a
different NUMA node, css_set_rwsem is held across the entire migration
attempt which can take a long time locking out forking, exiting and
other cgroup operations.

This patch updates css task iteration so that it locks css_set_rwsem
only while the iterator is being advanced.  css task iteration
involves two levels - css_set and task iteration.  As css_sets in use
are practically immutable, simply pinning the current one is enough
for resuming iteration afterwards.  Task iteration is tricky as tasks
may leave their css_set while iteration is in progress.  This is
solved by keeping track of active iterators and advancing them if
their next task leaves its css_set.

v2: put_task_struct() in css_task_iter_next() moved outside
    css_set_rwsem.  A later patch will add cgroup operations to
    task_struct free path which may grab the same lock and this avoids
    deadlock possibilities.

    css_set_move_task() updated to use list_for_each_entry_safe() when
    walking task_iters and advancing them.  This is necessary as
    advancing an iter may remove it from the list.

Signed-off-by: Tejun Heo <tj@kernel.org>
include/linux/cgroup-defs.h
include/linux/cgroup.h
kernel/cgroup.c