Pull cgroup fix from Tejun Heo: "One commit to fix a possible A-A deadlock around u64_stats_sync on 32bit machines caused by updating it without disabling IRQ when it may be read from IRQ context" * 'for-5.14-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup: rstat: fix A-A deadlock on 32bit around u64_stats_sync
Unified · Split
| @@ -790,6 +790,7 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu) · 789 unmodified lines | |||
| 790 | struct blkcg_gq *parent = blkg->parent; | 790 | struct blkcg_gq *parent = blkg->parent; |
| 791 | struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu); | 791 | struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu); |
| 792 | struct blkg_iostat cur, delta; | 792 | struct blkg_iostat cur, delta; |
| 793 | unsigned long flags; | ||
| 793 | unsigned int seq; | 794 | unsigned int seq; |
| 794 | 795 | ||
| 795 | /* fetch the current per-cpu values */ | 796 | /* fetch the current per-cpu values */ |
| @@ -799,21 +800,21 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu) · 3 unmodified lines | |||
| 799 | } while (u64_stats_fetch_retry(&bisc->sync, seq)); | 800 | } while (u64_stats_fetch_retry(&bisc->sync, seq)); |
| 800 | 801 | ||
| 801 | /* propagate percpu delta to global */ | 802 | /* propagate percpu delta to global */ |
| 802 | u64_stats_update_begin(&blkg->iostat.sync); | 803 | flags = u64_stats_update_begin_irqsave(&blkg->iostat.sync); |
| 803 | blkg_iostat_set(&delta, &cur); | 804 | blkg_iostat_set(&delta, &cur); |
| 804 | blkg_iostat_sub(&delta, &bisc->last); | 805 | blkg_iostat_sub(&delta, &bisc->last); |
| 805 | blkg_iostat_add(&blkg->iostat.cur, &delta); | 806 | blkg_iostat_add(&blkg->iostat.cur, &delta); |
| 806 | blkg_iostat_add(&bisc->last, &delta); | 807 | blkg_iostat_add(&bisc->last, &delta); |
| 807 | u64_stats_update_end(&blkg->iostat.sync); | 808 | u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); |
| 808 | 809 | ||
| 809 | /* propagate global delta to parent (unless that's root) */ | 810 | /* propagate global delta to parent (unless that's root) */ |
| 810 | if (parent && parent->parent) { | 811 | if (parent && parent->parent) { |
| 811 | u64_stats_update_begin(&parent->iostat.sync); | 812 | flags = u64_stats_update_begin_irqsave(&parent->iostat.sync); |
| 812 | blkg_iostat_set(&delta, &blkg->iostat.cur); | 813 | blkg_iostat_set(&delta, &blkg->iostat.cur); |
| 813 | blkg_iostat_sub(&delta, &blkg->iostat.last); | 814 | blkg_iostat_sub(&delta, &blkg->iostat.last); |
| 814 | blkg_iostat_add(&parent->iostat.cur, &delta); | 815 | blkg_iostat_add(&parent->iostat.cur, &delta); |
| 815 | blkg_iostat_add(&blkg->iostat.last, &delta); | 816 | blkg_iostat_add(&blkg->iostat.last, &delta); |
| 816 | u64_stats_update_end(&parent->iostat.sync); | 817 | u64_stats_update_end_irqrestore(&parent->iostat.sync, flags); |
| 817 | } | 818 | } |
| 818 | } | 819 | } |
| 819 | 820 | ||
| @@ -848,6 +849,7 @@ static void blkcg_fill_root_iostats(void) · 28 unmodified lines | |||
| 848 | memset(&tmp, 0, sizeof(tmp)); | 849 | memset(&tmp, 0, sizeof(tmp)); |
| 849 | for_each_possible_cpu(cpu) { | 850 | for_each_possible_cpu(cpu) { |
| 850 | struct disk_stats *cpu_dkstats; | 851 | struct disk_stats *cpu_dkstats; |
| 852 | unsigned long flags; | ||
| 851 | 853 | ||
| 852 | cpu_dkstats = per_cpu_ptr(bdev->bd_stats, cpu); | 854 | cpu_dkstats = per_cpu_ptr(bdev->bd_stats, cpu); |
| 853 | tmp.ios[BLKG_IOSTAT_READ] += | 855 | tmp.ios[BLKG_IOSTAT_READ] += |
| @@ -864,9 +866,9 @@ static void blkcg_fill_root_iostats(void) · 10 unmodified lines | |||
| 864 | tmp.bytes[BLKG_IOSTAT_DISCARD] += | 866 | tmp.bytes[BLKG_IOSTAT_DISCARD] += |
| 865 | cpu_dkstats->sectors[STAT_DISCARD] << 9; | 867 | cpu_dkstats->sectors[STAT_DISCARD] << 9; |
| 866 | 868 | ||
| 867 | u64_stats_update_begin(&blkg->iostat.sync); | 869 | flags = u64_stats_update_begin_irqsave(&blkg->iostat.sync); |
| 868 | blkg_iostat_set(&blkg->iostat.cur, &tmp); | 870 | blkg_iostat_set(&blkg->iostat.cur, &tmp); |
| 869 | u64_stats_update_end(&blkg->iostat.sync); | 871 | u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); |
| 870 | } | 872 | } |
| 871 | } | 873 | } |
| 872 | } | 874 | } |
| @@ -347,19 +347,20 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) · 346 unmodified lines | |||
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | static struct cgroup_rstat_cpu * | 349 | static struct cgroup_rstat_cpu * |
| 350 | cgroup_base_stat_cputime_account_begin(struct cgroup *cgrp) | 350 | cgroup_base_stat_cputime_account_begin(struct cgroup *cgrp, unsigned long *flags) |
| 351 | { | 351 | { |
| 352 | struct cgroup_rstat_cpu *rstatc; | 352 | struct cgroup_rstat_cpu *rstatc; |
| 353 | 353 | ||
| 354 | rstatc = get_cpu_ptr(cgrp->rstat_cpu); | 354 | rstatc = get_cpu_ptr(cgrp->rstat_cpu); |
| 355 | u64_stats_update_begin(&rstatc->bsync); | 355 | *flags = u64_stats_update_begin_irqsave(&rstatc->bsync); |
| 356 | return rstatc; | 356 | return rstatc; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp, | 359 | static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp, |
| 360 | struct cgroup_rstat_cpu *rstatc) | 360 | struct cgroup_rstat_cpu *rstatc, |
| 361 | unsigned long flags) | ||
| 361 | { | 362 | { |
| 362 | u64_stats_update_end(&rstatc->bsync); | 363 | u64_stats_update_end_irqrestore(&rstatc->bsync, flags); |
| 363 | cgroup_rstat_updated(cgrp, smp_processor_id()); | 364 | cgroup_rstat_updated(cgrp, smp_processor_id()); |
| 364 | put_cpu_ptr(rstatc); | 365 | put_cpu_ptr(rstatc); |
| 365 | } | 366 | } |
| @@ -367,18 +368,20 @@ static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp, · 1 unmodified line | |||
| 367 | void __cgroup_account_cputime(struct cgroup *cgrp, u64 delta_exec) | 368 | void __cgroup_account_cputime(struct cgroup *cgrp, u64 delta_exec) |
| 368 | { | 369 | { |
| 369 | struct cgroup_rstat_cpu *rstatc; | 370 | struct cgroup_rstat_cpu *rstatc; |
| 371 | unsigned long flags; | ||
| 370 | 372 | ||
| 371 | rstatc = cgroup_base_stat_cputime_account_begin(cgrp); | 373 | rstatc = cgroup_base_stat_cputime_account_begin(cgrp, &flags); |
| 372 | rstatc->bstat.cputime.sum_exec_runtime += delta_exec; | 374 | rstatc->bstat.cputime.sum_exec_runtime += delta_exec; |
| 373 | cgroup_base_stat_cputime_account_end(cgrp, rstatc); | 375 | cgroup_base_stat_cputime_account_end(cgrp, rstatc, flags); |
| 374 | } | 376 | } |
| 375 | 377 | ||
| 376 | void __cgroup_account_cputime_field(struct cgroup *cgrp, | 378 | void __cgroup_account_cputime_field(struct cgroup *cgrp, |
| 377 | enum cpu_usage_stat index, u64 delta_exec) | 379 | enum cpu_usage_stat index, u64 delta_exec) |
| 378 | { | 380 | { |
| 379 | struct cgroup_rstat_cpu *rstatc; | 381 | struct cgroup_rstat_cpu *rstatc; |
| 382 | unsigned long flags; | ||
| 380 | 383 | ||
| 381 | rstatc = cgroup_base_stat_cputime_account_begin(cgrp); | 384 | rstatc = cgroup_base_stat_cputime_account_begin(cgrp, &flags); |
| 382 | 385 | ||
| 383 | switch (index) { | 386 | switch (index) { |
| 384 | case CPUTIME_USER: | 387 | case CPUTIME_USER: |
| @@ -394,7 +397,7 @@ void __cgroup_account_cputime_field(struct cgroup *cgrp, · 9 unmodified lines | |||
| 394 | break; | 397 | break; |
| 395 | } | 398 | } |
| 396 | 399 | ||
| 397 | cgroup_base_stat_cputime_account_end(cgrp, rstatc); | 400 | cgroup_base_stat_cputime_account_end(cgrp, rstatc, flags); |
| 398 | } | 401 | } |
| 399 | 402 | ||
| 400 | /* | 403 | /* |