aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-09-11 15:00:21 -0400
committerTejun Heo <tj@kernel.org>2015-09-22 12:46:53 -0400
commitadaae5dcf8920375a2fdc6268f762a0b7b331c55 (patch)
treea09f5065616798908cb15822081d7fe79d2fc50f
parent9af2ec45c2d323d5ce35b431bb150c0eb567f19a (diff)
cgroup: separate out taskset operations from cgroup_migrate()
Currently, cgroup_migreate() implements large part of the migration logic inline including building the target taskset and actually migrating them. This patch separates out the following taskset operations. CGROUP_TASKSET_INIT() : taskset initializer cgroup_taskset_add() : add a task to a taskset cgroup_taskset_migrate() : migrate a taskset to the destination cgroup This will be used to implement atomic multi-process migration in cgroup_update_dfl_csses(). This is pure reorganization which doesn't introduce any functional changes. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Zefan Li <lizefan@huawei.com>
-rw-r--r--kernel/cgroup.c211
1 files changed, 125 insertions, 86 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index dc079560dd53..f24d3cedd809 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2144,6 +2144,49 @@ struct cgroup_taskset {
2144 struct task_struct *cur_task; 2144 struct task_struct *cur_task;
2145}; 2145};
2146 2146
2147#define CGROUP_TASKSET_INIT(tset) (struct cgroup_taskset){ \
2148 .src_csets = LIST_HEAD_INIT(tset.src_csets), \
2149 .dst_csets = LIST_HEAD_INIT(tset.dst_csets), \
2150 .csets = &tset.src_csets, \
2151}
2152
2153/**
2154 * cgroup_taskset_add - try to add a migration target task to a taskset
2155 * @task: target task
2156 * @tset: target taskset
2157 *
2158 * Add @task, which is a migration target, to @tset. This function becomes
2159 * noop if @task doesn't need to be migrated. @task's css_set should have
2160 * been added as a migration source and @task->cg_list will be moved from
2161 * the css_set's tasks list to mg_tasks one.
2162 */
2163static void cgroup_taskset_add(struct task_struct *task,
2164 struct cgroup_taskset *tset)
2165{
2166 struct css_set *cset;
2167
2168 lockdep_assert_held(&css_set_rwsem);
2169
2170 /* @task either already exited or can't exit until the end */
2171 if (task->flags & PF_EXITING)
2172 return;
2173
2174 /* leave @task alone if post_fork() hasn't linked it yet */
2175 if (list_empty(&task->cg_list))
2176 return;
2177
2178 cset = task_css_set(task);
2179 if (!cset->mg_src_cgrp)
2180 return;
2181
2182 list_move_tail(&task->cg_list, &cset->mg_tasks);
2183 if (list_empty(&cset->mg_node))
2184 list_add_tail(&cset->mg_node, &tset->src_csets);
2185 if (list_empty(&cset->mg_dst_cset->mg_node))
2186 list_move_tail(&cset->mg_dst_cset->mg_node,
2187 &tset->dst_csets);
2188}
2189
2147/** 2190/**
2148 * cgroup_taskset_first - reset taskset and return the first task 2191 * cgroup_taskset_first - reset taskset and return the first task
2149 * @tset: taskset of interest 2192 * @tset: taskset of interest
@@ -2228,6 +2271,84 @@ static void cgroup_task_migrate(struct cgroup *old_cgrp,
2228} 2271}
2229 2272
2230/** 2273/**
2274 * cgroup_taskset_migrate - migrate a taskset to a cgroup
2275 * @tset: taget taskset
2276 * @dst_cgrp: destination cgroup
2277 *
2278 * Migrate tasks in @tset to @dst_cgrp. This function fails iff one of the
2279 * ->can_attach callbacks fails and guarantees that either all or none of
2280 * the tasks in @tset are migrated. @tset is consumed regardless of
2281 * success.
2282 */
2283static int cgroup_taskset_migrate(struct cgroup_taskset *tset,
2284 struct cgroup *dst_cgrp)
2285{
2286 struct cgroup_subsys_state *css, *failed_css = NULL;
2287 struct task_struct *task, *tmp_task;
2288 struct css_set *cset, *tmp_cset;
2289 int i, ret;
2290
2291 /* methods shouldn't be called if no task is actually migrating */
2292 if (list_empty(&tset->src_csets))
2293 return 0;
2294
2295 /* check that we can legitimately attach to the cgroup */
2296 for_each_e_css(css, i, dst_cgrp) {
2297 if (css->ss->can_attach) {
2298 ret = css->ss->can_attach(css, tset);
2299 if (ret) {
2300 failed_css = css;
2301 goto out_cancel_attach;
2302 }
2303 }
2304 }
2305
2306 /*
2307 * Now that we're guaranteed success, proceed to move all tasks to
2308 * the new cgroup. There are no failure cases after here, so this
2309 * is the commit point.
2310 */
2311 down_write(&css_set_rwsem);
2312 list_for_each_entry(cset, &tset->src_csets, mg_node) {
2313 list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list)
2314 cgroup_task_migrate(cset->mg_src_cgrp, task,
2315 cset->mg_dst_cset);
2316 }
2317 up_write(&css_set_rwsem);
2318
2319 /*
2320 * Migration is committed, all target tasks are now on dst_csets.
2321 * Nothing is sensitive to fork() after this point. Notify
2322 * controllers that migration is complete.
2323 */
2324 tset->csets = &tset->dst_csets;
2325
2326 for_each_e_css(css, i, dst_cgrp)
2327 if (css->ss->attach)
2328 css->ss->attach(css, tset);
2329
2330 ret = 0;
2331 goto out_release_tset;
2332
2333out_cancel_attach:
2334 for_each_e_css(css, i, dst_cgrp) {
2335 if (css == failed_css)
2336 break;
2337 if (css->ss->cancel_attach)
2338 css->ss->cancel_attach(css, tset);
2339 }
2340out_release_tset:
2341 down_write(&css_set_rwsem);
2342 list_splice_init(&tset->dst_csets, &tset->src_csets);
2343 list_for_each_entry_safe(cset, tmp_cset, &tset->src_csets, mg_node) {
2344 list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
2345 list_del_init(&cset->mg_node);
2346 }
2347 up_write(&css_set_rwsem);
2348 return ret;
2349}
2350
2351/**
2231 * cgroup_migrate_finish - cleanup after attach 2352 * cgroup_migrate_finish - cleanup after attach
2232 * @preloaded_csets: list of preloaded css_sets 2353 * @preloaded_csets: list of preloaded css_sets
2233 * 2354 *
@@ -2381,15 +2502,8 @@ err:
2381static int cgroup_migrate(struct task_struct *leader, bool threadgroup, 2502static int cgroup_migrate(struct task_struct *leader, bool threadgroup,
2382 struct cgroup *cgrp) 2503 struct cgroup *cgrp)
2383{ 2504{
2384 struct cgroup_taskset tset = { 2505 struct cgroup_taskset tset = CGROUP_TASKSET_INIT(tset);
2385 .src_csets = LIST_HEAD_INIT(tset.src_csets), 2506 struct task_struct *task;
2386 .dst_csets = LIST_HEAD_INIT(tset.dst_csets),
2387 .csets = &tset.src_csets,
2388 };
2389 struct cgroup_subsys_state *css, *failed_css = NULL;
2390 struct css_set *cset, *tmp_cset;
2391 struct task_struct *task, *tmp_task;
2392 int i, ret;
2393 2507
2394 /* 2508 /*
2395 * Prevent freeing of tasks while we take a snapshot. Tasks that are 2509 * Prevent freeing of tasks while we take a snapshot. Tasks that are
@@ -2400,89 +2514,14 @@ static int cgroup_migrate(struct task_struct *leader, bool threadgroup,
2400 rcu_read_lock(); 2514 rcu_read_lock();
2401 task = leader; 2515 task = leader;
2402 do { 2516 do {
2403 /* @task either already exited or can't exit until the end */ 2517 cgroup_taskset_add(task, &tset);
2404 if (task->flags & PF_EXITING)
2405 goto next;
2406
2407 /* leave @task alone if post_fork() hasn't linked it yet */
2408 if (list_empty(&task->cg_list))
2409 goto next;
2410
2411 cset = task_css_set(task);
2412 if (!cset->mg_src_cgrp)
2413 goto next;
2414
2415 list_move_tail(&task->cg_list, &cset->mg_tasks);
2416 if (list_empty(&cset->mg_node))
2417 list_add_tail(&cset->mg_node, &tset.src_csets);
2418 if (list_empty(&cset->mg_dst_cset->mg_node))
2419 list_move_tail(&cset->mg_dst_cset->mg_node,
2420 &tset.dst_csets);
2421 next:
2422 if (!threadgroup) 2518 if (!threadgroup)
2423 break; 2519 break;
2424 } while_each_thread(leader, task); 2520 } while_each_thread(leader, task);
2425 rcu_read_unlock(); 2521 rcu_read_unlock();
2426 up_write(&css_set_rwsem); 2522 up_write(&css_set_rwsem);
2427 2523
2428 /* methods shouldn't be called if no task is actually migrating */ 2524 return cgroup_taskset_migrate(&tset, cgrp);
2429 if (list_empty(&tset.src_csets))
2430 return 0;
2431
2432 /* check that we can legitimately attach to the cgroup */
2433 for_each_e_css(css, i, cgrp) {
2434 if (css->ss->can_attach) {
2435 ret = css->ss->can_attach(css, &tset);
2436 if (ret) {
2437 failed_css = css;
2438 goto out_cancel_attach;
2439 }
2440 }
2441 }
2442
2443 /*
2444 * Now that we're guaranteed success, proceed to move all tasks to
2445 * the new cgroup. There are no failure cases after here, so this
2446 * is the commit point.
2447 */
2448 down_write(&css_set_rwsem);
2449 list_for_each_entry(cset, &tset.src_csets, mg_node) {
2450 list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list)
2451 cgroup_task_migrate(cset->mg_src_cgrp, task,
2452 cset->mg_dst_cset);
2453 }
2454 up_write(&css_set_rwsem);
2455
2456 /*
2457 * Migration is committed, all target tasks are now on dst_csets.
2458 * Nothing is sensitive to fork() after this point. Notify
2459 * controllers that migration is complete.
2460 */
2461 tset.csets = &tset.dst_csets;
2462
2463 for_each_e_css(css, i, cgrp)
2464 if (css->ss->attach)
2465 css->ss->attach(css, &tset);
2466
2467 ret = 0;
2468 goto out_release_tset;
2469
2470out_cancel_attach:
2471 for_each_e_css(css, i, cgrp) {
2472 if (css == failed_css)
2473 break;
2474 if (css->ss->cancel_attach)
2475 css->ss->cancel_attach(css, &tset);
2476 }
2477out_release_tset:
2478 down_write(&css_set_rwsem);
2479 list_splice_init(&tset.dst_csets, &tset.src_csets);
2480 list_for_each_entry_safe(cset, tmp_cset, &tset.src_csets, mg_node) {
2481 list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
2482 list_del_init(&cset->mg_node);
2483 }
2484 up_write(&css_set_rwsem);
2485 return ret;
2486} 2525}
2487 2526
2488/** 2527/**