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
