Skip to content

Commit 3e6c08d

Browse files
danieljordan10gregkh
authored andcommitted
padata: Put CPU offline callback in ONLINE section to allow failure
[ Upstream commit c8c4a29 ] syzbot reported the following warning: DEAD callback error for CPU1 WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 at commit 4ae12d8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") which tglx traced to padata_cpu_dead() given it's the only sub-CPUHP_TEARDOWN_CPU callback that returns an error. Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU so move the CPU offline callback to the ONLINE section where failure is possible. Fixes: 894c9ef ("padata: validate cpumask without removed CPU during offline") Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ Debugged-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 36661e9 commit 3e6c08d

3 files changed

Lines changed: 65 additions & 64 deletions

File tree

include/linux/cpuhotplug.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ enum cpuhp_state {
9494
CPUHP_PCI_XGENE_DEAD,
9595
CPUHP_IOMMU_IOVA_DEAD,
9696
CPUHP_AP_ARM_CACHE_B15_RAC_DEAD,
97-
CPUHP_PADATA_DEAD,
9897
CPUHP_AP_DTPM_CPU_DEAD,
9998
CPUHP_RANDOM_PREPARE,
10099
CPUHP_WORKQUEUE_PREP,

include/linux/padata.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,23 @@ struct padata_mt_job {
149149
/**
150150
* struct padata_instance - The overall control structure.
151151
*
152-
* @cpu_online_node: Linkage for CPU online callback.
153-
* @cpu_dead_node: Linkage for CPU offline callback.
152+
* @cpuhp_node: Linkage for CPU hotplug callbacks.
154153
* @parallel_wq: The workqueue used for parallel work.
155154
* @serial_wq: The workqueue used for serial work.
156155
* @pslist: List of padata_shell objects attached to this instance.
157156
* @cpumask: User supplied cpumasks for parallel and serial works.
157+
* @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug.
158158
* @kobj: padata instance kernel object.
159159
* @lock: padata instance lock.
160160
* @flags: padata flags.
161161
*/
162162
struct padata_instance {
163-
struct hlist_node cpu_online_node;
164-
struct hlist_node cpu_dead_node;
163+
struct hlist_node cpuhp_node;
165164
struct workqueue_struct *parallel_wq;
166165
struct workqueue_struct *serial_wq;
167166
struct list_head pslist;
168167
struct padata_cpumask cpumask;
168+
cpumask_var_t validate_cpumask;
169169
struct kobject kobj;
170170
struct mutex lock;
171171
u8 flags;

kernel/padata.c

Lines changed: 61 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ static void padata_init_reorder_list(struct parallel_data *pd)
558558
}
559559

560560
/* Allocate and initialize the internal cpumask dependend resources. */
561-
static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
561+
static struct parallel_data *padata_alloc_pd(struct padata_shell *ps,
562+
int offlining_cpu)
562563
{
563564
struct padata_instance *pinst = ps->pinst;
564565
struct parallel_data *pd;
@@ -584,6 +585,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
584585

585586
cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask);
586587
cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask);
588+
if (offlining_cpu >= 0) {
589+
__cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu);
590+
__cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu);
591+
}
587592

588593
padata_init_reorder_list(pd);
589594
padata_init_squeues(pd);
@@ -630,11 +635,11 @@ static void __padata_stop(struct padata_instance *pinst)
630635
}
631636

632637
/* Replace the internal control structure with a new one. */
633-
static int padata_replace_one(struct padata_shell *ps)
638+
static int padata_replace_one(struct padata_shell *ps, int offlining_cpu)
634639
{
635640
struct parallel_data *pd_new;
636641

637-
pd_new = padata_alloc_pd(ps);
642+
pd_new = padata_alloc_pd(ps, offlining_cpu);
638643
if (!pd_new)
639644
return -ENOMEM;
640645

@@ -644,15 +649,15 @@ static int padata_replace_one(struct padata_shell *ps)
644649
return 0;
645650
}
646651

