[ovs-dev] [PATCH 2/3] [bug 2462] flex-array: Add memory barriers to flex array updates.

Pravin B Shelar pshelar at nicira.com
Thu Feb 2 14:58:27 UTC 2012


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 <pshelar at nicira.com>
---
 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




More information about the dev mailing list