diff options
| author | Kozlov Dmitry <dima@server> | 2010-08-21 12:53:18 +0400 |
|---|---|---|
| committer | Kozlov Dmitry <dima@server> | 2010-08-21 12:53:38 +0400 |
| commit | c9db62c69f26684eb5b00c620d0e182f3e336412 (patch) | |
| tree | eb68981248e8afb71ad8b0aff395073a457ce92a /kernel/driver/gre.c | |
| parent | c30962027d1bd4e93ffd484f4177dee53a36aa1c (diff) | |
| download | accel-ppp-c9db62c69f26684eb5b00c620d0e182f3e336412.tar.gz accel-ppp-c9db62c69f26684eb5b00c620d0e182f3e336412.zip | |
* use rcu + spin_lock in gre module for 2.6 kernel
* use rcu + spin_lock instead of rcu + semaphone in pptp module
* fixed incorrect rcu_synchronize() place
* use static bitmap (DECLARE_BITMAP) instead of dynamically allocated
* use vmalloc for callid_sock memory allocation instead of BITS_PER_LONG + __get_free_pages
* avoid copying writable clones (thanks to theMIROn)
Diffstat (limited to 'kernel/driver/gre.c')
| -rw-r--r-- | kernel/driver/gre.c | 107 |
1 files changed, 85 insertions, 22 deletions
diff --git a/kernel/driver/gre.c b/kernel/driver/gre.c index cda0576b..485da85d 100644 --- a/kernel/driver/gre.c +++ b/kernel/driver/gre.c @@ -10,50 +10,83 @@ #include "gre.h" - struct gre_protocol *gre_proto[GREPROTO_MAX] ____cacheline_aligned_in_smp; -static DEFINE_RWLOCK(gre_proto_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +static rwlock_t chan_lock=RW_LOCK_UNLOCKED; +#else +static DEFINE_SPINLOCK(gre_proto_lock); +#endif int gre_add_protocol(struct gre_protocol *proto, u8 version) { int ret; if (version >= GREPROTO_MAX) - return -1; + return -EINVAL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_lock_bh(&gre_proto_lock); +#else + spin_lock(&gre_proto_lock); +#endif if (gre_proto[version]) { - ret = -1; + ret = -EAGAIN; } else { - gre_proto[version]=proto; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + gre_proto[version] = proto; +#else + rcu_assign_pointer(gre_proto[version], proto); +#endif ret = 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_unlock_bh(&gre_proto_lock); +#else + spin_unlock(&gre_proto_lock); +#endif return ret; } int gre_del_protocol(struct gre_protocol *proto, u8 version) { - int ret; - if (version >= GREPROTO_MAX) - return -1; + goto out_err; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_lock_bh(&gre_proto_lock); - if (gre_proto[version] == proto) { +#else + spin_lock(&gre_proto_lock); +#endif + if (gre_proto[version] == proto) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) gre_proto[version] = NULL; - ret = 0; - } else { - ret = -1; - } +#else + rcu_assign_pointer(gre_proto[version], NULL); +#endif + else + goto out_err_unlock; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_unlock_bh(&gre_proto_lock); +#else + spin_unlock(&gre_proto_lock); + synchronize_rcu(); +#endif + return 0; - return ret; +out_err_unlock: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + write_unlock_bh(&gre_proto_lock); +#else + spin_unlock(&gre_proto_lock); +#endif +out_err: + return -EINVAL; } static int gre_rcv(struct sk_buff *skb) { u8 ver; int ret; + struct gre_protocol *proto; if (!pskb_may_pull(skb, 12)) goto drop_nolock; @@ -62,17 +95,32 @@ static int gre_rcv(struct sk_buff *skb) if (ver >= GREPROTO_MAX) goto drop_nolock; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_lock(&gre_proto_lock); - if (!gre_proto[ver] || !gre_proto[ver]->handler) + proto = gre_proto[ver]; +#else + rcu_read_lock(); + proto = rcu_dereference(gre_proto[ver]); +#endif + if (!proto || !proto->handler) goto drop; - ret = gre_proto[ver]->handler(skb); + ret = proto->handler(skb); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); +#else + rcu_read_unlock(); +#endif return ret; drop: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); +#else + rcu_read_unlock(); +#endif drop_nolock: kfree_skb(skb); return NET_RX_DROP; @@ -80,27 +128,40 @@ drop_nolock: static void gre_err(struct sk_buff *skb, u32 info) { u8 ver; - - printk("err\n"); + struct gre_protocol *proto; if (!pskb_may_pull(skb, 12)) goto drop_nolock; - ver=skb->data[1]; + ver=skb->data[1]&0x7f; if (ver>=GREPROTO_MAX) goto drop_nolock; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_lock(&gre_proto_lock); - if (!gre_proto[ver] || !gre_proto[ver]->err_handler) + proto = gre_proto[ver]; +#else + rcu_read_lock(); + proto = rcu_dereference(gre_proto[ver]); +#endif + if (!proto || !proto->err_handler) goto drop; - gre_proto[ver]->err_handler(skb,info); + proto->err_handler(skb, info); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); +#else + rcu_read_unlock(); +#endif return; drop: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); +#else + rcu_read_unlock(); +#endif drop_nolock: kfree_skb(skb); } @@ -109,7 +170,9 @@ drop_nolock: static struct net_protocol net_gre_protocol = { .handler = gre_rcv, .err_handler = gre_err, -// .netns_ok=1, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) + .netns_ok=1, +#endif }; static int __init gre_init(void) |
