summaryrefslogtreecommitdiff
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
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)
-rw-r--r--gentoo/net-dialup/accel-pptp/accel-pptp-0.8.5.ebuild (renamed from gentoo/net-dialup/accel-pptp/accel-pptp-0.8.4.ebuild)0
-rw-r--r--kernel/driver/gre.c107
-rw-r--r--kernel/driver/pptp.c100
-rwxr-xr-xpppd_plugin/configure2
-rw-r--r--pppd_plugin/configure.in2
-rwxr-xr-xpptpd-1.3.3/configure2
-rw-r--r--pptpd-1.3.3/configure.in2
7 files changed, 128 insertions, 87 deletions
diff --git a/gentoo/net-dialup/accel-pptp/accel-pptp-0.8.4.ebuild b/gentoo/net-dialup/accel-pptp/accel-pptp-0.8.5.ebuild
index 7fe4f73a..7fe4f73a 100644
--- a/gentoo/net-dialup/accel-pptp/accel-pptp-0.8.4.ebuild
+++ b/gentoo/net-dialup/accel-pptp/accel-pptp-0.8.5.ebuild
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)
diff --git a/kernel/driver/pptp.c b/kernel/driver/pptp.c
index 26886249..7e9ba89b 100644
--- a/kernel/driver/pptp.c
+++ b/kernel/driver/pptp.c
@@ -30,9 +30,6 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-#include <linux/semaphore.h>
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#include <asm/bitops.h>
@@ -53,7 +50,7 @@
#include "gre.h"
#endif
-#define PPTP_DRIVER_VERSION "0.8.5"
+#define PPTP_DRIVER_VERSION "0.8.5-rc1"
static int log_level=0;
static int log_packets=10;
@@ -62,8 +59,8 @@ static int log_packets=10;
#define PPP_LCP_ECHOREQ 0x09
#define PPP_LCP_ECHOREP 0x0A
-static unsigned long *callid_bitmap=NULL;
-static struct pppox_sock **callid_sock=NULL;
+static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+static struct pppox_sock **callid_sock;
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
@@ -181,7 +178,7 @@ found_middle:
static rwlock_t chan_lock=RW_LOCK_UNLOCKED;
#define SK_STATE(sk) (sk)->state
#else
-static DECLARE_MUTEX(chan_lock);
+static DEFINE_SPINLOCK(chan_lock);
#define SK_STATE(sk) (sk)->sk_state
#endif
@@ -227,7 +224,7 @@ struct pptp_gre_header {
u32 seq; /* sequence number. Present if S==1 */
u32 ack; /* seq number of highest packet recieved by */
/* sender in this session */
-};
+} __packed;
#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
@@ -270,19 +267,20 @@ static int lookup_chan_dst(u16 call_id, __be32 d_addr)
int i;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
- down(&chan_lock);
+ rcu_read_lock();
#else
- read_lock(&chan_lock);
+ down(&chan_lock);
#endif
- for(i=find_next_bit(callid_bitmap,MAX_CALLID,1); i<MAX_CALLID; i=find_next_bit(callid_bitmap,MAX_CALLID,i+1)){
- sock=callid_sock[i];
- opt=&sock->proto.pptp;
- if (opt->dst_addr.call_id==call_id && opt->dst_addr.sin_addr.s_addr==d_addr) break;
+ for(i = find_next_bit(callid_bitmap,MAX_CALLID,1); i < MAX_CALLID;
+ i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)){
+ sock = callid_sock[i];
+ opt = &sock->proto.pptp;
+ if (opt->dst_addr.call_id == call_id && opt->dst_addr.sin_addr.s_addr == d_addr) break;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
- up(&chan_lock);
+ rcu_read_unlock();
#else
- read_unlock(&chan_lock);
+ up(&chan_lock);
#endif
return i<MAX_CALLID;
@@ -294,8 +292,7 @@ static int add_chan(struct pppox_sock *sock)
int res=-1;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
- synchronize_rcu();
- down(&chan_lock);
+ spin_lock(&chan_lock);
#else
write_lock_bh(&chan_lock);
#endif
@@ -314,13 +311,13 @@ static int add_chan(struct pppox_sock *sock)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id],sock);
#else
- callid_sock[sock->proto.pptp.src_addr.call_id]=sock;
+ callid_sock[sock->proto.pptp.src_addr.call_id] = sock;
#endif
res=0;
exit:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
- up(&chan_lock);
+ spin_unlock(&chan_lock);
#else
write_unlock_bh(&chan_lock);
#endif
@@ -331,17 +328,17 @@ exit:
static void del_chan(struct pppox_sock *sock)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
- synchronize_rcu();
- down(&chan_lock);
+ spin_lock(&chan_lock);
#else
write_lock_bh(&chan_lock);
#endif
clear_bit(sock->proto.pptp.src_addr.call_id,callid_bitmap);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id],NULL);
- up(&chan_lock);
+ spin_unlock(&chan_lock);
+ synchronize_rcu();
#else
- callid_sock[sock->proto.pptp.src_addr.call_id]=NULL;
+ callid_sock[sock->proto.pptp.src_addr.call_id] = NULL;
write_unlock_bh(&chan_lock);
#endif
}
@@ -405,10 +402,11 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
#endif
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
- struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb) ||
+ (skb_cloned(skb) && !skb_clone_writable(skb,0))) {
+ struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
- ip_rt_put(rt);
+ ip_rt_put(rt);
goto tx_error;
}
if (skb->sk)
@@ -699,7 +697,6 @@ static int pptp_rcv(struct sk_buff *skb)
if ((po=lookup_chan(htons(header->call_id),iph->saddr))) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
skb_dst_drop(skb);
- skb_dst_set(skb,NULL);
#else
dst_release(skb->dst);
skb->dst = NULL;
@@ -1141,6 +1138,13 @@ static int __init pptp_init_module(void)
int err=0;
printk(KERN_INFO "PPTP driver version " PPTP_DRIVER_VERSION "\n");
+ callid_sock = __vmalloc((MAX_CALLID + 1) * sizeof(void *),
+ GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ if (!callid_sock) {
+ printk(KERN_ERR "PPTP: cann't allocate memory\n");
+ return -ENOMEM;
+ }
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
inet_add_protocol(&net_pptp_protocol);
#else
@@ -1150,7 +1154,7 @@ static int __init pptp_init_module(void)
if (inet_add_protocol(&net_pptp_protocol, IPPROTO_GRE) < 0) {
#endif
printk(KERN_INFO "PPTP: can't add protocol\n");
- goto out;
+ goto out_free_mem;
}
#endif
@@ -1168,23 +1172,7 @@ static int __init pptp_init_module(void)
goto out_unregister_sk_proto;
}
-
- //assuming PAGESIZE is 4096 bytes
- callid_bitmap=(unsigned long*)__get_free_pages(GFP_KERNEL,1);
- memset(callid_bitmap,0,PAGE_SIZE<<1);
-
- #if (BITS_PER_LONG == 32)
- callid_sock=(struct pppox_sock **)__get_free_pages(GFP_KERNEL,6);
- memset(callid_sock,0,PAGE_SIZE<<6);
- #elif (BITS_PER_LONG == 64)
- callid_sock=(struct pppox_sock **)__get_free_pages(GFP_KERNEL,7);
- memset(callid_sock,0,PAGE_SIZE<<7);
- #else
- #error unknown size of LONG
- #endif
-
-out:
- return err;
+ return 0;
out_unregister_sk_proto:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
proto_unregister(&pptp_sk_proto);
@@ -1203,17 +1191,14 @@ out_inet_del_protocol:
inet_del_protocol(&net_pptp_protocol, IPPROTO_GRE);
#endif
#endif
- goto out;
+out_free_mem:
+ vfree(callid_sock);
+
+ return err;
}
static void __exit pptp_exit_module(void)
{
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- flush_scheduled_tasks();
- #else
- flush_scheduled_work();
- #endif
-
unregister_pppox_proto(PX_PROTO_PPTP);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
inet_del_protocol(&net_pptp_protocol);
@@ -1225,14 +1210,7 @@ static void __exit pptp_exit_module(void)
inet_del_protocol(&net_pptp_protocol, IPPROTO_GRE);
#endif
#endif
- if (callid_bitmap) free_pages((unsigned long)callid_bitmap,1);
- if (callid_sock) {
- #if (BITS_PER_LONG == 32)
- free_pages((unsigned long)callid_sock,6);
- #elif (BITS_PER_LONG == 64)
- free_pages((unsigned long)callid_sock,7);
- #endif
- }
+ vfree(callid_sock);
}
module_init(pptp_init_module);
diff --git a/pppd_plugin/configure b/pppd_plugin/configure
index 3fecbf90..74869a79 100755
--- a/pppd_plugin/configure
+++ b/pppd_plugin/configure
@@ -2236,7 +2236,7 @@ fi
# Define the identity of the package.
PACKAGE=pptp
- VERSION=0.8.4
+ VERSION=0.8.5
cat >>confdefs.h <<_ACEOF
diff --git a/pppd_plugin/configure.in b/pppd_plugin/configure.in
index 6e0e074d..a9d4a441 100644
--- a/pppd_plugin/configure.in
+++ b/pppd_plugin/configure.in
@@ -1,7 +1,7 @@
AC_INIT(configure.in)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(pptp,0.8.4)
+AM_INIT_AUTOMAKE(pptp,0.8.5)
AC_LANG_C
AC_PROG_CC
diff --git a/pptpd-1.3.3/configure b/pptpd-1.3.3/configure
index c8c463eb..98dc1e89 100755
--- a/pptpd-1.3.3/configure
+++ b/pptpd-1.3.3/configure
@@ -2043,7 +2043,7 @@ fi
# Define the identity of the package.
PACKAGE=pptpd
- VERSION=0.8.4
+ VERSION=0.8.5
cat >>confdefs.h <<_ACEOF
diff --git a/pptpd-1.3.3/configure.in b/pptpd-1.3.3/configure.in
index 185963b4..8c4e640c 100644
--- a/pptpd-1.3.3/configure.in
+++ b/pptpd-1.3.3/configure.in
@@ -1,7 +1,7 @@
AC_INIT(configure.in)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(pptpd,0.8.4)
+AM_INIT_AUTOMAKE(pptpd,0.8.5)
AC_DEFINE(BCRELAY,[],"Enable Broadcast Relay")
AC_DEFINE(PPPD_VERSION,[],"PPPD version")