Commit a312a8cc authored by Linus Torvalds's avatar Linus Torvalds

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

Pull cgroup updates from Tejun Heo:
 "Nothing too interesting:

   - Add CONFIG_DEBUG_GROUP_REF which makes cgroup refcnt operations
     kprobable

   - A couple cpuset optimizations

   - Other misc changes including doc and test updates"

* tag 'cgroup-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  cgroup: remove rcu_read_lock()/rcu_read_unlock() in critical section of spin_lock_irq()
  cgroup/cpuset: Improve cpuset_css_alloc() description
  kselftest/cgroup: Add cleanup() to test_cpuset_prs.sh
  cgroup/cpuset: Optimize cpuset_attach() on v2
  cgroup/cpuset: Skip spread flags update on v2
  kselftest/cgroup: Fix gathering number of CPUs
  cgroup: cgroup refcnt functions should be exported when CONFIG_DEBUG_CGROUP_REF
  cgroup: Implement DEBUG_CGROUP_REF
parents bf57ae21 674b745e
...@@ -310,71 +310,24 @@ void css_task_iter_end(struct css_task_iter *it); ...@@ -310,71 +310,24 @@ void css_task_iter_end(struct css_task_iter *it);
* Inline functions. * Inline functions.
*/ */
#ifdef CONFIG_DEBUG_CGROUP_REF
void css_get(struct cgroup_subsys_state *css);
void css_get_many(struct cgroup_subsys_state *css, unsigned int n);
bool css_tryget(struct cgroup_subsys_state *css);
bool css_tryget_online(struct cgroup_subsys_state *css);
void css_put(struct cgroup_subsys_state *css);
void css_put_many(struct cgroup_subsys_state *css, unsigned int n);
#else
#define CGROUP_REF_FN_ATTRS static inline
#define CGROUP_REF_EXPORT(fn)
#include <linux/cgroup_refcnt.h>
#endif
static inline u64 cgroup_id(const struct cgroup *cgrp) static inline u64 cgroup_id(const struct cgroup *cgrp)
{ {
return cgrp->kn->id; return cgrp->kn->id;
} }
/**
* css_get - obtain a reference on the specified css
* @css: target css
*
* The caller must already have a reference.
*/
static inline void css_get(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_get(&css->refcnt);
}
/**
* css_get_many - obtain references on the specified css
* @css: target css
* @n: number of references to get
*
* The caller must already have a reference.
*/
static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_get_many(&css->refcnt, n);
}
/**
* css_tryget - try to obtain a reference on the specified css
* @css: target css
*
* Obtain a reference on @css unless it already has reached zero and is
* being released. This function doesn't care whether @css is on or
* offline. The caller naturally needs to ensure that @css is accessible
* but doesn't have to be holding a reference on it - IOW, RCU protected
* access is good enough for this function. Returns %true if a reference
* count was successfully obtained; %false otherwise.
*/
static inline bool css_tryget(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
return percpu_ref_tryget(&css->refcnt);
return true;
}
/**
* css_tryget_online - try to obtain a reference on the specified css if online
* @css: target css
*
* Obtain a reference on @css if it's online. The caller naturally needs
* to ensure that @css is accessible but doesn't have to be holding a
* reference on it - IOW, RCU protected access is good enough for this
* function. Returns %true if a reference count was successfully obtained;
* %false otherwise.
*/
static inline bool css_tryget_online(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
return percpu_ref_tryget_live(&css->refcnt);
return true;
}
/** /**
* css_is_dying - test whether the specified css is dying * css_is_dying - test whether the specified css is dying
* @css: target css * @css: target css
...@@ -395,31 +348,6 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css) ...@@ -395,31 +348,6 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css)
return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt); return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
} }
/**
* css_put - put a css reference
* @css: target css
*
* Put a reference obtained via css_get() and css_tryget_online().
*/
static inline void css_put(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_put(&css->refcnt);
}
/**
* css_put_many - put css references
* @css: target css
* @n: number of references to put
*
* Put references obtained via css_get() and css_tryget_online().
*/
static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_put_many(&css->refcnt, n);
}
static inline void cgroup_get(struct cgroup *cgrp) static inline void cgroup_get(struct cgroup *cgrp)
{ {
css_get(&cgrp->self); css_get(&cgrp->self);
......
/**
* css_get - obtain a reference on the specified css
* @css: target css
*
* The caller must already have a reference.
*/
CGROUP_REF_FN_ATTRS
void css_get(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_get(&css->refcnt);
}
CGROUP_REF_EXPORT(css_get)
/**
* css_get_many - obtain references on the specified css
* @css: target css
* @n: number of references to get
*
* The caller must already have a reference.
*/
CGROUP_REF_FN_ATTRS
void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_get_many(&css->refcnt, n);
}
CGROUP_REF_EXPORT(css_get_many)
/**
* css_tryget - try to obtain a reference on the specified css
* @css: target css
*
* Obtain a reference on @css unless it already has reached zero and is
* being released. This function doesn't care whether @css is on or
* offline. The caller naturally needs to ensure that @css is accessible
* but doesn't have to be holding a reference on it - IOW, RCU protected
* access is good enough for this function. Returns %true if a reference
* count was successfully obtained; %false otherwise.
*/
CGROUP_REF_FN_ATTRS
bool css_tryget(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
return percpu_ref_tryget(&css->refcnt);
return true;
}
CGROUP_REF_EXPORT(css_tryget)
/**
* css_tryget_online - try to obtain a reference on the specified css if online
* @css: target css
*
* Obtain a reference on @css if it's online. The caller naturally needs
* to ensure that @css is accessible but doesn't have to be holding a
* reference on it - IOW, RCU protected access is good enough for this
* function. Returns %true if a reference count was successfully obtained;
* %false otherwise.
*/
CGROUP_REF_FN_ATTRS
bool css_tryget_online(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
return percpu_ref_tryget_live(&css->refcnt);
return true;
}
CGROUP_REF_EXPORT(css_tryget_online)
/**
* css_put - put a css reference
* @css: target css
*
* Put a reference obtained via css_get() and css_tryget_online().
*/
CGROUP_REF_FN_ATTRS
void css_put(struct cgroup_subsys_state *css)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_put(&css->refcnt);
}
CGROUP_REF_EXPORT(css_put)
/**
* css_put_many - put css references
* @css: target css
* @n: number of references to put
*
* Put references obtained via css_get() and css_tryget_online().
*/
CGROUP_REF_FN_ATTRS
void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
{
if (!(css->flags & CSS_NO_REF))
percpu_ref_put_many(&css->refcnt, n);
}
CGROUP_REF_EXPORT(css_put_many)
...@@ -248,6 +248,12 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css, ...@@ -248,6 +248,12 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css,
struct cgroup *cgrp, struct cftype cfts[], struct cgroup *cgrp, struct cftype cfts[],
bool is_add); bool is_add);
#ifdef CONFIG_DEBUG_CGROUP_REF
#define CGROUP_REF_FN_ATTRS noinline
#define CGROUP_REF_EXPORT(fn) EXPORT_SYMBOL_GPL(fn);
#include <linux/cgroup_refcnt.h>
#endif
/** /**
* cgroup_ssid_enabled - cgroup subsys enabled test by subsys ID * cgroup_ssid_enabled - cgroup subsys enabled test by subsys ID
* @ssid: subsys ID of interest * @ssid: subsys ID of interest
...@@ -2860,14 +2866,12 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup, ...@@ -2860,14 +2866,12 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup,
* take an rcu_read_lock. * take an rcu_read_lock.
*/ */
spin_lock_irq(&css_set_lock); spin_lock_irq(&css_set_lock);
rcu_read_lock();
task = leader; task = leader;
do { do {
cgroup_migrate_add_task(task, mgctx); cgroup_migrate_add_task(task, mgctx);
if (!threadgroup) if (!threadgroup)
break; break;
} while_each_thread(leader, task); } while_each_thread(leader, task);
rcu_read_unlock();
spin_unlock_irq(&css_set_lock); spin_unlock_irq(&css_set_lock);
return cgroup_migrate_execute(mgctx); return cgroup_migrate_execute(mgctx);
......
...@@ -550,11 +550,15 @@ static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask) ...@@ -550,11 +550,15 @@ static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask)
/* /*
* update task's spread flag if cpuset's page/slab spread flag is set * update task's spread flag if cpuset's page/slab spread flag is set
* *
* Call with callback_lock or cpuset_rwsem held. * Call with callback_lock or cpuset_rwsem held. The check can be skipped
* if on default hierarchy.
*/ */
static void cpuset_update_task_spread_flag(struct cpuset *cs, static void cpuset_update_task_spread_flags(struct cpuset *cs,
struct task_struct *tsk) struct task_struct *tsk)
{ {
if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys))
return;
if (is_spread_page(cs)) if (is_spread_page(cs))
task_set_spread_page(tsk); task_set_spread_page(tsk);
else else
...@@ -2153,7 +2157,7 @@ static void update_tasks_flags(struct cpuset *cs) ...@@ -2153,7 +2157,7 @@ static void update_tasks_flags(struct cpuset *cs)
css_task_iter_start(&cs->css, 0, &it); css_task_iter_start(&cs->css, 0, &it);
while ((task = css_task_iter_next(&it))) while ((task = css_task_iter_next(&it)))
cpuset_update_task_spread_flag(cs, task); cpuset_update_task_spread_flags(cs, task);
css_task_iter_end(&it); css_task_iter_end(&it);
} }
...@@ -2509,12 +2513,28 @@ static void cpuset_attach(struct cgroup_taskset *tset) ...@@ -2509,12 +2513,28 @@ static void cpuset_attach(struct cgroup_taskset *tset)
struct cgroup_subsys_state *css; struct cgroup_subsys_state *css;
struct cpuset *cs; struct cpuset *cs;
struct cpuset *oldcs = cpuset_attach_old_cs; struct cpuset *oldcs = cpuset_attach_old_cs;
bool cpus_updated, mems_updated;
cgroup_taskset_first(tset, &css); cgroup_taskset_first(tset, &css);
cs = css_cs(css); cs = css_cs(css);
lockdep_assert_cpus_held(); /* see cgroup_attach_lock() */ lockdep_assert_cpus_held(); /* see cgroup_attach_lock() */
percpu_down_write(&cpuset_rwsem); percpu_down_write(&cpuset_rwsem);
cpus_updated = !cpumask_equal(cs->effective_cpus,
oldcs->effective_cpus);
mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
/*
* In the default hierarchy, enabling cpuset in the child cgroups
* will trigger a number of cpuset_attach() calls with no change
* in effective cpus and mems. In that case, we can optimize out
* by skipping the task iteration and update.
*/
if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
!cpus_updated && !mems_updated) {
cpuset_attach_nodemask_to = cs->effective_mems;
goto out;
}
guarantee_online_mems(cs, &cpuset_attach_nodemask_to); guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
...@@ -2530,14 +2550,19 @@ static void cpuset_attach(struct cgroup_taskset *tset) ...@@ -2530,14 +2550,19 @@ static void cpuset_attach(struct cgroup_taskset *tset)
WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach)); WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach));
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to); cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
cpuset_update_task_spread_flag(cs, task); cpuset_update_task_spread_flags(cs, task);
} }
/* /*
* Change mm for all threadgroup leaders. This is expensive and may * Change mm for all threadgroup leaders. This is expensive and may
* sleep and should be moved outside migration path proper. * sleep and should be moved outside migration path proper. Skip it
* if there is no change in effective_mems and CS_MEMORY_MIGRATE is
* not set.
*/ */
cpuset_attach_nodemask_to = cs->effective_mems; cpuset_attach_nodemask_to = cs->effective_mems;
if (!is_memory_migrate(cs) && !mems_updated)
goto out;
cgroup_taskset_for_each_leader(leader, css, tset) { cgroup_taskset_for_each_leader(leader, css, tset) {
struct mm_struct *mm = get_task_mm(leader); struct mm_struct *mm = get_task_mm(leader);
...@@ -2560,6 +2585,7 @@ static void cpuset_attach(struct cgroup_taskset *tset) ...@@ -2560,6 +2585,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
} }
} }
out:
cs->old_mems_allowed = cpuset_attach_nodemask_to; cs->old_mems_allowed = cpuset_attach_nodemask_to;
cs->attach_in_progress--; cs->attach_in_progress--;
...@@ -3046,11 +3072,15 @@ static struct cftype dfl_files[] = { ...@@ -3046,11 +3072,15 @@ static struct cftype dfl_files[] = {
}; };
/* /**
* cpuset_css_alloc - allocate a cpuset css * cpuset_css_alloc - Allocate a cpuset css
* cgrp: control group that the new cpuset will be part of * @parent_css: Parent css of the control group that the new cpuset will be
* part of
* Return: cpuset css on success, -ENOMEM on failure.
*
* Allocate and initialize a new cpuset css, for non-NULL @parent_css, return
* top cpuset css otherwise.
*/ */
static struct cgroup_subsys_state * static struct cgroup_subsys_state *
cpuset_css_alloc(struct cgroup_subsys_state *parent_css) cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
{ {
......
...@@ -1717,6 +1717,16 @@ config LATENCYTOP ...@@ -1717,6 +1717,16 @@ config LATENCYTOP
Enable this option if you want to use the LatencyTOP tool Enable this option if you want to use the LatencyTOP tool
to find out which userspace is blocking on what kernel operations. to find out which userspace is blocking on what kernel operations.
config DEBUG_CGROUP_REF
bool "Disable inlining of cgroup css reference count functions"
depends on DEBUG_KERNEL
depends on CGROUPS
depends on KPROBES
default n
help
Force cgroup css reference count functions to not be inlined so
that they can be kprobed for debugging.
source "kernel/trace/Kconfig" source "kernel/trace/Kconfig"
config PROVIDE_OHCI1394_DMA_INIT config PROVIDE_OHCI1394_DMA_INIT
......
...@@ -16,7 +16,12 @@ skip_test() { ...@@ -16,7 +16,12 @@ skip_test() {
[[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!" [[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!"
# Set sched verbose flag, if available # Set sched verbose flag, if available
[[ -d /sys/kernel/debug/sched ]] && echo Y > /sys/kernel/debug/sched/verbose if [[ -d /sys/kernel/debug/sched ]]
then
# Used to restore the original setting during cleanup
SCHED_DEBUG=$(cat /sys/kernel/debug/sched/verbose)
echo Y > /sys/kernel/debug/sched/verbose
fi
# Get wait_inotify location # Get wait_inotify location
WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify
...@@ -25,7 +30,7 @@ WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify ...@@ -25,7 +30,7 @@ WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify
CGROUP2=$(mount -t cgroup2 | head -1 | awk -e '{print $3}') CGROUP2=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
[[ -n "$CGROUP2" ]] || skip_test "Cgroup v2 mount point not found!" [[ -n "$CGROUP2" ]] || skip_test "Cgroup v2 mount point not found!"
CPUS=$(lscpu | grep "^CPU(s)" | sed -e "s/.*:[[:space:]]*//") CPUS=$(lscpu | grep "^CPU(s):" | sed -e "s/.*:[[:space:]]*//")
[[ $CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!" [[ $CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!"
# Set verbose flag and delay factor # Set verbose flag and delay factor
...@@ -54,6 +59,15 @@ echo +cpuset > cgroup.subtree_control ...@@ -54,6 +59,15 @@ echo +cpuset > cgroup.subtree_control
[[ -d test ]] || mkdir test [[ -d test ]] || mkdir test
cd test cd test
cleanup()
{
online_cpus
rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
cd ..
rmdir test > /dev/null 2>&1
echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose
}
# Pause in ms # Pause in ms
pause() pause()
{ {
...@@ -666,6 +680,7 @@ test_inotify() ...@@ -666,6 +680,7 @@ test_inotify()
fi fi
} }
trap cleanup 0 2 3 6
run_state_test TEST_MATRIX run_state_test TEST_MATRIX
test_isolated test_isolated
test_inotify test_inotify
......
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