46
46
#include <linux/slab.h>
47
47
#include <linux/spinlock.h>
48
48
#include <linux/rwsem.h>
49
- #include <linux/percpu-rwsem.h>
50
49
#include <linux/string.h>
51
50
#include <linux/sort.h>
52
51
#include <linux/kmod.h>
@@ -104,8 +103,6 @@ static DEFINE_SPINLOCK(cgroup_idr_lock);
104
103
*/
105
104
static DEFINE_SPINLOCK (release_agent_path_lock );
106
105
107
- struct percpu_rw_semaphore cgroup_threadgroup_rwsem ;
108
-
109
106
#define cgroup_assert_mutex_or_rcu_locked () \
110
107
RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \
111
108
!lockdep_is_held(&cgroup_mutex), \
@@ -874,6 +871,48 @@ static struct css_set *find_css_set(struct css_set *old_cset,
874
871
return cset ;
875
872
}
876
873
874
+ void cgroup_threadgroup_change_begin (struct task_struct * tsk )
875
+ {
876
+ down_read (& tsk -> signal -> group_rwsem );
877
+ }
878
+
879
+ void cgroup_threadgroup_change_end (struct task_struct * tsk )
880
+ {
881
+ up_read (& tsk -> signal -> group_rwsem );
882
+ }
883
+
884
+ /**
885
+ * threadgroup_lock - lock threadgroup
886
+ * @tsk: member task of the threadgroup to lock
887
+ *
888
+ * Lock the threadgroup @tsk belongs to. No new task is allowed to enter
889
+ * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
890
+ * change ->group_leader/pid. This is useful for cases where the threadgroup
891
+ * needs to stay stable across blockable operations.
892
+ *
893
+ * fork and exit explicitly call threadgroup_change_{begin|end}() for
894
+ * synchronization. While held, no new task will be added to threadgroup
895
+ * and no existing live task will have its PF_EXITING set.
896
+ *
897
+ * de_thread() does threadgroup_change_{begin|end}() when a non-leader
898
+ * sub-thread becomes a new leader.
899
+ */
900
+ static void threadgroup_lock (struct task_struct * tsk )
901
+ {
902
+ down_write (& tsk -> signal -> group_rwsem );
903
+ }
904
+
905
+ /**
906
+ * threadgroup_unlock - unlock threadgroup
907
+ * @tsk: member task of the threadgroup to unlock
908
+ *
909
+ * Reverse threadgroup_lock().
910
+ */
911
+ static inline void threadgroup_unlock (struct task_struct * tsk )
912
+ {
913
+ up_write (& tsk -> signal -> group_rwsem );
914
+ }
915
+
877
916
static struct cgroup_root * cgroup_root_from_kf (struct kernfs_root * kf_root )
878
917
{
879
918
struct cgroup * root_cgrp = kf_root -> kn -> priv ;
@@ -2074,9 +2113,9 @@ static void cgroup_task_migrate(struct cgroup *old_cgrp,
2074
2113
lockdep_assert_held (& css_set_rwsem );
2075
2114
2076
2115
/*
2077
- * We are synchronized through cgroup_threadgroup_rwsem against
2078
- * PF_EXITING setting such that we can't race against cgroup_exit()
2079
- * changing the css_set to init_css_set and dropping the old one.
2116
+ * We are synchronized through threadgroup_lock() against PF_EXITING
2117
+ * setting such that we can't race against cgroup_exit() changing the
2118
+ * css_set to init_css_set and dropping the old one.
2080
2119
*/
2081
2120
WARN_ON_ONCE (tsk -> flags & PF_EXITING );
2082
2121
old_cset = task_css_set (tsk );
@@ -2133,11 +2172,10 @@ static void cgroup_migrate_finish(struct list_head *preloaded_csets)
2133
2172
* @src_cset and add it to @preloaded_csets, which should later be cleaned
2134
2173
* up by cgroup_migrate_finish().
2135
2174
*
2136
- * This function may be called without holding cgroup_threadgroup_rwsem
2137
- * even if the target is a process. Threads may be created and destroyed
2138
- * but as long as cgroup_mutex is not dropped, no new css_set can be put
2139
- * into play and the preloaded css_sets are guaranteed to cover all
2140
- * migrations.
2175
+ * This function may be called without holding threadgroup_lock even if the
2176
+ * target is a process. Threads may be created and destroyed but as long
2177
+ * as cgroup_mutex is not dropped, no new css_set can be put into play and
2178
+ * the preloaded css_sets are guaranteed to cover all migrations.
2141
2179
*/
2142
2180
static void cgroup_migrate_add_src (struct css_set * src_cset ,
2143
2181
struct cgroup * dst_cgrp ,
@@ -2240,7 +2278,7 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp,
2240
2278
* @threadgroup: whether @leader points to the whole process or a single task
2241
2279
*
2242
2280
* Migrate a process or task denoted by @leader to @cgrp. If migrating a
2243
- * process, the caller must be holding cgroup_threadgroup_rwsem . The
2281
+ * process, the caller must be holding threadgroup_lock of @leader . The
2244
2282
* caller is also responsible for invoking cgroup_migrate_add_src() and
2245
2283
* cgroup_migrate_prepare_dst() on the targets before invoking this
2246
2284
* function and following up with cgroup_migrate_finish().
@@ -2368,7 +2406,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader,
2368
2406
* @leader: the task or the leader of the threadgroup to be attached
2369
2407
* @threadgroup: attach the whole threadgroup?
2370
2408
*
2371
- * Call holding cgroup_mutex and cgroup_threadgroup_rwsem .
2409
+ * Call holding cgroup_mutex and threadgroup_lock of @leader .
2372
2410
*/
2373
2411
static int cgroup_attach_task (struct cgroup * dst_cgrp ,
2374
2412
struct task_struct * leader , bool threadgroup )
@@ -2490,7 +2528,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2490
2528
get_task_struct (tsk );
2491
2529
rcu_read_unlock ();
2492
2530
2493
- percpu_down_write ( & cgroup_threadgroup_rwsem );
2531
+ threadgroup_lock ( tsk );
2494
2532
if (threadgroup ) {
2495
2533
if (!thread_group_leader (tsk )) {
2496
2534
/*
@@ -2500,7 +2538,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2500
2538
* try again; this is
2501
2539
* "double-double-toil-and-trouble-check locking".
2502
2540
*/
2503
- percpu_up_write ( & cgroup_threadgroup_rwsem );
2541
+ threadgroup_unlock ( tsk );
2504
2542
put_task_struct (tsk );
2505
2543
goto retry_find_task ;
2506
2544
}
@@ -2510,7 +2548,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2510
2548
if (!ret )
2511
2549
ret = cgroup_attach_task (cgrp , tsk , threadgroup );
2512
2550
2513
- percpu_up_write ( & cgroup_threadgroup_rwsem );
2551
+ threadgroup_unlock ( tsk );
2514
2552
2515
2553
put_task_struct (tsk );
2516
2554
out_unlock_cgroup :
@@ -2713,17 +2751,17 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
2713
2751
goto out_finish ;
2714
2752
last_task = task ;
2715
2753
2716
- percpu_down_write ( & cgroup_threadgroup_rwsem );
2754
+ threadgroup_lock ( task );
2717
2755
/* raced against de_thread() from another thread? */
2718
2756
if (!thread_group_leader (task )) {
2719
- percpu_up_write ( & cgroup_threadgroup_rwsem );
2757
+ threadgroup_unlock ( task );
2720
2758
put_task_struct (task );
2721
2759
continue ;
2722
2760
}
2723
2761
2724
2762
ret = cgroup_migrate (src_cset -> dfl_cgrp , task , true);
2725
2763
2726
- percpu_up_write ( & cgroup_threadgroup_rwsem );
2764
+ threadgroup_unlock ( task );
2727
2765
put_task_struct (task );
2728
2766
2729
2767
if (WARN (ret , "cgroup: failed to update controllers for the default hierarchy (%d), further operations may crash or hang\n" , ret ))
@@ -5045,7 +5083,6 @@ int __init cgroup_init(void)
5045
5083
unsigned long key ;
5046
5084
int ssid , err ;
5047
5085
5048
- BUG_ON (percpu_init_rwsem (& cgroup_threadgroup_rwsem ));
5049
5086
BUG_ON (cgroup_init_cftypes (NULL , cgroup_dfl_base_files ));
5050
5087
BUG_ON (cgroup_init_cftypes (NULL , cgroup_legacy_base_files ));
5051
5088
0 commit comments