Commit 5950a006 authored by Linus Torvalds's avatar Linus Torvalds

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}()
parents dad9774d 6f363f5a
...@@ -1798,7 +1798,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) ...@@ -1798,7 +1798,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
{ {
struct cgroup *dcgrp = &dst_root->cgrp; struct cgroup *dcgrp = &dst_root->cgrp;
struct cgroup_subsys *ss; struct cgroup_subsys *ss;
int ssid, i, ret; int ssid, ret;
u16 dfl_disable_ss_mask = 0; u16 dfl_disable_ss_mask = 0;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
...@@ -1842,7 +1842,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) ...@@ -1842,7 +1842,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
struct cgroup_root *src_root = ss->root; struct cgroup_root *src_root = ss->root;
struct cgroup *scgrp = &src_root->cgrp; struct cgroup *scgrp = &src_root->cgrp;
struct cgroup_subsys_state *css = cgroup_css(scgrp, ss); 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)); WARN_ON(!css || cgroup_css(dcgrp, ss));
...@@ -1860,9 +1861,22 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) ...@@ -1860,9 +1861,22 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
css->cgroup = dcgrp; css->cgroup = dcgrp;
spin_lock_irq(&css_set_lock); 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], list_move_tail(&cset->e_cset_node[ss->id],
&dcgrp->e_csets[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); spin_unlock_irq(&css_set_lock);
if (ss->css_rstat_flush) { if (ss->css_rstat_flush) {
......
...@@ -108,16 +108,18 @@ static int freezer_css_online(struct cgroup_subsys_state *css) ...@@ -108,16 +108,18 @@ static int freezer_css_online(struct cgroup_subsys_state *css)
struct freezer *freezer = css_freezer(css); struct freezer *freezer = css_freezer(css);
struct freezer *parent = parent_freezer(freezer); struct freezer *parent = parent_freezer(freezer);
cpus_read_lock();
mutex_lock(&freezer_mutex); mutex_lock(&freezer_mutex);
freezer->state |= CGROUP_FREEZER_ONLINE; freezer->state |= CGROUP_FREEZER_ONLINE;
if (parent && (parent->state & CGROUP_FREEZING)) { if (parent && (parent->state & CGROUP_FREEZING)) {
freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN; freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN;
static_branch_inc(&freezer_active); static_branch_inc_cpuslocked(&freezer_active);
} }
mutex_unlock(&freezer_mutex); mutex_unlock(&freezer_mutex);
cpus_read_unlock();
return 0; return 0;
} }
...@@ -132,14 +134,16 @@ static void freezer_css_offline(struct cgroup_subsys_state *css) ...@@ -132,14 +134,16 @@ static void freezer_css_offline(struct cgroup_subsys_state *css)
{ {
struct freezer *freezer = css_freezer(css); struct freezer *freezer = css_freezer(css);
cpus_read_lock();
mutex_lock(&freezer_mutex); mutex_lock(&freezer_mutex);
if (freezer->state & CGROUP_FREEZING) if (freezer->state & CGROUP_FREEZING)
static_branch_dec(&freezer_active); static_branch_dec_cpuslocked(&freezer_active);
freezer->state = 0; freezer->state = 0;
mutex_unlock(&freezer_mutex); mutex_unlock(&freezer_mutex);
cpus_read_unlock();
} }
static void freezer_css_free(struct cgroup_subsys_state *css) static void freezer_css_free(struct cgroup_subsys_state *css)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment