Commit 913f2d79 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

parents fe3f2053 73d4f84f
...@@ -68,8 +68,8 @@ ...@@ -68,8 +68,8 @@
#define DRV_MODULE_NAME "tg3" #define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "3.43" #define DRV_MODULE_VERSION "3.44"
#define DRV_MODULE_RELDATE "Oct 24, 2005" #define DRV_MODULE_RELDATE "Dec 6, 2005"
#define TG3_DEF_MAC_MODE 0 #define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0 #define TG3_DEF_RX_MODE 0
...@@ -3565,12 +3565,15 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3565,12 +3565,15 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!spin_trylock(&tp->tx_lock)) if (!spin_trylock(&tp->tx_lock))
return NETDEV_TX_LOCKED; return NETDEV_TX_LOCKED;
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
netif_stop_queue(dev); if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
/* This is a hard error, log it. */
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
"queue awake!\n", dev->name);
}
spin_unlock(&tp->tx_lock); spin_unlock(&tp->tx_lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
......
...@@ -670,6 +670,9 @@ enum { ...@@ -670,6 +670,9 @@ enum {
NET_DECNET_DST_GC_INTERVAL = 9, NET_DECNET_DST_GC_INTERVAL = 9,
NET_DECNET_CONF = 10, NET_DECNET_CONF = 10,
NET_DECNET_NO_FC_MAX_CWND = 11, NET_DECNET_NO_FC_MAX_CWND = 11,
NET_DECNET_MEM = 12,
NET_DECNET_RMEM = 13,
NET_DECNET_WMEM = 14,
NET_DECNET_DEBUG_LEVEL = 255 NET_DECNET_DEBUG_LEVEL = 255
}; };
......
...@@ -234,4 +234,8 @@ extern int decnet_di_count; ...@@ -234,4 +234,8 @@ extern int decnet_di_count;
extern int decnet_dr_count; extern int decnet_dr_count;
extern int decnet_no_fc_max_cwnd; extern int decnet_no_fc_max_cwnd;
extern int sysctl_decnet_mem[3];
extern int sysctl_decnet_wmem[3];
extern int sysctl_decnet_rmem[3];
#endif /* _NET_DN_H */ #endif /* _NET_DN_H */
...@@ -1113,7 +1113,8 @@ out: ...@@ -1113,7 +1113,8 @@ out:
void netdev_rx_csum_fault(struct net_device *dev) void netdev_rx_csum_fault(struct net_device *dev)
{ {
if (net_ratelimit()) { if (net_ratelimit()) {
printk(KERN_ERR "%s: hw csum failure.\n", dev->name); printk(KERN_ERR "%s: hw csum failure.\n",
dev ? dev->name : "<unknown>");
dump_stack(); dump_stack();
} }
} }
......
...@@ -1725,7 +1725,7 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, ...@@ -1725,7 +1725,7 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
* of the skb if any page alloc fails user this procedure returns -ENOMEM * of the skb if any page alloc fails user this procedure returns -ENOMEM
*/ */
int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
int getfrag(void *from, char *to, int offset, int (*getfrag)(void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb), int len, int odd, struct sk_buff *skb),
void *from, int length) void *from, int length)
{ {
......
...@@ -153,6 +153,7 @@ static struct proto_ops dn_proto_ops; ...@@ -153,6 +153,7 @@ static struct proto_ops dn_proto_ops;
static DEFINE_RWLOCK(dn_hash_lock); static DEFINE_RWLOCK(dn_hash_lock);
static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
static struct hlist_head dn_wild_sk; static struct hlist_head dn_wild_sk;
static atomic_t decnet_memory_allocated;
static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags); static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags);
static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags); static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags);
...@@ -446,10 +447,26 @@ static void dn_destruct(struct sock *sk) ...@@ -446,10 +447,26 @@ static void dn_destruct(struct sock *sk)
dst_release(xchg(&sk->sk_dst_cache, NULL)); dst_release(xchg(&sk->sk_dst_cache, NULL));
} }
static int dn_memory_pressure;
static void dn_enter_memory_pressure(void)
{
if (!dn_memory_pressure) {
dn_memory_pressure = 1;
}
}
static struct proto dn_proto = { static struct proto dn_proto = {
.name = "DECNET", .name = "NSP",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.obj_size = sizeof(struct dn_sock), .enter_memory_pressure = dn_enter_memory_pressure,
.memory_pressure = &dn_memory_pressure,
.memory_allocated = &decnet_memory_allocated,
.sysctl_mem = sysctl_decnet_mem,
.sysctl_wmem = sysctl_decnet_wmem,
.sysctl_rmem = sysctl_decnet_rmem,
.max_header = DN_MAX_NSP_DATA_HEADER + 64,
.obj_size = sizeof(struct dn_sock),
}; };
static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp) static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
...@@ -470,6 +487,8 @@ static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp) ...@@ -470,6 +487,8 @@ static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
sk->sk_family = PF_DECnet; sk->sk_family = PF_DECnet;
sk->sk_protocol = 0; sk->sk_protocol = 0;
sk->sk_allocation = gfp; sk->sk_allocation = gfp;
sk->sk_sndbuf = sysctl_decnet_wmem[1];
sk->sk_rcvbuf = sysctl_decnet_rmem[1];
/* Initialization of DECnet Session Control Port */ /* Initialization of DECnet Session Control Port */
scp = DN_SK(sk); scp = DN_SK(sk);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* *
* Changes: * Changes:
* Steve Whitehouse - C99 changes and default device handling * Steve Whitehouse - C99 changes and default device handling
* Steve Whitehouse - Memory buffer settings, like the tcp ones
* *
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -37,6 +38,11 @@ int decnet_dr_count = 3; ...@@ -37,6 +38,11 @@ int decnet_dr_count = 3;
int decnet_log_martians = 1; int decnet_log_martians = 1;
int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW; int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
/* Reasonable defaults, I hope, based on tcp's defaults */
int sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
extern int decnet_dst_gc_interval; extern int decnet_dst_gc_interval;
static int min_decnet_time_wait[] = { 5 }; static int min_decnet_time_wait[] = { 5 };
...@@ -428,6 +434,33 @@ static ctl_table dn_table[] = { ...@@ -428,6 +434,33 @@ static ctl_table dn_table[] = {
.extra1 = &min_decnet_no_fc_max_cwnd, .extra1 = &min_decnet_no_fc_max_cwnd,
.extra2 = &max_decnet_no_fc_max_cwnd .extra2 = &max_decnet_no_fc_max_cwnd
}, },
{
.ctl_name = NET_DECNET_MEM,
.procname = "decnet_mem",
.data = &sysctl_decnet_mem,
.maxlen = sizeof(sysctl_decnet_mem),
.mode = 0644,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
},
{
.ctl_name = NET_DECNET_RMEM,
.procname = "decnet_rmem",
.data = &sysctl_decnet_rmem,
.maxlen = sizeof(sysctl_decnet_rmem),
.mode = 0644,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
},
{
.ctl_name = NET_DECNET_WMEM,
.procname = "decnet_wmem",
.data = &sysctl_decnet_wmem,
.maxlen = sizeof(sysctl_decnet_wmem),
.mode = 0644,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
},
{ {
.ctl_name = NET_DECNET_DEBUG_LEVEL, .ctl_name = NET_DECNET_DEBUG_LEVEL,
.procname = "debug", .procname = "debug",
......
...@@ -56,8 +56,8 @@ config IP_NF_CONNTRACK_MARK ...@@ -56,8 +56,8 @@ config IP_NF_CONNTRACK_MARK
instead of the individual packets. instead of the individual packets.
config IP_NF_CONNTRACK_EVENTS config IP_NF_CONNTRACK_EVENTS
bool "Connection tracking events" bool "Connection tracking events (EXPERIMENTAL)"
depends on IP_NF_CONNTRACK depends on EXPERIMENTAL && IP_NF_CONNTRACK
help help
If this option is enabled, the connection tracking code will If this option is enabled, the connection tracking code will
provide a notifier chain that can be used by other kernel code provide a notifier chain that can be used by other kernel code
...@@ -66,8 +66,8 @@ config IP_NF_CONNTRACK_EVENTS ...@@ -66,8 +66,8 @@ config IP_NF_CONNTRACK_EVENTS
IF unsure, say `N'. IF unsure, say `N'.
config IP_NF_CONNTRACK_NETLINK config IP_NF_CONNTRACK_NETLINK
tristate 'Connection tracking netlink interface' tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
depends on IP_NF_CONNTRACK && NETFILTER_NETLINK depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK
depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
help help
This option enables support for a netlink-based userspace interface This option enables support for a netlink-based userspace interface
......
...@@ -1345,6 +1345,11 @@ static int kill_all(struct ip_conntrack *i, void *data) ...@@ -1345,6 +1345,11 @@ static int kill_all(struct ip_conntrack *i, void *data)
return 1; return 1;
} }
void ip_conntrack_flush(void)
{
ip_ct_iterate_cleanup(kill_all, NULL);
}
static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size) static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size)
{ {
if (vmalloced) if (vmalloced)
...@@ -1354,8 +1359,12 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size) ...@@ -1354,8 +1359,12 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size)
get_order(sizeof(struct list_head) * size)); get_order(sizeof(struct list_head) * size));
} }
void ip_conntrack_flush(void) /* Mishearing the voices in his head, our hero wonders how he's
supposed to kill the mall. */
void ip_conntrack_cleanup(void)
{ {
ip_ct_attach = NULL;
/* This makes sure all current packets have passed through /* This makes sure all current packets have passed through
netfilter framework. Roll on, two-stage module netfilter framework. Roll on, two-stage module
delete... */ delete... */
...@@ -1363,7 +1372,7 @@ void ip_conntrack_flush(void) ...@@ -1363,7 +1372,7 @@ void ip_conntrack_flush(void)
ip_ct_event_cache_flush(); ip_ct_event_cache_flush();
i_see_dead_people: i_see_dead_people:
ip_ct_iterate_cleanup(kill_all, NULL); ip_conntrack_flush();
if (atomic_read(&ip_conntrack_count) != 0) { if (atomic_read(&ip_conntrack_count) != 0) {
schedule(); schedule();
goto i_see_dead_people; goto i_see_dead_people;
...@@ -1371,14 +1380,7 @@ void ip_conntrack_flush(void) ...@@ -1371,14 +1380,7 @@ void ip_conntrack_flush(void)
/* wait until all references to ip_conntrack_untracked are dropped */ /* wait until all references to ip_conntrack_untracked are dropped */
while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1) while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1)
schedule(); schedule();
}
/* Mishearing the voices in his head, our hero wonders how he's
supposed to kill the mall. */
void ip_conntrack_cleanup(void)
{
ip_ct_attach = NULL;
ip_conntrack_flush();
kmem_cache_destroy(ip_conntrack_cachep); kmem_cache_destroy(ip_conntrack_cachep);
kmem_cache_destroy(ip_conntrack_expect_cachep); kmem_cache_destroy(ip_conntrack_expect_cachep);
free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc, free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc,
......
...@@ -503,7 +503,7 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) ...@@ -503,7 +503,7 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
} }
static const size_t cta_min_proto[CTA_PROTO_MAX] = { static const size_t cta_min_proto[CTA_PROTO_MAX] = {
[CTA_PROTO_NUM-1] = sizeof(u_int16_t), [CTA_PROTO_NUM-1] = sizeof(u_int8_t),
[CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t),
[CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t), [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t),
[CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
...@@ -528,7 +528,7 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr, ...@@ -528,7 +528,7 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
if (!tb[CTA_PROTO_NUM-1]) if (!tb[CTA_PROTO_NUM-1])
return -EINVAL; return -EINVAL;
tuple->dst.protonum = *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
proto = ip_conntrack_proto_find_get(tuple->dst.protonum); proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
...@@ -728,11 +728,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ...@@ -728,11 +728,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT; return -ENOENT;
} }
} }
if (del_timer(&ct->timeout)) { if (del_timer(&ct->timeout))
ip_conntrack_put(ct);
ct->timeout.function((unsigned long)ct); ct->timeout.function((unsigned long)ct);
return 0;
}
ip_conntrack_put(ct); ip_conntrack_put(ct);
DEBUGP("leaving\n"); DEBUGP("leaving\n");
...@@ -877,7 +875,7 @@ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) ...@@ -877,7 +875,7 @@ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
DEBUGP("NAT status: %lu\n", DEBUGP("NAT status: %lu\n",
status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
if (ip_nat_initialized(ct, hooknum)) if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
return -EEXIST; return -EEXIST;
ip_nat_setup_info(ct, &range, hooknum); ip_nat_setup_info(ct, &range, hooknum);
......
...@@ -341,9 +341,10 @@ static int tcp_print_conntrack(struct seq_file *s, ...@@ -341,9 +341,10 @@ static int tcp_print_conntrack(struct seq_file *s,
static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
const struct ip_conntrack *ct) const struct ip_conntrack *ct)
{ {
struct nfattr *nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); struct nfattr *nest_parms;
read_lock_bh(&tcp_lock); read_lock_bh(&tcp_lock);
nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
&ct->proto.tcp.state); &ct->proto.tcp.state);
read_unlock_bh(&tcp_lock); read_unlock_bh(&tcp_lock);
......
This diff is collapsed.
...@@ -215,14 +215,6 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, ...@@ -215,14 +215,6 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
vegas->beg_snd_nxt = tp->snd_nxt; vegas->beg_snd_nxt = tp->snd_nxt;
vegas->beg_snd_cwnd = tp->snd_cwnd; vegas->beg_snd_cwnd = tp->snd_cwnd;
/* Take into account the current RTT sample too, to
* decrease the impact of delayed acks. This double counts
* this sample since we count it for the next window as well,
* but that's not too awful, since we're taking the min,
* rather than averaging.
*/
tcp_vegas_rtt_calc(sk, seq_rtt * 1000);
/* We do the Vegas calculations only if we got enough RTT /* We do the Vegas calculations only if we got enough RTT
* samples that we can be reasonably sure that we got * samples that we can be reasonably sure that we got
* at least one RTT sample that wasn't from a delayed ACK. * at least one RTT sample that wasn't from a delayed ACK.
...@@ -333,11 +325,11 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, ...@@ -333,11 +325,11 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
else if (tp->snd_cwnd > tp->snd_cwnd_clamp) else if (tp->snd_cwnd > tp->snd_cwnd_clamp)
tp->snd_cwnd = tp->snd_cwnd_clamp; tp->snd_cwnd = tp->snd_cwnd_clamp;
} }
}
/* Wipe the slate clean for the next RTT. */ /* Wipe the slate clean for the next RTT. */
vegas->cntRTT = 0; vegas->cntRTT = 0;
vegas->minRTT = 0x7fffffff; vegas->minRTT = 0x7fffffff;
}
} }
/* Extract info for Tcp socket info provided via netlink. */ /* Extract info for Tcp socket info provided via netlink. */
......
...@@ -248,7 +248,7 @@ static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) ...@@ -248,7 +248,7 @@ static u32 esp6_get_max_size(struct xfrm_state *x, int mtu)
if (esp->conf.padlen) if (esp->conf.padlen)
mtu = ALIGN(mtu, esp->conf.padlen); mtu = ALIGN(mtu, esp->conf.padlen);
return mtu + x->props.header_len + esp->auth.icv_full_len; return mtu + x->props.header_len + esp->auth.icv_trunc_len;
} }
static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
......
...@@ -68,8 +68,8 @@ static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, ...@@ -68,8 +68,8 @@ static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
[ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1
}; };
__u8 type = orig->dst.u.icmp.type - 128; int type = orig->dst.u.icmp.type - 128;
if (type >= sizeof(invmap) || !invmap[type]) if (type < 0 || type >= sizeof(invmap) || !invmap[type])
return 0; return 0;
tuple->src.u.icmp.id = orig->src.u.icmp.id; tuple->src.u.icmp.id = orig->src.u.icmp.id;
...@@ -129,12 +129,12 @@ static int icmpv6_new(struct nf_conn *conntrack, ...@@ -129,12 +129,12 @@ static int icmpv6_new(struct nf_conn *conntrack,
[ICMPV6_ECHO_REQUEST - 128] = 1, [ICMPV6_ECHO_REQUEST - 128] = 1,
[ICMPV6_NI_QUERY - 128] = 1 [ICMPV6_NI_QUERY - 128] = 1
}; };
int type = conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128;
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128 >= sizeof(valid_new) if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128]) {
/* Can't create a new ICMPv6 `conn' with this. */ /* Can't create a new ICMPv6 `conn' with this. */
DEBUGP("icmp: can't create new conn with type %u\n", DEBUGP("icmpv6: can't create new conn with type %u\n",
conntrack->tuplehash[0].tuple.dst.u.icmp.type); type + 128);
NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple); NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0; return 0;
} }
......
...@@ -61,8 +61,8 @@ config NF_CONNTRACK_MARK ...@@ -61,8 +61,8 @@ config NF_CONNTRACK_MARK
instead of the individual packets. instead of the individual packets.
config NF_CONNTRACK_EVENTS config NF_CONNTRACK_EVENTS
bool "Connection tracking events" bool "Connection tracking events (EXPERIMENTAL)"
depends on NF_CONNTRACK depends on EXPERIMENTAL && NF_CONNTRACK
help help
If this option is enabled, the connection tracking code will If this option is enabled, the connection tracking code will
provide a notifier chain that can be used by other kernel code provide a notifier chain that can be used by other kernel code
......
...@@ -1383,6 +1383,9 @@ void nf_conntrack_cleanup(void) ...@@ -1383,6 +1383,9 @@ void nf_conntrack_cleanup(void)
schedule(); schedule();
goto i_see_dead_people; goto i_see_dead_people;
} }
/* wait until all references to nf_conntrack_untracked are dropped */
while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
schedule();
for (i = 0; i < NF_CT_F_NUM; i++) { for (i = 0; i < NF_CT_F_NUM; i++) {
if (nf_ct_cache[i].use == 0) if (nf_ct_cache[i].use == 0)
......
...@@ -162,7 +162,7 @@ nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys, ...@@ -162,7 +162,7 @@ nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
return -EINVAL; return -EINVAL;
} }
min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg)); min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
if (unlikely(nlh->nlmsg_len < min_len)) if (unlikely(nlh->nlmsg_len < min_len))
return -EINVAL; return -EINVAL;
...@@ -236,8 +236,7 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb, ...@@ -236,8 +236,7 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
} }
/* All the messages must at least contain nfgenmsg */ /* All the messages must at least contain nfgenmsg */
if (nlh->nlmsg_len < if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) {
DEBUGP("received message was too short\n"); DEBUGP("received message was too short\n");
return 0; return 0;
} }
......
...@@ -1587,23 +1587,47 @@ static inline struct page *pg_vec_endpage(char *one_pg_vec, unsigned int order) ...@@ -1587,23 +1587,47 @@ static inline struct page *pg_vec_endpage(char *one_pg_vec, unsigned int order)
return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1); return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1);
} }
static void free_pg_vec(char **pg_vec, unsigned order, unsigned len) static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
{ {
int i; int i;
for (i=0; i<len; i++) { for (i = 0; i < len; i++) {
if (pg_vec[i]) { if (likely(pg_vec[i]))
struct page *page, *pend; free_pages((unsigned long) pg_vec[i], order);
pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
ClearPageReserved(page);
free_pages((unsigned long)pg_vec[i], order);
}
} }
kfree(pg_vec); kfree(pg_vec);
} }
static inline char *alloc_one_pg_vec_page(unsigned long order)
{
return (char *) __get_free_pages(GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
order);
}
static char **alloc_pg_vec(struct tpacket_req *req, int order)
{
unsigned int block_nr = req->tp_block_nr;
char **pg_vec;
int i;
pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL);
if (unlikely(!pg_vec))
goto out;
for (i = 0; i < block_nr; i++) {
pg_vec[i] = alloc_one_pg_vec_page(order);
if (unlikely(!pg_vec[i]))
goto out_free_pgvec;
}
out:
return pg_vec;
out_free_pgvec:
free_pg_vec(pg_vec, order, block_nr);
pg_vec = NULL;
goto out;
}
static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
{ {
...@@ -1617,64 +1641,46 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1617,64 +1641,46 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
/* Sanity tests and some calculations */ /* Sanity tests and some calculations */
if (po->pg_vec) if (unlikely(po->pg_vec))
return -EBUSY; return -EBUSY;
if ((int)req->tp_block_size <= 0) if (unlikely((int)req->tp_block_size <= 0))
return -EINVAL; return -EINVAL;
if (req->tp_block_size&(PAGE_SIZE-1)) if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
return -EINVAL; return -EINVAL;
if (req->tp_frame_size < TPACKET_HDRLEN) if (unlikely(req->tp_frame_size < TPACKET_HDRLEN))
return -EINVAL; return -EINVAL;
if (req->tp_frame_size&(TPACKET_ALIGNMENT-1)) if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
return -EINVAL; return -EINVAL;
po->frames_per_block = req->tp_block_size/req->tp_frame_size; po->frames_per_block = req->tp_block_size/req->tp_frame_size;
if (po->frames_per_block <= 0) if (unlikely(po->frames_per_block <= 0))
return -EINVAL; return -EINVAL;
if (po->frames_per_block*req->tp_block_nr != req->tp_frame_nr) if (unlikely((po->frames_per_block * req->tp_block_nr) !=
req->tp_frame_nr))
return -EINVAL; return -EINVAL;
/* OK! */
/* Allocate page vector */
while ((PAGE_SIZE<<order) < req->tp_block_size)
order++;
err = -ENOMEM; err = -ENOMEM;
order = get_order(req->tp_block_size);
pg_vec = kmalloc(req->tp_block_nr*sizeof(char *), GFP_KERNEL); pg_vec = alloc_pg_vec(req, order);
if (pg_vec == NULL) if (unlikely(!pg_vec))
goto out; goto out;
memset(pg_vec, 0, req->tp_block_nr*sizeof(char **));
for (i=0; i<req->tp_block_nr; i++) {
struct page *page, *pend;
pg_vec[i] = (char *)__get_free_pages(GFP_KERNEL, order);
if (!pg_vec[i])
goto out_free_pgvec;
pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
SetPageReserved(page);
}
/* Page vector is allocated */
l = 0; l = 0;
for (i=0; i<req->tp_block_nr; i++) { for (i = 0; i < req->tp_block_nr; i++) {
char *ptr = pg_vec[i]; char *ptr = pg_vec[i];
struct tpacket_hdr *header; struct tpacket_hdr *header;
int k; int k;
for (k=0; k<po->frames_per_block; k++) { for (k = 0; k < po->frames_per_block; k++) {
header = (struct tpacket_hdr *) ptr;
header = (struct tpacket_hdr*)ptr;
header->tp_status = TP_STATUS_KERNEL; header->tp_status = TP_STATUS_KERNEL;
ptr += req->tp_frame_size; ptr += req->tp_frame_size;
} }
} }
/* Done */ /* Done */
} else { } else {
if (req->tp_frame_nr) if (unlikely(req->tp_frame_nr))
return -EINVAL; return -EINVAL;
} }
...@@ -1701,7 +1707,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1701,7 +1707,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
spin_lock_bh(&sk->sk_receive_queue.lock); spin_lock_bh(&sk->sk_receive_queue.lock);
pg_vec = XC(po->pg_vec, pg_vec); pg_vec = XC(po->pg_vec, pg_vec);
po->frame_max = req->tp_frame_nr-1; po->frame_max = (req->tp_frame_nr - 1);
po->head = 0; po->head = 0;
po->frame_size = req->tp_frame_size; po->frame_size = req->tp_frame_size;
spin_unlock_bh(&sk->sk_receive_queue.lock); spin_unlock_bh(&sk->sk_receive_queue.lock);
...@@ -1728,7 +1734,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1728,7 +1734,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
release_sock(sk); release_sock(sk);
out_free_pgvec:
if (pg_vec) if (pg_vec)
free_pg_vec(pg_vec, order, req->tp_block_nr); free_pg_vec(pg_vec, order, req->tp_block_nr);
out: out:
...@@ -1755,17 +1760,19 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st ...@@ -1755,17 +1760,19 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st
if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE)
goto out; goto out;
atomic_inc(&po->mapped);
start = vma->vm_start; start = vma->vm_start;
err = -EAGAIN; for (i = 0; i < po->pg_vec_len; i++) {
for (i=0; i<po->pg_vec_len; i++) { struct page *page = virt_to_page(po->pg_vec[i]);
if (remap_pfn_range(vma, start, int pg_num;
__pa(po->pg_vec[i]) >> PAGE_SHIFT,
po->pg_vec_pages*PAGE_SIZE, for (pg_num = 0; pg_num < po->pg_vec_pages; pg_num++, page++) {
vma->vm_page_prot)) err = vm_insert_page(vma, start, page);
goto out; if (unlikely(err))
start += po->pg_vec_pages*PAGE_SIZE; goto out;
start += PAGE_SIZE;
}
} }
atomic_inc(&po->mapped);
vma->vm_ops = &packet_mmap_ops; vma->vm_ops = &packet_mmap_ops;
err = 0; err = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment