4646#include <linux/slab.h>
4747#include <linux/spinlock.h>
4848#include <linux/rwsem.h>
49+ #include <linux/percpu-rwsem.h>
4950#include <linux/string.h>
5051#include <linux/sort.h>
5152#include <linux/kmod.h>
@@ -103,6 +104,8 @@ static DEFINE_SPINLOCK(cgroup_idr_lock);
103104 */
104105static DEFINE_SPINLOCK (release_agent_path_lock );
105106
107+ struct percpu_rw_semaphore cgroup_threadgroup_rwsem ;
108+
106109#define cgroup_assert_mutex_or_rcu_locked () \
107110 rcu_lockdep_assert(rcu_read_lock_held() || \
108111 lockdep_is_held(&cgroup_mutex), \
@@ -848,48 +851,6 @@ static struct css_set *find_css_set(struct css_set *old_cset,
848851 return cset ;
849852}
850853
851- void cgroup_threadgroup_change_begin (struct task_struct * tsk )
852- {
853- down_read (& tsk -> signal -> group_rwsem );
854- }
855-
856- void cgroup_threadgroup_change_end (struct task_struct * tsk )
857- {
858- up_read (& tsk -> signal -> group_rwsem );
859- }
860-
861- /**
862- * threadgroup_lock - lock threadgroup
863- * @tsk: member task of the threadgroup to lock
864- *
865- * Lock the threadgroup @tsk belongs to. No new task is allowed to enter
866- * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
867- * change ->group_leader/pid. This is useful for cases where the threadgroup
868- * needs to stay stable across blockable operations.
869- *
870- * fork and exit explicitly call threadgroup_change_{begin|end}() for
871- * synchronization. While held, no new task will be added to threadgroup
872- * and no existing live task will have its PF_EXITING set.
873- *
874- * de_thread() does threadgroup_change_{begin|end}() when a non-leader
875- * sub-thread becomes a new leader.
876- */
877- static void threadgroup_lock (struct task_struct * tsk )
878- {
879- down_write (& tsk -> signal -> group_rwsem );
880- }
881-
882- /**
883- * threadgroup_unlock - unlock threadgroup
884- * @tsk: member task of the threadgroup to unlock
885- *
886- * Reverse threadgroup_lock().
887- */
888- static inline void threadgroup_unlock (struct task_struct * tsk )
889- {
890- up_write (& tsk -> signal -> group_rwsem );
891- }
892-
893854static struct cgroup_root * cgroup_root_from_kf (struct kernfs_root * kf_root )
894855{
895856 struct cgroup * root_cgrp = kf_root -> kn -> priv ;
@@ -2095,9 +2056,9 @@ static void cgroup_task_migrate(struct cgroup *old_cgrp,
20952056 lockdep_assert_held (& css_set_rwsem );
20962057
20972058 /*
2098- * We are synchronized through threadgroup_lock() against PF_EXITING
2099- * setting such that we can't race against cgroup_exit() changing the
2100- * css_set to init_css_set and dropping the old one.
2059+ * We are synchronized through cgroup_threadgroup_rwsem against
2060+ * PF_EXITING setting such that we can't race against cgroup_exit()
2061+ * changing the css_set to init_css_set and dropping the old one.
21012062 */
21022063 WARN_ON_ONCE (tsk -> flags & PF_EXITING );
21032064 old_cset = task_css_set (tsk );
@@ -2154,10 +2115,11 @@ static void cgroup_migrate_finish(struct list_head *preloaded_csets)
21542115 * @src_cset and add it to @preloaded_csets, which should later be cleaned
21552116 * up by cgroup_migrate_finish().
21562117 *
2157- * This function may be called without holding threadgroup_lock even if the
2158- * target is a process. Threads may be created and destroyed but as long
2159- * as cgroup_mutex is not dropped, no new css_set can be put into play and
2160- * the preloaded css_sets are guaranteed to cover all migrations.
2118+ * This function may be called without holding cgroup_threadgroup_rwsem
2119+ * even if the target is a process. Threads may be created and destroyed
2120+ * but as long as cgroup_mutex is not dropped, no new css_set can be put
2121+ * into play and the preloaded css_sets are guaranteed to cover all
2122+ * migrations.
21612123 */
21622124static void cgroup_migrate_add_src (struct css_set * src_cset ,
21632125 struct cgroup * dst_cgrp ,
@@ -2260,7 +2222,7 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp,
22602222 * @threadgroup: whether @leader points to the whole process or a single task
22612223 *
22622224 * Migrate a process or task denoted by @leader to @cgrp. If migrating a
2263- * process, the caller must be holding threadgroup_lock of @leader . The
2225+ * process, the caller must be holding cgroup_threadgroup_rwsem . The
22642226 * caller is also responsible for invoking cgroup_migrate_add_src() and
22652227 * cgroup_migrate_prepare_dst() on the targets before invoking this
22662228 * function and following up with cgroup_migrate_finish().
@@ -2388,7 +2350,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader,
23882350 * @leader: the task or the leader of the threadgroup to be attached
23892351 * @threadgroup: attach the whole threadgroup?
23902352 *
2391- * Call holding cgroup_mutex and threadgroup_lock of @leader .
2353+ * Call holding cgroup_mutex and cgroup_threadgroup_rwsem .
23922354 */
23932355static int cgroup_attach_task (struct cgroup * dst_cgrp ,
23942356 struct task_struct * leader , bool threadgroup )
@@ -2481,7 +2443,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
24812443 get_task_struct (tsk );
24822444 rcu_read_unlock ();
24832445
2484- threadgroup_lock ( tsk );
2446+ percpu_down_write ( & cgroup_threadgroup_rwsem );
24852447 if (threadgroup ) {
24862448 if (!thread_group_leader (tsk )) {
24872449 /*
@@ -2491,15 +2453,15 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
24912453 * try again; this is
24922454 * "double-double-toil-and-trouble-check locking".
24932455 */
2494- threadgroup_unlock ( tsk );
2456+ percpu_up_write ( & cgroup_threadgroup_rwsem );
24952457 put_task_struct (tsk );
24962458 goto retry_find_task ;
24972459 }
24982460 }
24992461
25002462 ret = cgroup_attach_task (cgrp , tsk , threadgroup );
25012463
2502- threadgroup_unlock ( tsk );
2464+ percpu_up_write ( & cgroup_threadgroup_rwsem );
25032465
25042466 put_task_struct (tsk );
25052467out_unlock_cgroup :
@@ -2704,17 +2666,17 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
27042666 goto out_finish ;
27052667 last_task = task ;
27062668
2707- threadgroup_lock ( task );
2669+ percpu_down_write ( & cgroup_threadgroup_rwsem );
27082670 /* raced against de_thread() from another thread? */
27092671 if (!thread_group_leader (task )) {
2710- threadgroup_unlock ( task );
2672+ percpu_up_write ( & cgroup_threadgroup_rwsem );
27112673 put_task_struct (task );
27122674 continue ;
27132675 }
27142676
27152677 ret = cgroup_migrate (src_cset -> dfl_cgrp , task , true);
27162678
2717- threadgroup_unlock ( task );
2679+ percpu_up_write ( & cgroup_threadgroup_rwsem );
27182680 put_task_struct (task );
27192681
27202682 if (WARN (ret , "cgroup: failed to update controllers for the default hierarchy (%d), further operations may crash or hang\n" , ret ))
@@ -5032,6 +4994,7 @@ int __init cgroup_init(void)
50324994 unsigned long key ;
50334995 int ssid , err ;
50344996
4997+ BUG_ON (percpu_init_rwsem (& cgroup_threadgroup_rwsem ));
50354998 BUG_ON (cgroup_init_cftypes (NULL , cgroup_dfl_base_files ));
50364999 BUG_ON (cgroup_init_cftypes (NULL , cgroup_legacy_base_files ));
50375000
0 commit comments