summaryrefslogtreecommitdiff
path: root/kernel/driver/gre.c
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2010-08-21 12:53:18 +0400
committerKozlov Dmitry <dima@server>2010-08-21 12:53:38 +0400
commitc9db62c69f26684eb5b00c620d0e182f3e336412 (patch)
treeeb68981248e8afb71ad8b0aff395073a457ce92a /kernel/driver/gre.c
parentc30962027d1bd4e93ffd484f4177dee53a36aa1c (diff)
downloadaccel-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.c107
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)