aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-04-13 04:17:07 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-04-15 06:20:54 -0400
commitea875ec94eafb858990f3fe9528501f983105653 (patch)
tree585e04cb7ea21568d920d753b10c8c3c6adcc4e6
parent6d11b87d55eb75007a3721c2de5938f5bbf607fb (diff)
sparc/sysfs: Replace racy task affinity logic
The mmustat_enable sysfs file accessor functions must run code on the target CPU. This is achieved by temporarily setting the affinity of the calling user space thread to the requested CPU and reset it to the original affinity afterwards. That's racy vs. concurrent affinity settings for that thread resulting in code executing on the wrong CPU and overwriting the new affinity setting. Replace it by using work_on_cpu() which guarantees to run the code on the requested CPU. Protection against CPU hotplug is not required as the open sysfs file already prevents the removal from the CPU offline callback. Using the hotplug protected version would actually be wrong because it would deadlock against a CPU hotplug operation of the CPU associated to the sysfs file in progress. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: David S. Miller <davem@davemloft.net> Cc: fenghua.yu@intel.com Cc: tony.luck@intel.com Cc: herbert@gondor.apana.org.au Cc: rjw@rjwysocki.net Cc: peterz@infradead.org Cc: benh@kernel.crashing.org Cc: bigeasy@linutronix.de Cc: jiangshanlai@gmail.com Cc: sparclinux@vger.kernel.org Cc: viresh.kumar@linaro.org Cc: mpe@ellerman.id.au Cc: tj@kernel.org Cc: lenb@kernel.org Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1704131001270.2408@nanos Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/sparc/kernel/sysfs.c39
1 files changed, 11 insertions, 28 deletions
diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c
index d63fc613e7a9..5fd352b759af 100644
--- a/arch/sparc/kernel/sysfs.c
+++ b/arch/sparc/kernel/sysfs.c
@@ -98,27 +98,7 @@ static struct attribute_group mmu_stat_group = {
98 .name = "mmu_stats", 98 .name = "mmu_stats",
99}; 99};
100 100
101/* XXX convert to rusty's on_one_cpu */ 101static long read_mmustat_enable(void *data __maybe_unused)
102static unsigned long run_on_cpu(unsigned long cpu,
103 unsigned long (*func)(unsigned long),
104 unsigned long arg)
105{
106 cpumask_t old_affinity;
107 unsigned long ret;
108
109 cpumask_copy(&old_affinity, &current->cpus_allowed);
110 /* should return -EINVAL to userspace */
111 if (set_cpus_allowed_ptr(current, cpumask_of(cpu)))
112 return 0;
113
114 ret = func(arg);
115
116 set_cpus_allowed_ptr(current, &old_affinity);
117
118 return ret;
119}
120
121static unsigned long read_mmustat_enable(unsigned long junk)
122{ 102{
123 unsigned long ra = 0; 103 unsigned long ra = 0;
124 104
@@ -127,11 +107,11 @@ static unsigned long read_mmustat_enable(unsigned long junk)
127 return ra != 0; 107 return ra != 0;
128} 108}
129 109
130static unsigned long write_mmustat_enable(unsigned long val) 110static long write_mmustat_enable(void *data)
131{ 111{
132 unsigned long ra, orig_ra; 112 unsigned long ra, orig_ra, *val = data;
133 113
134 if (val) 114 if (*val)
135 ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); 115 ra = __pa(&per_cpu(mmu_stats, smp_processor_id()));
136 else 116 else
137 ra = 0UL; 117 ra = 0UL;
@@ -142,7 +122,8 @@ static unsigned long write_mmustat_enable(unsigned long val)
142static ssize_t show_mmustat_enable(struct device *s, 122static ssize_t show_mmustat_enable(struct device *s,
143 struct device_attribute *attr, char *buf) 123 struct device_attribute *attr, char *buf)
144{ 124{
145 unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); 125 long val = work_on_cpu(s->id, read_mmustat_enable, NULL);
126
146 return sprintf(buf, "%lx\n", val); 127 return sprintf(buf, "%lx\n", val);
147} 128}
148 129
@@ -150,13 +131,15 @@ static ssize_t store_mmustat_enable(struct device *s,
150 struct device_attribute *attr, const char *buf, 131 struct device_attribute *attr, const char *buf,
151 size_t count) 132 size_t count)
152{ 133{
153 unsigned long val, err; 134 unsigned long val;
154 int ret = sscanf(buf, "%lu", &val); 135 long err;
136 int ret;
155 137
138 ret = sscanf(buf, "%lu", &val);
156 if (ret != 1) 139 if (ret != 1)
157 return -EINVAL; 140 return -EINVAL;
158 141
159 err = run_on_cpu(s->id, write_mmustat_enable, val); 142 err = work_on_cpu(s->id, write_mmustat_enable, &val);
160 if (err) 143 if (err)
161 return -EIO; 144 return -EIO;
162 145