aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2019-04-20 07:27:51 -0400
committerBorislav Petkov <bp@suse.de>2019-06-07 17:18:26 -0400
commitf3c74b38a55aefe1004200d15a83f109b510068c (patch)
treef93b40aeee01dc8be879b50cb1a1000133c63681
parentf2c7c76c5d0a443053e94adb9f0918fa2fb85c3a (diff)
RAS/CEC: Fix binary search function
Switch to using Donald Knuth's binary search algorithm (The Art of Computer Programming, vol. 3, section 6.2.1). This should've been done from the very beginning but the author must've been smoking something very potent at the time. The problem with the current one was that it would return the wrong element index in certain situations: https://lkml.kernel.org/r/CAM_iQpVd02zkVJ846cj-Fg1yUNuz6tY5q1Vpj4LrXmE06dPYYg@mail.gmail.com and the noodling code after the loop was fishy at best. So switch to using Knuth's binary search. The final result is much cleaner and straightforward. Fixes: 011d82611172 ("RAS: Add a Corrected Errors Collector") Reported-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Tony Luck <tony.luck@intel.com> Cc: linux-edac <linux-edac@vger.kernel.org> Cc: <stable@vger.kernel.org>
-rw-r--r--drivers/ras/cec.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c
index 88e4f3ff0cb8..dbfe3e61d2c2 100644
--- a/drivers/ras/cec.c
+++ b/drivers/ras/cec.c
@@ -183,32 +183,38 @@ static void cec_timer_fn(struct timer_list *unused)
183 */ 183 */
184static int __find_elem(struct ce_array *ca, u64 pfn, unsigned int *to) 184static int __find_elem(struct ce_array *ca, u64 pfn, unsigned int *to)
185{ 185{
186 int min = 0, max = ca->n - 1;
186 u64 this_pfn; 187 u64 this_pfn;
187 int min = 0, max = ca->n;
188 188
189 while (min < max) { 189 while (min <= max) {
190 int tmp = (max + min) >> 1; 190 int i = (min + max) >> 1;
191 191
192 this_pfn = PFN(ca->array[tmp]); 192 this_pfn = PFN(ca->array[i]);
193 193
194 if (this_pfn < pfn) 194 if (this_pfn < pfn)
195 min = tmp + 1; 195 min = i + 1;
196 else if (this_pfn > pfn) 196 else if (this_pfn > pfn)
197 max = tmp; 197 max = i - 1;
198 else { 198 else if (this_pfn == pfn) {
199 min = tmp; 199 if (to)
200 break; 200 *to = i;
201
202 return i;
201 } 203 }
202 } 204 }
203 205
206 /*
207 * When the loop terminates without finding @pfn, min has the index of
208 * the element slot where the new @pfn should be inserted. The loop
209 * terminates when min > max, which means the min index points to the
210 * bigger element while the max index to the smaller element, in-between
211 * which the new @pfn belongs to.
212 *
213 * For more details, see exercise 1, Section 6.2.1 in TAOCP, vol. 3.
214 */
204 if (to) 215 if (to)
205 *to = min; 216 *to = min;
206 217
207 this_pfn = PFN(ca->array[min]);
208
209 if (this_pfn == pfn)
210 return min;
211
212 return -ENOKEY; 218 return -ENOKEY;
213} 219}
214 220