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

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
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -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) {
+6 −2
Original line number Diff line number Diff line
@@ -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)