Hi,
Paul E. McKenney paulmck@linux.vnet.ibm.com proposed some changes which will reduce the amount of "kfree only" rcu-callback functions. The batman-adv compatibility layer has to add a similar functionality to support older kernels.
I wanted to propose a solution which should be discussed before the kfree_rcu functionality enters Linus' kernel and our master branch.
The amount of kfree_rcu_* function was reduced to support only a maximum offset of 256 to any 'struct rcu_head' inside a struct. This should be enough for the current version and supported architectures. Offsets of 4096 are supported by Paul E. McKenney's implementation, but our workaround would increase the size of the final module too much (personal opinion).
~~~ These patches should *NOT* enter the batman-adv repo right now ~~~~~
Kind regards, Sven
Signed-off-by: Sven Eckelmann sven@narfation.org --- Makefile.kbuild | 2 +- bat_printk.c => compat.c | 0 2 files changed, 1 insertions(+), 1 deletions(-) rename bat_printk.c => compat.c (100%)
diff --git a/Makefile.kbuild b/Makefile.kbuild index 0a35006..d469668 100644 --- a/Makefile.kbuild +++ b/Makefile.kbuild @@ -50,4 +50,4 @@ batman-adv-y += soft-interface.o batman-adv-y += translation-table.o batman-adv-y += unicast.o batman-adv-y += vis.o -batman-adv-y += bat_printk.o +batman-adv-y += compat.o diff --git a/bat_printk.c b/compat.c similarity index 100% rename from bat_printk.c rename to compat.c
On Wednesday 04 May 2011 10:06:29 Sven Eckelmann wrote:
Makefile.kbuild | 2 +- bat_printk.c => compat.c | 0 2 files changed, 1 insertions(+), 1 deletions(-) rename bat_printk.c => compat.c (100%)
Applied in revision adcaaf2.
Thanks, Marek
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat.c | 37 +++++++++++++++++++++++++++++++++++++ compat.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/compat.c b/compat.c index f4561c3..881420f 100644 --- a/compat.c +++ b/compat.c @@ -1,4 +1,7 @@ #include <linux/version.h> +#include <linux/sysfs.h> +#include <linux/netdevice.h> +#include "compat.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
@@ -959,3 +962,37 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...) }
#endif /* < KERNEL_VERSION(2, 6, 29) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1234) + +#define BAT_KFREE_RCU0(n, x) \ + static void bat_kfree_rcu_##n(struct rcu_head *head) \ + {\ + unsigned long offset = (unsigned long)(x);\ + kfree((void *)head - offset);\ + } + +#define BAT_KFREE_RCU1(n,x) BAT_KFREE_RCU0(n##z,x) BAT_KFREE_RCU0(n##o,x+1UL) +#define BAT_KFREE_RCU2(n,x) BAT_KFREE_RCU1(n##z,x) BAT_KFREE_RCU1(n##o,x+2UL) +#define BAT_KFREE_RCU3(n,x) BAT_KFREE_RCU2(n##z,x) BAT_KFREE_RCU2(n##o,x+4UL) +#define BAT_KFREE_RCU4(n,x) BAT_KFREE_RCU3(n##z,x) BAT_KFREE_RCU3(n##o,x+8UL) +#define BAT_KFREE_RCU5(n,x) BAT_KFREE_RCU4(n##z,x) BAT_KFREE_RCU4(n##o,x+16UL) +#define BAT_KFREE_RCU6(n,x) BAT_KFREE_RCU5(n##z,x) BAT_KFREE_RCU5(n##o,x+32UL) +#define BAT_KFREE_RCU7(n,x) BAT_KFREE_RCU6(n##z,x) BAT_KFREE_RCU6(n##o,x+64UL) +#define BAT_KFREE_RCU8(n,x) BAT_KFREE_RCU7(n##z,x) BAT_KFREE_RCU7(n##o,x+128UL) + +BAT_KFREE_RCU8(s, 0UL) + +#define LKRCU0(n) &bat_kfree_rcu_##n +#define LKRCU1(n) LKRCU0(n##z), LKRCU0(n##o) +#define LKRCU2(n) LKRCU1(n##z), LKRCU1(n##o) +#define LKRCU3(n) LKRCU2(n##z), LKRCU2(n##o) +#define LKRCU4(n) LKRCU3(n##z), LKRCU3(n##o) +#define LKRCU5(n) LKRCU4(n##z), LKRCU4(n##o) +#define LKRCU6(n) LKRCU5(n##z), LKRCU5(n##o) +#define LKRCU7(n) LKRCU6(n##z), LKRCU6(n##o) +#define LKRCU8(n) LKRCU7(n##z), LKRCU7(n##o) + +bat_rcu_callback bat_kfree_rcu_offset[_BAT_MAX_KFREE_RCU_OFFSET] = {LKRCU8(s)}; + +#endif /* < KERNEL_VERSION(2, 6, 1234) */ diff --git a/compat.h b/compat.h index 0c5ad82..59bd752 100644 --- a/compat.h +++ b/compat.h @@ -288,4 +288,32 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...);
#endif /* < KERNEL_VERSION(2, 6, 36) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1234) + +#define _BAT_MAX_KFREE_RCU_OFFSET 256 +typedef void (*bat_rcu_callback)(struct rcu_head *); +extern bat_rcu_callback bat_kfree_rcu_offset[_BAT_MAX_KFREE_RCU_OFFSET]; + +static __always_inline bool __is_kfree_rcu_offset(unsigned long offset) +{ + return offset < _BAT_MAX_KFREE_RCU_OFFSET; +} + +static __always_inline +void __kfree_rcu(struct rcu_head *head, unsigned long offset) +{ + BUILD_BUG_ON(!__builtin_constant_p(offset)); + BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); + + call_rcu(head, (bat_rcu_callback)bat_kfree_rcu_offset[offset]); +} + +extern void kfree(const void *); + +#define kfree_rcu(ptr, rcu_head) \ + __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) + + +#endif /* < KERNEL_VERSION(2, 6, 1234) */ + #endif /* _NET_BATMAN_ADV_COMPAT_H_ */
On Wednesday 04 May 2011 10:06:30 Sven Eckelmann wrote:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1234)
+#define BAT_KFREE_RCU0(n, x) \
static void bat_kfree_rcu_##n(struct rcu_head *head) \
{\
unsigned long offset = (unsigned long)(x);\
kfree((void *)head - offset);\
}
+#define BAT_KFREE_RCU1(n,x) BAT_KFREE_RCU0(n##z,x) BAT_KFREE_RCU0(n##o,x+1UL) +#define BAT_KFREE_RCU2(n,x) BAT_KFREE_RCU1(n##z,x) BAT_KFREE_RCU1(n##o,x+2UL) +#define BAT_KFREE_RCU3(n,x) BAT_KFREE_RCU2(n##z,x) BAT_KFREE_RCU2(n##o,x+4UL) +#define BAT_KFREE_RCU4(n,x) BAT_KFREE_RCU3(n##z,x) BAT_KFREE_RCU3(n##o,x+8UL) +#define BAT_KFREE_RCU5(n,x) BAT_KFREE_RCU4(n##z,x) BAT_KFREE_RCU4(n##o,x+16UL) +#define BAT_KFREE_RCU6(n,x) BAT_KFREE_RCU5(n##z,x) BAT_KFREE_RCU5(n##o,x+32UL) +#define BAT_KFREE_RCU7(n,x) BAT_KFREE_RCU6(n##z,x) BAT_KFREE_RCU6(n##o,x+64UL) +#define BAT_KFREE_RCU8(n,x) BAT_KFREE_RCU7(n##z,x) BAT_KFREE_RCU7(n##o,x+128UL)
How about something like this (in compat.h):
static void free_rcu_gw_node(struct rcu_head *rcu) { struct gw_node *gw_node;
gw_node = container_of(rcu, struct gw_node, rcu); kfree(gw_node); }
#define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, free_rcu_##ptr);
Disclaimer: This is a proof of concept to convey the idea - I did not even try to compile this code.
Obviously, we would need an extra function for each kfree_rcu() call.
Regards, Marek
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat.c | 30 +++++++++++++++++++++++++++++- compat.h | 10 ++++++++++ 2 files changed, 39 insertions(+), 1 deletions(-)
diff --git a/compat.c b/compat.c index f4561c3..67c5126 100644 --- a/compat.c +++ b/compat.c @@ -1,4 +1,4 @@ -#include <linux/version.h> +#include "main.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
@@ -959,3 +959,31 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...) }
#endif /* < KERNEL_VERSION(2, 6, 29) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1234) + +void free_rcu_gw_node(struct rcu_head *rcu) +{ + struct gw_node *gw_node; + + gw_node = container_of(rcu, struct gw_node, rcu); + kfree(gw_node); +} + +void free_rcu_neigh_node(struct rcu_head *rcu) +{ + struct neigh_node *neigh_node; + + neigh_node = container_of(rcu, struct neigh_node, rcu); + kfree(neigh_node); +} + +void free_rcu_softif_neigh(struct rcu_head *rcu) +{ + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(rcu, struct softif_neigh, rcu); + kfree(softif_neigh); +} + +#endif /* < KERNEL_VERSION(2, 6, 1234) */ diff --git a/compat.h b/compat.h index c3fd2cd..62fd968 100644 --- a/compat.h +++ b/compat.h @@ -291,4 +291,14 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...);
#endif /* < KERNEL_VERSION(2, 6, 36) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1234) + +#define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, free_rcu_##ptr) + +void free_rcu_gw_node(struct rcu_head *rcu); +void free_rcu_neigh_node(struct rcu_head *rcu); +void free_rcu_softif_neigh(struct rcu_head *rcu); + +#endif /* < KERNEL_VERSION(2, 6, 1234) */ + #endif /* _NET_BATMAN_ADV_COMPAT_H_ */
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback gw_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Cc: Sven Eckelmann sven@narfation.org Acked-by: David S. Miller davem@davemloft.net Signed-off-by: Sven Eckelmann sven@narfation.org --- gateway_client.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/gateway_client.c b/gateway_client.c index 65f3953..61605a0 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -29,18 +29,10 @@ #include <linux/udp.h> #include <linux/if_vlan.h>
-static void gw_node_free_rcu(struct rcu_head *rcu) -{ - struct gw_node *gw_node; - - gw_node = container_of(rcu, struct gw_node, rcu); - kfree(gw_node); -} - static void gw_node_free_ref(struct gw_node *gw_node) { if (atomic_dec_and_test(&gw_node->refcount)) - call_rcu(&gw_node->rcu, gw_node_free_rcu); + kfree_rcu(gw_node, rcu); }
static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback neigh_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Cc: Sven Eckelmann sven@narfation.org Acked-by: David S. Miller davem@davemloft.net Signed-off-by: Sven Eckelmann sven@narfation.org --- originator.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/originator.c b/originator.c index ef4a9be..05cc738 100644 --- a/originator.c +++ b/originator.c @@ -56,18 +56,10 @@ err: return 0; }
-static void neigh_node_free_rcu(struct rcu_head *rcu) -{ - struct neigh_node *neigh_node; - - neigh_node = container_of(rcu, struct neigh_node, rcu); - kfree(neigh_node); -} - void neigh_node_free_ref(struct neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount)) - call_rcu(&neigh_node->rcu, neigh_node_free_rcu); + kfree_rcu(neigh_node, rcu); }
/* increases the refcounter of a found router */
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback softif_neigh_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Cc: Sven Eckelmann sven@narfation.org Acked-by: David S. Miller davem@davemloft.net Signed-off-by: Sven Eckelmann sven@narfation.org --- soft-interface.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/soft-interface.c b/soft-interface.c index 9e5fcd1..85ae42d 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -72,18 +72,10 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) return 0; }
-static void softif_neigh_free_rcu(struct rcu_head *rcu) -{ - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(rcu, struct softif_neigh, rcu); - kfree(softif_neigh); -} - static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) { if (atomic_dec_and_test(&softif_neigh->refcount)) - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + kfree_rcu(softif_neigh, rcu); }
static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv)
Signed-off-by: Sven Eckelmann sven@narfation.org --- Rebased on top of current master + newest version from Paul E. McKenney
compat.c | 28 ++++++++++++++++++++++++++++ compat.h | 10 ++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/compat.c b/compat.c index 586898f..e040486 100644 --- a/compat.c +++ b/compat.c @@ -988,3 +988,31 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...) }
#endif /* < KERNEL_VERSION(2, 6, 29) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 40) + +void free_rcu_gw_node(struct rcu_head *rcu) +{ + struct gw_node *gw_node; + + gw_node = container_of(rcu, struct gw_node, rcu); + kfree(gw_node); +} + +void free_rcu_neigh_node(struct rcu_head *rcu) +{ + struct neigh_node *neigh_node; + + neigh_node = container_of(rcu, struct neigh_node, rcu); + kfree(neigh_node); +} + +void free_rcu_softif_neigh(struct rcu_head *rcu) +{ + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(rcu, struct softif_neigh, rcu); + kfree(softif_neigh); +} + +#endif /* < KERNEL_VERSION(2, 6, 40) */ diff --git a/compat.h b/compat.h index fb49f9d..2e3f062 100644 --- a/compat.h +++ b/compat.h @@ -273,4 +273,14 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...);
#endif /* < KERNEL_VERSION(2, 6, 36) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 40) + +#define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, free_rcu_##ptr) + +void free_rcu_gw_node(struct rcu_head *rcu); +void free_rcu_neigh_node(struct rcu_head *rcu); +void free_rcu_softif_neigh(struct rcu_head *rcu); + +#endif /* < KERNEL_VERSION(2, 6, 40) */ + #endif /* _NET_BATMAN_ADV_COMPAT_H_ */
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback gw_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org --- Rebased on top of current master + newest version from Paul E. McKenney
gateway_client.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/gateway_client.c b/gateway_client.c index 65f3953..61605a0 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -29,18 +29,10 @@ #include <linux/udp.h> #include <linux/if_vlan.h>
-static void gw_node_free_rcu(struct rcu_head *rcu) -{ - struct gw_node *gw_node; - - gw_node = container_of(rcu, struct gw_node, rcu); - kfree(gw_node); -} - static void gw_node_free_ref(struct gw_node *gw_node) { if (atomic_dec_and_test(&gw_node->refcount)) - call_rcu(&gw_node->rcu, gw_node_free_rcu); + kfree_rcu(gw_node, rcu); }
static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
Sven Eckelmann wrote:
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback gw_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org
Linus applied it in eb340b2f804860a51a0b92e35fd36742b6c2d6b7
Applied in 9f517fb3
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback neigh_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org --- Rebased on top of current master + newest version from Paul E. McKenney
originator.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/originator.c b/originator.c index 080ec88..40a30bb 100644 --- a/originator.c +++ b/originator.c @@ -54,18 +54,10 @@ err: return 0; }
-static void neigh_node_free_rcu(struct rcu_head *rcu) -{ - struct neigh_node *neigh_node; - - neigh_node = container_of(rcu, struct neigh_node, rcu); - kfree(neigh_node); -} - void neigh_node_free_ref(struct neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount)) - call_rcu(&neigh_node->rcu, neigh_node_free_rcu); + kfree_rcu(neigh_node, rcu); }
/* increases the refcounter of a found router */
Sven Eckelmann wrote:
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback neigh_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org
Linus applied it in ae179ae433bb4ef6b6179c5c1c7b6cc7dc01c670
Applied in 178a37e6f
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback softif_neigh_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org --- Rebased on top of current master + newest version from Paul E. McKenney
soft-interface.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/soft-interface.c b/soft-interface.c index c76a33e..d5aa609 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -72,18 +72,10 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) return 0; }
-static void softif_neigh_free_rcu(struct rcu_head *rcu) -{ - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(rcu, struct softif_neigh, rcu); - kfree(softif_neigh); -} - static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) { if (atomic_dec_and_test(&softif_neigh->refcount)) - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + kfree_rcu(softif_neigh, rcu); }
static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
Sven Eckelmann wrote:
From: Paul E. McKenney paulmck@linux.vnet.ibm.com
The RCU callback softif_neigh_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu().
Signed-off-by: Paul E. McKenney paulmck@linux.vnet.ibm.com Cc: Marek Lindner lindner_marek@yahoo.de Cc: Simon Wunderlich siwu@hrz.tu-chemnitz.de Acked-by: David S. Miller davem@davemloft.net Reviewed-by: Josh Triplett josh@joshtriplett.org Signed-off-by: Sven Eckelmann sven@narfation.org
Linus applied it in 8e3572cff70ee19a0a1f2e2dde0bca0b7c8b54dc
Applied in 8bd9620
Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
Rebased on top of current master + newest version from Paul E. McKenney
Applied in 903ca65
b.a.t.m.a.n@lists.open-mesh.org