647-
static int padata_replace(struct padata_instance *pinst)
652+
static int padata_replace(struct padata_instance *pinst, int offlining_cpu)
648653
{
649654
struct padata_shell *ps;
650655
int err = 0;
651656

652657
pinst->flags |= PADATA_RESET;
653658

654659
list_for_each_entry(ps, &pinst->pslist, list) {
655-
err = padata_replace_one(ps);
660+
err = padata_replace_one(ps, offlining_cpu);
656661
if (err)
657662
break;
658663
}
@@ -669,9 +674,21 @@ static int padata_replace(struct padata_instance *pinst)
669674

670675
/* If cpumask contains no active cpu, we mark the instance as invalid. */
671676
static bool padata_validate_cpumask(struct padata_instance *pinst,
672-
const struct cpumask *cpumask)
677+
const struct cpumask *cpumask,
678+
int offlining_cpu)
673679
{
674-
if (!cpumask_intersects(cpumask, cpu_online_mask)) {
680+
cpumask_copy(pinst->validate_cpumask, cpu_online_mask);
681+
682+
/*
683+
* @offlining_cpu is still in cpu_online_mask, so remove it here for
684+
* validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where
685+
* @offlining_cpu wouldn't be in the online mask doesn't work because
686+
* padata_cpu_offline() can fail but such a state doesn't allow failure.
687+
*/
688+
if (offlining_cpu >= 0)
689+
__cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask);
690+
691+
if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) {
675692
pinst->flags |= PADATA_INVALID;
676693
return false;
677694
}
@@ -687,21 +704,21 @@ static int __padata_set_cpumasks(struct padata_instance *pinst,
687704
int valid;
688705
int err;
689706

690-
valid = padata_validate_cpumask(pinst, pcpumask);
707+
valid = padata_validate_cpumask(pinst, pcpumask, -1);
691708
if (!valid) {
692709
__padata_stop(pinst);
693710
goto out_replace;
694711
}
695712

696-
valid = padata_validate_cpumask(pinst, cbcpumask);
713+
valid = padata_validate_cpumask(pinst, cbcpumask, -1);
697714
if (!valid)
698715
__padata_stop(pinst);
699716

700717
out_replace:
701718
cpumask_copy(pinst->cpumask.pcpu, pcpumask);
702719
cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
703720

704-
err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst);
721+
err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1);
705722

706723
if (valid)
707724
__padata_start(pinst);
@@ -753,26 +770,6 @@ EXPORT_SYMBOL(padata_set_cpumask);
753770

754771
#ifdef CONFIG_HOTPLUG_CPU
755772

756-
static int __padata_add_cpu(struct padata_instance *pinst, int cpu)
757-
{
758-
int err = padata_replace(pinst);
759-
760-
if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) &&
761-
padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
762-
__padata_start(pinst);
763-
764-
return err;
765-
}
766-
767-
static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
768-
{
769-
if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) ||
770-
!padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
771-
__padata_stop(pinst);
772-
773-
return padata_replace(pinst);
774-
}
775-
776773
static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu)
777774
{
778775
return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) ||
@@ -784,27 +781,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node)
784781
struct padata_instance *pinst;
785782
int ret;
786783

787-
pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node);
784+
pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node);
788785
if (!pinst_has_cpu(pinst, cpu))
789786
return 0;
790787

791788
mutex_lock(&pinst->lock);
792-
ret = __padata_add_cpu(pinst, cpu);
789+
790+
ret = padata_replace(pinst, -1);
791+
792+
if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) &&
793+
padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1))
794+
__padata_start(pinst);
795+
793796
mutex_unlock(&pinst->lock);
794797
return ret;
795798
}
796799

797-
static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node)
800+
static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node)
798801
{
799802
struct padata_instance *pinst;
800803
int ret;
801804

802-
pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node);
805+
pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node);
803806
if (!pinst_has_cpu(pinst, cpu))
804807
return 0;
805808

806809
mutex_lock(&pinst->lock);
807-
ret = __padata_remove_cpu(pinst, cpu);
810+
811+
if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) ||
812+
!padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu))
813+
__padata_stop(pinst);
814+
815+
ret = padata_replace(pinst, cpu);
816+
808817
mutex_unlock(&pinst->lock);
809818
return ret;
810819
}
@@ -815,15 +824,14 @@ static enum cpuhp_state hp_online;
815824
static void __padata_free(struct padata_instance *pinst)
816825
{
817826
#ifdef CONFIG_HOTPLUG_CPU
818-
cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD,
819-
&pinst->cpu_dead_node);
820-
cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node);
827+
cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node);
821828
#endif
822829

