cgroup: Fixes for v6.4-rc7

It's late but here are two bug fixes. Both fix problems which can be severe
 but are very confined in scope. The risk to most use cases should be
 minimal.
 
 * Fix for an old bug which triggers if a cgroup subsystem is remounted to a
   different hierarchy while someone is reading its cgroup.procs/tasks file.
   The risk is pretty low given how seldom cgroup subsystems are moved across
   hierarchies.
 
 * We moved cpus_read_lock() outside of cgroup internal locks a while ago but
   forgot to update the legacy_freezer leading to lockdep triggers. Fixed.
 -----BEGIN PGP SIGNATURE-----
 
 iIQEABYIACwWIQTfIjM1kS57o3GsC/uxYfJx3gVYGQUCZJNz6g4cdGpAa2VybmVs
 Lm9yZwAKCRCxYfJx3gVYGS9zAP9lGszI1Zgvjz+qlU0dmE96yUEuqEg7Tfwcqxr3
 Y+hHyAEArgNGnCoPfu4NAWQDZ31AgPUdL8EFqx6pY9Vq9R0oFg0=
 =uaB+
 -----END PGP SIGNATURE-----

Merge tag 'cgroup-for-6.4-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

Pull cgroup fixes from Tejun Heo:
 "It's late but here are two bug fixes. Both fix problems which can be
  severe but are very confined in scope. The risk to most use cases
  should be minimal.

   - Fix for an old bug which triggers if a cgroup subsystem is
     remounted to a different hierarchy while someone is reading its
     cgroup.procs/tasks file. The risk is pretty low given how seldom
     cgroup subsystems are moved across hierarchies.

   - We moved cpus_read_lock() outside of cgroup internal locks a while
     ago but forgot to update the legacy_freezer leading to lockdep
     triggers. Fixed"

* tag 'cgroup-for-6.4-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  cgroup: Do not corrupt task iteration when rebinding subsystem
  cgroup,freezer: hold cpu_hotplug_lock before freezer_mutex in freezer_css_{online,offline}()
This commit is contained in:
Linus Torvalds 2023-06-22 17:27:16 -07:00
commit 5950a0066f
2 changed files with 23 additions and 5 deletions

View file

@ -1798,7 +1798,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
{
struct cgroup *dcgrp = &dst_root->cgrp;
struct cgroup_subsys *ss;
int ssid, i, ret;
int ssid, ret;
u16 dfl_disable_ss_mask = 0;
lockdep_assert_held(&cgroup_mutex);
@ -1842,7 +1842,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
struct cgroup_root *src_root = ss->root;
struct cgroup *scgrp = &src_root->cgrp;
struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);
struct css_set *cset;
struct css_set *cset, *cset_pos;
struct css_task_iter *it;
WARN_ON(!css || cgroup_css(dcgrp, ss));
@ -1860,9 +1861,22 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
css->cgroup = dcgrp;
spin_lock_irq(&css_set_lock);
hash_for_each(css_set_table, i, cset, hlist)
WARN_ON(!list_empty(&dcgrp->e_csets[ss->id]));
list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id],
e_cset_node[ss->id]) {
list_move_tail(&cset->e_cset_node[ss->id],
&dcgrp->e_csets[ss->id]);
/*
* all css_sets of scgrp together in same order to dcgrp,
* patch in-flight iterators to preserve correct iteration.
* since the iterator is always advanced right away and
* finished when it->cset_pos meets it->cset_head, so only
* update it->cset_head is enough here.
*/
list_for_each_entry(it, &cset->task_iters, iters_node)
if (it->cset_head == &scgrp->e_csets[ss->id])
it->cset_head = &dcgrp->e_csets[ss->id];
}
spin_unlock_irq(&css_set_lock);
if (ss->css_rstat_flush) {

View file

@ -108,16 +108,18 @@ static int freezer_css_online(struct cgroup_subsys_state *css)
struct freezer *freezer = css_freezer(css);
struct freezer *parent = parent_freezer(freezer);
cpus_read_lock();
mutex_lock(&freezer_mutex);
freezer->state |= CGROUP_FREEZER_ONLINE;
if (parent && (parent->state & CGROUP_FREEZING)) {
freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN;
static_branch_inc(&freezer_active);
static_branch_inc_cpuslocked(&freezer_active);
}
mutex_unlock(&freezer_mutex);
cpus_read_unlock();
return 0;
}
@ -132,14 +134,16 @@ static void freezer_css_offline(struct cgroup_subsys_state *css)
{
struct freezer *freezer = css_freezer(css);
cpus_read_lock();
mutex_lock(&freezer_mutex);
if (freezer->state & CGROUP_FREEZING)
static_branch_dec(&freezer_active);
static_branch_dec_cpuslocked(&freezer_active);
freezer->state = 0;
mutex_unlock(&freezer_mutex);
cpus_read_unlock();
}
static void freezer_css_free(struct cgroup_subsys_state *css)