summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2019-04-20 13:27:51 +0200
committerBorislav Petkov <bp@suse.de>2019-06-07 23:18:26 +0200
commitf3c74b38a55aefe1004200d15a83f109b510068c (patch)
treef93b40aeee01dc8be879b50cb1a1000133c63681
parentf2c7c76c5d0a443053e94adb9f0918fa2fb85c3a (diff)
downloadlinux-f3c74b38a55aefe1004200d15a83f109b510068c.tar.gz
linux-f3c74b38a55aefe1004200d15a83f109b510068c.tar.bz2
linux-f3c74b38a55aefe1004200d15a83f109b510068c.zip
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)
*/
static int __find_elem(struct ce_array *ca, u64 pfn, unsigned int *to)
{
+ int min = 0, max = ca->n - 1;
u64 this_pfn;
- int min = 0, max = ca->n;
- while (min < max) {
- int tmp = (max + min) >> 1;
+ while (min <= max) {
+ int i = (min + max) >> 1;
- this_pfn = PFN(ca->array[tmp]);
+ this_pfn = PFN(ca->array[i]);
if (this_pfn < pfn)
- min = tmp + 1;
+ min = i + 1;
else if (this_pfn > pfn)
- max = tmp;
- else {
- min = tmp;
- break;
+ max = i - 1;
+ else if (this_pfn == pfn) {
+ if (to)
+ *to = i;
+
+ return i;
}
}
+ /*
+ * When the loop terminates without finding @pfn, min has the index of
+ * the element slot where the new @pfn should be inserted. The loop
+ * terminates when min > max, which means the min index points to the
+ * bigger element while the max index to the smaller element, in-between
+ * which the new @pfn belongs to.
+ *
+ * For more details, see exercise 1, Section 6.2.1 in TAOCP, vol. 3.
+ */
if (to)
*to = min;
- this_pfn = PFN(ca->array[min]);
-
- if (this_pfn == pfn)
- return min;
-
return -ENOKEY;
}