823830
WARN_ON(!list_empty(&pinst->pslist));
824831

825832
free_cpumask_var(pinst->cpumask.pcpu);
826833
free_cpumask_var(pinst->cpumask.cbcpu);
834+
free_cpumask_var(pinst->validate_cpumask);
827835
destroy_workqueue(pinst->serial_wq);
828836
destroy_workqueue(pinst->parallel_wq);
829837
kfree(pinst);
@@ -983,18 +991,18 @@ struct padata_instance *padata_alloc(const char *name)
983991

984992
if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL))
985993
goto err_free_serial_wq;
986-
if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) {
987-
free_cpumask_var(pinst->cpumask.pcpu);
988-
goto err_free_serial_wq;
989-
}
994+
if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL))
995+
goto err_free_p_mask;
996+
if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL))
997+
goto err_free_cb_mask;
990998

991999
INIT_LIST_HEAD(&pinst->pslist);
9921000

9931001
cpumask_copy(pinst->cpumask.pcpu, cpu_possible_mask);
9941002
cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask);
9951003

9961004
if (padata_setup_cpumasks(pinst))
997-
goto err_free_masks;
1005+
goto err_free_v_mask;
9981006

9991007
__padata_start(pinst);
10001008

@@ -1003,18 +1011,19 @@ struct padata_instance *padata_alloc(const char *name)
10031011

10041012
#ifdef CONFIG_HOTPLUG_CPU
10051013
cpuhp_state_add_instance_nocalls_cpuslocked(hp_online,
1006-
&pinst->cpu_online_node);
1007-
cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD,
1008-
&pinst->cpu_dead_node);
1014+
&pinst->cpuhp_node);
10091015
#endif
10101016

10111017
cpus_read_unlock();
10121018

10131019
return pinst;
10141020

1015-
err_free_masks:
1016-
free_cpumask_var(pinst->cpumask.pcpu);
1021+
err_free_v_mask:
1022+
free_cpumask_var(pinst->validate_cpumask);
1023+
err_free_cb_mask:
10171024
free_cpumask_var(pinst->cpumask.cbcpu);
1025+
err_free_p_mask:
1026+
free_cpumask_var(pinst->cpumask.pcpu);
10181027
err_free_serial_wq:
10191028
destroy_workqueue(pinst->serial_wq);
10201029
err_put_cpus:
@@ -1057,7 +1066,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst)
10571066
ps->pinst = pinst;
10581067

10591068
cpus_read_lock();
1060-
pd = padata_alloc_pd(ps);
1069+
pd = padata_alloc_pd(ps, -1);
10611070
cpus_read_unlock();
10621071

10631072
if (!pd)
@@ -1106,32 +1115,25 @@ void __init padata_init(void)
11061115
int ret;
11071116

11081117
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online",
1109-
padata_cpu_online, NULL);
1118+
padata_cpu_online, padata_cpu_offline);
11101119
if (ret < 0)
11111120
goto err;
11121121
hp_online = ret;
1113-
1114-
ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead",
1115-
NULL, padata_cpu_dead);
1116-
if (ret < 0)
1117-
goto remove_online_state;
11181122
#endif
11191123

11201124
possible_cpus = num_possible_cpus();
11211125
padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work),
11221126
GFP_KERNEL);
11231127
if (!padata_works)
1124-
goto remove_dead_state;
1128+
goto remove_online_state;
11251129

11261130
for (i = 0; i < possible_cpus; ++i)
11271131
list_add(&padata_works[i].pw_list, &padata_free_works);
11281132

11291133
return;
11301134

1131-
remove_dead_state:
1132-
#ifdef CONFIG_HOTPLUG_CPU
1133-
cpuhp_remove_multi_state(CPUHP_PADATA_DEAD);
11341135
remove_online_state:
1136+
#ifdef CONFIG_HOTPLUG_CPU
11351137
cpuhp_remove_multi_state(hp_online);
11361138
err:
11371139
#endif

0 commit comments

Comments
 (0)