[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