Commit 385a635c authored by Michal Koutný's avatar Michal Koutný Committed by Tejun Heo
Browse files

cgroup/pids: Make event counters hierarchical



The pids.events file should honor the hierarchy, so make the events
propagate from their origin up to the root on the unified hierarchy. The
legacy behavior remains non-hierarchical.

Signed-off-by: default avatarMichal Koutný <mkoutny@suse.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent 73e75e6f
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -240,8 +240,11 @@ cgroup v2 currently supports the following mount options.
          v2 is remounted later on).

  pids_localevents
        Represent fork failures inside cgroup's pids.events:max (v1 behavior),
        not its limit being hit (v2 behavior).
        The option restores v1-like behavior of pids.events:max, that is only
        local (inside cgroup proper) fork failures are counted. Without this
        option pids.events.max represents any pids.max enforcemnt across
        cgroup's subtree.



Organizing Processes and Threads
@@ -2214,7 +2217,7 @@ PID Interface Files
	modified event. The following entries are defined.

	  max
		The number of times the cgroup's number of processes hit the
		The number of times the cgroup's total number of processes hit the pids.max
		limit (see also pids_localevents).

Organisational operations are not blocked by cgroup policies, so it is
+30 −16
Original line number Diff line number Diff line
@@ -238,6 +238,34 @@ static void pids_cancel_attach(struct cgroup_taskset *tset)
	}
}

static void pids_event(struct pids_cgroup *pids_forking,
		       struct pids_cgroup *pids_over_limit)
{
	struct pids_cgroup *p = pids_forking;
	bool limit = false;

	for (; parent_pids(p); p = parent_pids(p)) {
		/* Only log the first time limit is hit. */
		if (atomic64_inc_return(&p->events[PIDCG_FORKFAIL]) == 1) {
			pr_info("cgroup: fork rejected by pids controller in ");
			pr_cont_cgroup_path(p->css.cgroup);
			pr_cont("\n");
		}
		cgroup_file_notify(&p->events_file);

		if (!cgroup_subsys_on_dfl(pids_cgrp_subsys) ||
		    cgrp_dfl_root.flags & CGRP_ROOT_PIDS_LOCAL_EVENTS)
			break;

		if (p == pids_over_limit)
			limit = true;
		if (limit)
			atomic64_inc(&p->events[PIDCG_MAX]);

		cgroup_file_notify(&p->events_file);
	}
}

/*
 * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
 * on cgroup_threadgroup_change_begin() held by the copy_process().
@@ -254,23 +282,9 @@ static int pids_can_fork(struct task_struct *task, struct css_set *cset)
		css = task_css_check(current, pids_cgrp_id, true);
	pids = css_pids(css);
	err = pids_try_charge(pids, 1, &pids_over_limit);
	if (err) {
		/* compatibility on v1 where events were notified in leaves. */
		if (!cgroup_subsys_on_dfl(pids_cgrp_subsys))
			pids_over_limit = pids;

		/* Only log the first time limit is hit. */
		if (atomic64_inc_return(&pids->events[PIDCG_FORKFAIL]) == 1) {
			pr_info("cgroup: fork rejected by pids controller in ");
			pr_cont_cgroup_path(pids->css.cgroup);
			pr_cont("\n");
		}
		atomic64_inc(&pids_over_limit->events[PIDCG_MAX]);
	if (err)
		pids_event(pids, pids_over_limit);

		cgroup_file_notify(&pids->events_file);
		if (pids_over_limit != pids)
			cgroup_file_notify(&pids_over_limit->events_file);
	}
	return err;
}