aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cpuhotplug.h3
-rw-r--r--kernel/cpu.c60
2 files changed, 61 insertions, 2 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 477b2e6f60f7..6d508767e144 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -22,7 +22,8 @@
22 */ 22 */
23 23
24enum cpuhp_state { 24enum cpuhp_state {
25 CPUHP_OFFLINE, 25 CPUHP_INVALID = -1,
26 CPUHP_OFFLINE = 0,
26 CPUHP_CREATE_THREADS, 27 CPUHP_CREATE_THREADS,
27 CPUHP_PERF_PREPARE, 28 CPUHP_PERF_PREPARE,
28 CPUHP_PERF_X86_PREPARE, 29 CPUHP_PERF_X86_PREPARE,
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 6bbe261b851f..8de11a29e495 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -52,6 +52,7 @@
52struct cpuhp_cpu_state { 52struct cpuhp_cpu_state {
53 enum cpuhp_state state; 53 enum cpuhp_state state;
54 enum cpuhp_state target; 54 enum cpuhp_state target;
55 enum cpuhp_state fail;
55#ifdef CONFIG_SMP 56#ifdef CONFIG_SMP
56 struct task_struct *thread; 57 struct task_struct *thread;
57 bool should_run; 58 bool should_run;
@@ -67,7 +68,9 @@ struct cpuhp_cpu_state {
67#endif 68#endif
68}; 69};
69 70
70static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state); 71static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state) = {
72 .fail = CPUHP_INVALID,
73};
71 74
72#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP) 75#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP)
73static struct lockdep_map cpuhp_state_up_map = 76static struct lockdep_map cpuhp_state_up_map =
@@ -160,6 +163,15 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
160 int (*cb)(unsigned int cpu); 163 int (*cb)(unsigned int cpu);
161 int ret, cnt; 164 int ret, cnt;
162 165
166 if (st->fail == state) {
167 st->fail = CPUHP_INVALID;
168
169 if (!(bringup ? step->startup.single : step->teardown.single))
170 return 0;
171
172 return -EAGAIN;
173 }
174
163 if (!step->multi_instance) { 175 if (!step->multi_instance) {
164 WARN_ON_ONCE(lastp && *lastp); 176 WARN_ON_ONCE(lastp && *lastp);
165 cb = bringup ? step->startup.single : step->teardown.single; 177 cb = bringup ? step->startup.single : step->teardown.single;
@@ -1805,9 +1817,55 @@ static ssize_t show_cpuhp_target(struct device *dev,
1805} 1817}
1806static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); 1818static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target);
1807 1819
1820
1821static ssize_t write_cpuhp_fail(struct device *dev,
1822 struct device_attribute *attr,
1823 const char *buf, size_t count)
1824{
1825 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
1826 struct cpuhp_step *sp;
1827 int fail, ret;
1828
1829 ret = kstrtoint(buf, 10, &fail);
1830 if (ret)
1831 return ret;
1832
1833 /*
1834 * Cannot fail STARTING/DYING callbacks.
1835 */
1836 if (cpuhp_is_atomic_state(fail))
1837 return -EINVAL;
1838
1839 /*
1840 * Cannot fail anything that doesn't have callbacks.
1841 */
1842 mutex_lock(&cpuhp_state_mutex);
1843 sp = cpuhp_get_step(fail);
1844 if (!sp->startup.single && !sp->teardown.single)
1845 ret = -EINVAL;
1846 mutex_unlock(&cpuhp_state_mutex);
1847 if (ret)
1848 return ret;
1849
1850 st->fail = fail;
1851
1852 return count;
1853}
1854
1855static ssize_t show_cpuhp_fail(struct device *dev,
1856 struct device_attribute *attr, char *buf)
1857{
1858 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);
1859
1860 return sprintf(buf, "%d\n", st->fail);
1861}
1862
1863static DEVICE_ATTR(fail, 0644, show_cpuhp_fail, write_cpuhp_fail);
1864
1808static struct attribute *cpuhp_cpu_attrs[] = { 1865static struct attribute *cpuhp_cpu_attrs[] = {
1809 &dev_attr_state.attr, 1866 &dev_attr_state.attr,
1810 &dev_attr_target.attr, 1867 &dev_attr_target.attr,
1868 &dev_attr_fail.attr,
1811 NULL 1869 NULL
1812}; 1870};
1813 1871