cpuset_rwsem is going to be acquired from sched_setscheduler() with a following patch. There are however paths (e.g., spawn_ksoftirqd) in which sched_scheduler() is eventually called while holding hotplug lock; this creates a dependecy between hotplug lock (to be always acquired first) and cpuset_rwsem (to be always acquired after hotplug lock). Fix paths which currently take the two locks in the wrong order (after a following patch is applied).
Unified · Split
| @@ -40,14 +40,14 @@ static inline bool cpusets_enabled(void) · 39 unmodified lines | |||
| 40 | 40 | ||
| 41 | static inline void cpuset_inc(void) | 41 | static inline void cpuset_inc(void) |
| 42 | { | 42 | { |
| 43 | static_branch_inc(&cpusets_pre_enable_key); | 43 | static_branch_inc_cpuslocked(&cpusets_pre_enable_key); |
| 44 | static_branch_inc(&cpusets_enabled_key); | 44 | static_branch_inc_cpuslocked(&cpusets_enabled_key); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | static inline void cpuset_dec(void) | 47 | static inline void cpuset_dec(void) |
| 48 | { | 48 | { |
| 49 | static_branch_dec(&cpusets_enabled_key); | 49 | static_branch_dec_cpuslocked(&cpusets_enabled_key); |
| 50 | static_branch_dec(&cpusets_pre_enable_key); | 50 | static_branch_dec_cpuslocked(&cpusets_pre_enable_key); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | extern int cpuset_init(void); | 53 | extern int cpuset_init(void); |
| @@ -973,8 +973,8 @@ static void rebuild_sched_domains_locked(void) · 972 unmodified lines | |||
| 973 | cpumask_var_t *doms; | 973 | cpumask_var_t *doms; |
| 974 | int ndoms; | 974 | int ndoms; |
| 975 | 975 | ||
| 976 | lockdep_assert_cpus_held(); | ||
| 976 | percpu_rwsem_assert_held(&cpuset_rwsem); | 977 | percpu_rwsem_assert_held(&cpuset_rwsem); |
| 977 | get_online_cpus(); | ||
| 978 | 978 | ||
| 979 | /* | 979 | /* |
| 980 | * We have raced with CPU hotplug. Don't do anything to avoid | 980 | * We have raced with CPU hotplug. Don't do anything to avoid |
| @@ -983,19 +983,17 @@ static void rebuild_sched_domains_locked(void) · 2 unmodified lines | |||
| 983 | */ | 983 | */ |
| 984 | if (!top_cpuset.nr_subparts_cpus && | 984 | if (!top_cpuset.nr_subparts_cpus && |
| 985 | !cpumask_equal(top_cpuset.effective_cpus, cpu_active_mask)) | 985 | !cpumask_equal(top_cpuset.effective_cpus, cpu_active_mask)) |
| 986 | goto out; | 986 | return; |
| 987 | 987 | ||
| 988 | if (top_cpuset.nr_subparts_cpus && | 988 | if (top_cpuset.nr_subparts_cpus && |
| 989 | !cpumask_subset(top_cpuset.effective_cpus, cpu_active_mask)) | 989 | !cpumask_subset(top_cpuset.effective_cpus, cpu_active_mask)) |
| 990 | goto out; | 990 | return; |
| 991 | 991 | ||
| 992 | /* Generate domain masks and attrs */ | 992 | /* Generate domain masks and attrs */ |
| 993 | ndoms = generate_sched_domains(&doms, &attr); | 993 | ndoms = generate_sched_domains(&doms, &attr); |
| 994 | 994 | ||
| 995 | /* Have scheduler rebuild the domains */ | 995 | /* Have scheduler rebuild the domains */ |
| 996 | partition_and_rebuild_sched_domains(ndoms, doms, attr); | 996 | partition_and_rebuild_sched_domains(ndoms, doms, attr); |
| 997 | out: | ||
| 998 | put_online_cpus(); | ||
| 999 | } | 997 | } |
| 1000 | #else /* !CONFIG_SMP */ | 998 | #else /* !CONFIG_SMP */ |
| 1001 | static void rebuild_sched_domains_locked(void) | 999 | static void rebuild_sched_domains_locked(void) |
| @@ -1005,9 +1003,11 @@ static void rebuild_sched_domains_locked(void) · 3 unmodified lines | |||
| 1005 | 1003 | ||
| 1006 | void rebuild_sched_domains(void) | 1004 | void rebuild_sched_domains(void) |
| 1007 | { | 1005 | { |
| 1006 | get_online_cpus(); | ||
| 1008 | percpu_down_write(&cpuset_rwsem); | 1007 | percpu_down_write(&cpuset_rwsem); |
| 1009 | rebuild_sched_domains_locked(); | 1008 | rebuild_sched_domains_locked(); |
| 1010 | percpu_up_write(&cpuset_rwsem); | 1009 | percpu_up_write(&cpuset_rwsem); |
| 1010 | put_online_cpus(); | ||
| 1011 | } | 1011 | } |
| 1012 | 1012 | ||
| 1013 | /** | 1013 | /** |
| @@ -2245,6 +2245,7 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft, · 1231 unmodified lines | |||
| 2245 | cpuset_filetype_t type = cft->private; | 2245 | cpuset_filetype_t type = cft->private; |
| 2246 | int retval = 0; | 2246 | int retval = 0; |
| 2247 | 2247 | ||
| 2248 | get_online_cpus(); | ||
| 2248 | percpu_down_write(&cpuset_rwsem); | 2249 | percpu_down_write(&cpuset_rwsem); |
| 2249 | if (!is_cpuset_online(cs)) { | 2250 | if (!is_cpuset_online(cs)) { |
| 2250 | retval = -ENODEV; | 2251 | retval = -ENODEV; |
| @@ -2282,6 +2283,7 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft, · 31 unmodified lines | |||
| 2282 | } | 2283 | } |
| 2283 | out_unlock: | 2284 | out_unlock: |
| 2284 | percpu_up_write(&cpuset_rwsem); | 2285 | percpu_up_write(&cpuset_rwsem); |
| 2286 | put_online_cpus(); | ||
| 2285 | return retval; | 2287 | return retval; |
| 2286 | } | 2288 | } |
| 2287 | 2289 | ||
| @@ -2292,6 +2294,7 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft, · 4 unmodified lines | |||
| 2292 | cpuset_filetype_t type = cft->private; | 2294 | cpuset_filetype_t type = cft->private; |
| 2293 | int retval = -ENODEV; | 2295 | int retval = -ENODEV; |
| 2294 | 2296 | ||
| 2297 | get_online_cpus(); | ||
| 2295 | percpu_down_write(&cpuset_rwsem); | 2298 | percpu_down_write(&cpuset_rwsem); |
| 2296 | if (!is_cpuset_online(cs)) | 2299 | if (!is_cpuset_online(cs)) |
| 2297 | goto out_unlock; | 2300 | goto out_unlock; |
| @@ -2306,6 +2309,7 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft, · 8 unmodified lines | |||
| 2306 | } | 2309 | } |
| 2307 | out_unlock: | 2310 | out_unlock: |
| 2308 | percpu_up_write(&cpuset_rwsem); | 2311 | percpu_up_write(&cpuset_rwsem); |
| 2312 | put_online_cpus(); | ||
| 2309 | return retval; | 2313 | return retval; |
| 2310 | } | 2314 | } |
| 2311 | 2315 | ||
| @@ -2344,6 +2348,7 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of, · 32 unmodified lines | |||
| 2344 | kernfs_break_active_protection(of->kn); | 2348 | kernfs_break_active_protection(of->kn); |
| 2345 | flush_work(&cpuset_hotplug_work); | 2349 | flush_work(&cpuset_hotplug_work); |
| 2346 | 2350 | ||
| 2351 | get_online_cpus(); | ||
| 2347 | percpu_down_write(&cpuset_rwsem); | 2352 | percpu_down_write(&cpuset_rwsem); |
| 2348 | if (!is_cpuset_online(cs)) | 2353 | if (!is_cpuset_online(cs)) |
| 2349 | goto out_unlock; | 2354 | goto out_unlock; |
| @@ -2369,6 +2374,7 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of, · 19 unmodified lines | |||
| 2369 | free_cpuset(trialcs); | 2374 | free_cpuset(trialcs); |
| 2370 | out_unlock: | 2375 | out_unlock: |
| 2371 | percpu_up_write(&cpuset_rwsem); | 2376 | percpu_up_write(&cpuset_rwsem); |
| 2377 | put_online_cpus(); | ||
| 2372 | kernfs_unbreak_active_protection(of->kn); | 2378 | kernfs_unbreak_active_protection(of->kn); |
| 2373 | css_put(&cs->css); | 2379 | css_put(&cs->css); |
| 2374 | flush_workqueue(cpuset_migrate_mm_wq); | 2380 | flush_workqueue(cpuset_migrate_mm_wq); |
| @@ -2499,6 +2505,7 @@ static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf, · 124 unmodified lines | |||
| 2499 | return -EINVAL; | 2505 | return -EINVAL; |
| 2500 | 2506 | ||
| 2501 | css_get(&cs->css); | 2507 | css_get(&cs->css); |
| 2508 | get_online_cpus(); | ||
| 2502 | percpu_down_write(&cpuset_rwsem); | 2509 | percpu_down_write(&cpuset_rwsem); |
| 2503 | if (!is_cpuset_online(cs)) | 2510 | if (!is_cpuset_online(cs)) |
| 2504 | goto out_unlock; | 2511 | goto out_unlock; |
| @@ -2506,6 +2513,7 @@ static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf, · 1 unmodified line | |||
| 2506 | retval = update_prstate(cs, val); | 2513 | retval = update_prstate(cs, val); |
| 2507 | out_unlock: | 2514 | out_unlock: |
| 2508 | percpu_up_write(&cpuset_rwsem); | 2515 | percpu_up_write(&cpuset_rwsem); |
| 2516 | put_online_cpus(); | ||
| 2509 | css_put(&cs->css); | 2517 | css_put(&cs->css); |
| 2510 | return retval ?: nbytes; | 2518 | return retval ?: nbytes; |
| 2511 | } | 2519 | } |
| @@ -2711,6 +2719,7 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) · 199 unmodified lines | |||
| 2711 | if (!parent) | 2719 | if (!parent) |
| 2712 | return 0; | 2720 | return 0; |
| 2713 | 2721 | ||
| 2722 | get_online_cpus(); | ||
| 2714 | percpu_down_write(&cpuset_rwsem); | 2723 | percpu_down_write(&cpuset_rwsem); |
| 2715 | 2724 | ||
| 2716 | set_bit(CS_ONLINE, &cs->flags); | 2725 | set_bit(CS_ONLINE, &cs->flags); |
| @@ -2763,6 +2772,7 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) · 46 unmodified lines | |||
| 2763 | spin_unlock_irq(&callback_lock); | 2772 | spin_unlock_irq(&callback_lock); |
| 2764 | out_unlock: | 2773 | out_unlock: |
| 2765 | percpu_up_write(&cpuset_rwsem); | 2774 | percpu_up_write(&cpuset_rwsem); |
| 2775 | put_online_cpus(); | ||
| 2766 | return 0; | 2776 | return 0; |
| 2767 | } | 2777 | } |
| 2768 | 2778 | ||
| @@ -2781,6 +2791,7 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css) · 12 unmodified lines | |||
| 2781 | { | 2791 | { |
| 2782 | struct cpuset *cs = css_cs(css); | 2792 | struct cpuset *cs = css_cs(css); |
| 2783 | 2793 | ||
| 2794 | get_online_cpus(); | ||
| 2784 | percpu_down_write(&cpuset_rwsem); | 2795 | percpu_down_write(&cpuset_rwsem); |
| 2785 | 2796 | ||
| 2786 | if (is_partition_root(cs)) | 2797 | if (is_partition_root(cs)) |
| @@ -2801,6 +2812,7 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css) · 14 unmodified lines | |||
| 2801 | clear_bit(CS_ONLINE, &cs->flags); | 2812 | clear_bit(CS_ONLINE, &cs->flags); |
| 2802 | 2813 | ||
| 2803 | percpu_up_write(&cpuset_rwsem); | 2814 | percpu_up_write(&cpuset_rwsem); |
| 2815 | put_online_cpus(); | ||
| 2804 | } | 2816 | } |
| 2805 | 2817 | ||
| 2806 | static void cpuset_css_free(struct cgroup_subsys_state *css) | 2818 | static void cpuset_css_free(struct cgroup_subsys_state *css) |