]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix potential race condition in _ma_insert
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Mon, 7 Jan 2019 19:45:10 +0000 (14:45 -0500)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Fri, 30 Oct 2020 18:55:08 +0000 (14:55 -0400)
The pivots protect readers from reading invalid data.  Without a wmb
between overwriting the end pivot (of zero), there is a potential that
the writes could be reordered and a race condition would exist between
updating both values and a reader interleaving those writes.

Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
lib/maple_tree.c

index 28643f8aba5ddd8040e9698d1a33ebb1eb4290c4..de7a6b2657fe806a6a4fcd26fce45b39968b3d22 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/maple_tree.h>
 #include <linux/export.h>
 #include <linux/slab.h>
+#include <asm/barrier.h>
 
 #define MA_ROOT_PARENT 1
 
@@ -323,25 +324,31 @@ static int _ma_insert(struct ma_state *ms, void *entry, unsigned char slot)
        if (o_end == slot) { // Appending
                /* zero the new end if the pivot exists. */
                if (n_end < MAPLE_RANGE64_SLOTS - 2)
-                       mr64->pivot[n_end+1] = 0;
+                       mr64->pivot[n_end + 1] = 0;
        } else {
                while (o_end > slot) {
+                       RCU_INIT_POINTER(mr64->slot[n_end],
+                                        mr64->slot[o_end]);
                        if (n_end < MAPLE_RANGE64_SLOTS - 2)
                                mr64->pivot[n_end] = mr64->pivot[o_end];
-                       RCU_INIT_POINTER(mr64->slot[n_end--],
-                                        mr64->slot[o_end--]);
+                       n_end--;
+                       o_end--;
                }
        }
 
-       /* Set the entry value */
-       mr64->pivot[n_end] = ms->last;
-       RCU_INIT_POINTER(mr64->slot[n_end--], entry);
-
-       /* Create a NULL gap, if necessary */
-       if ((ms->index - 1 != mr64->pivot[n_end]) ||
+       RCU_INIT_POINTER(mr64->slot[n_end], entry);
+       if ((ms->index - 1 != mr64->pivot[n_end - 1]) ||
                        (ms->index != ms->last)) {
+               /* Set the entry value */
+               mr64->pivot[n_end--] = ms->last;
+               /* Create a NULL gap */
                RCU_INIT_POINTER(mr64->slot[n_end], NULL);
+               wmb(); /* slot needs to be written before readers can see. */
                mr64->pivot[n_end] = ms->index - 1;
+       } else {
+               wmb(); /* slot needs to be written before readers can see. */
+               /* Set the entry value */
+               mr64->pivot[n_end] = ms->last;
        }
        return added;
 }
@@ -591,7 +598,7 @@ exists:
 void *mas_walk(struct ma_state *ms)
 {
        void *entry = mas_start(ms);
-       unsigned char slot;
+       unsigned char slot = MAPLE_NODE_SLOTS;
 
        /* Outside this nodes range, it doesn't exist. */
        if (ms->min > ms->index ||