Following patch adds memory barriers, using RCU APIs, so
that upper layers can use flex array in RCU context
without flex-array pre-allocation.

Signed-off-by: Pravin B Shelar <[email protected]>
---
 datapath/linux/compat/flex_array.c               |   17 ++++++++++-------
 datapath/linux/compat/include/linux/flex_array.h |    4 +++-
 datapath/linux/compat/include/linux/rcupdate.h   |    3 +++
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/datapath/linux/compat/flex_array.c 
b/datapath/linux/compat/flex_array.c
index f2d0cd2..6621bce 100644
--- a/datapath/linux/compat/flex_array.c
+++ b/datapath/linux/compat/flex_array.c
@@ -153,7 +153,7 @@ void flex_array_free_parts(const struct flex_array *fa)
        if (elements_fit_in_base(fa))
                return;
        for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
-               kfree(fa->parts[part_nr]);
+               kfree(rcu_dereference_raw(fa->parts[part_nr]));
 }
 
 void flex_array_free(const struct flex_array *fa)
@@ -175,7 +175,7 @@ static unsigned int index_inside_part(const struct 
flex_array *fa,
 static struct flex_array_part *
 __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
 {
-       struct flex_array_part *part = fa->parts[part_nr];
+       struct flex_array_part *part = rcu_dereference_raw(fa->parts[part_nr]);
        if (!part) {
                part = kmalloc(sizeof(struct flex_array_part), flags);
                if (!part)
@@ -183,7 +183,7 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t 
flags)
                if (!(flags & __GFP_ZERO))
                        memset(part, 0, sizeof(struct flex_array_part));
 
-               fa->parts[part_nr] = part;
+               rcu_assign_pointer(fa->parts[part_nr], part);
        }
        return part;
 }
@@ -225,6 +225,7 @@ int flex_array_put(struct flex_array *fa, unsigned int 
element_nr, void *src,
                        return -ENOMEM;
        }
        dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
+       smp_wmb();
        memcpy(dst, src, fa->element_size);
        return 0;
 }
@@ -250,11 +251,12 @@ int flex_array_clear(struct flex_array *fa, unsigned int 
element_nr)
                part = (struct flex_array_part *)&fa->parts[0];
        else {
                part_nr = fa_element_to_part_nr(fa, element_nr);
-               part = fa->parts[part_nr];
+               part = rcu_dereference_raw(fa->parts[part_nr]);
                if (!part)
                        return -EINVAL;
        }
        dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
+       smp_wmb();
        memset(dst, 0, fa->element_size);
        return 0;
 }
@@ -329,11 +331,12 @@ void *flex_array_get(const struct flex_array *fa, 
unsigned int element_nr)
                return NULL;
        if (element_nr >= fa->total_nr_elements)
                return NULL;
-       if (elements_fit_in_base(fa))
+       if (elements_fit_in_base(fa)) {
+               smp_read_barrier_depends();
                part = (struct flex_array_part *)&fa->parts[0];
-       else {
+       } else {
                part_nr = fa_element_to_part_nr(fa, element_nr);
-               part = fa->parts[part_nr];
+               part = rcu_dereference_raw(fa->parts[part_nr]);
                if (!part)
                        return NULL;
        }
diff --git a/datapath/linux/compat/include/linux/flex_array.h 
b/datapath/linux/compat/include/linux/flex_array.h
index 6fdaef7..334dc46 100644
--- a/datapath/linux/compat/include/linux/flex_array.h
+++ b/datapath/linux/compat/include/linux/flex_array.h
@@ -24,7 +24,7 @@ struct flex_array {
                        int total_nr_elements;
                        int elems_per_part;
                        u32 reciprocal_elems;
-                       struct flex_array_part *parts[];
+                       struct flex_array_part __rcu *parts[];
                };
                /*
                 * This little trick makes sure that
@@ -73,6 +73,8 @@ void flex_array_free(const struct flex_array *fa);
 void flex_array_free_parts(const struct flex_array *fa);
 int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
                gfp_t flags);
+
+#define flex_array_clear rpl_flex_array_clear
 int flex_array_clear(struct flex_array *fa, unsigned int element_nr);
 #define flex_array_get rpl_flex_array_get
 void *flex_array_get(const struct flex_array *fa, unsigned int element_nr);
diff --git a/datapath/linux/compat/include/linux/rcupdate.h 
b/datapath/linux/compat/include/linux/rcupdate.h
index 99459ea..6c486bd 100644
--- a/datapath/linux/compat/include/linux/rcupdate.h
+++ b/datapath/linux/compat/include/linux/rcupdate.h
@@ -18,4 +18,7 @@ static inline int rcu_read_lock_held(void)
 }
 #endif
 
+#ifndef rcu_dereference_raw
+#define rcu_dereference_raw(p) rcu_dereference_check(p, 1)
+#endif
 #endif /* linux/rcupdate.h wrapper */
-- 
1.7.1

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to