diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 25 | ||||
-rw-r--r-- | net/ipv4/Kconfig | 2 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 10 |
3 files changed, 24 insertions, 13 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 876b1112d5ba..e8041eb76ac1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2206,6 +2206,7 @@ DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, }; /* * get_rps_cpu is called from netif_receive_skb and returns the target * CPU from the RPS map of the receiving queue for a given skb. + * rcu_read_lock must be held on entry. */ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb) { @@ -2217,8 +2218,6 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb) u8 ip_proto; u32 addr1, addr2, ports, ihl; - rcu_read_lock(); - if (skb_rx_queue_recorded(skb)) { u16 index = skb_get_rx_queue(skb); if (unlikely(index >= dev->num_rx_queues)) { @@ -2296,7 +2295,6 @@ got_hash: } done: - rcu_read_unlock(); return cpu; } @@ -2392,7 +2390,7 @@ enqueue: int netif_rx(struct sk_buff *skb) { - int cpu; + int ret; /* if netpoll wants it, pretend we never saw it */ if (netpoll_rx(skb)) @@ -2402,14 +2400,21 @@ int netif_rx(struct sk_buff *skb) net_timestamp(skb); #ifdef CONFIG_RPS - cpu = get_rps_cpu(skb->dev, skb); - if (cpu < 0) - cpu = smp_processor_id(); + { + int cpu; + + rcu_read_lock(); + cpu = get_rps_cpu(skb->dev, skb); + if (cpu < 0) + cpu = smp_processor_id(); + ret = enqueue_to_backlog(skb, cpu); + rcu_read_unlock(); + } #else - cpu = smp_processor_id(); + ret = enqueue_to_backlog(skb, get_cpu()); + put_cpu(); #endif - - return enqueue_to_backlog(skb, cpu); + return ret; } EXPORT_SYMBOL(netif_rx); diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index be597749c385..8e3a1fd938ab 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -252,7 +252,7 @@ config IP_MROUTE config IP_MROUTE_MULTIPLE_TABLES bool "IP: multicast policy routing" - depends on IP_ADVANCED_ROUTER + depends on IP_MROUTE && IP_ADVANCED_ROUTER select FIB_RULES help Normally, a multicast router runs a userspace daemon and decides diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 5df5fd74c6d1..7d8a2bcecb76 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -71,6 +71,9 @@ struct mr_table { struct list_head list; +#ifdef CONFIG_NET_NS + struct net *net; +#endif u32 id; struct sock *mroute_sk; struct timer_list ipmr_expire_timer; @@ -308,6 +311,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); if (mrt == NULL) return NULL; + write_pnet(&mrt->net, net); mrt->id = id; /* Forwarding cache */ @@ -580,7 +584,7 @@ static inline void ipmr_cache_free(struct mfc_cache *c) static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c) { - struct net *net = NULL; //mrt->net; + struct net *net = read_pnet(&mrt->net); struct sk_buff *skb; struct nlmsgerr *e; @@ -1089,12 +1093,14 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, * Check to see if we resolved a queued list. If so we * need to send on the frames and tidy up. */ + found = false; spin_lock_bh(&mfc_unres_lock); list_for_each_entry(uc, &mrt->mfc_unres_queue, list) { if (uc->mfc_origin == c->mfc_origin && uc->mfc_mcastgrp == c->mfc_mcastgrp) { list_del(&uc->list); atomic_dec(&mrt->cache_resolve_queue_len); + found = true; break; } } @@ -1102,7 +1108,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, del_timer(&mrt->ipmr_expire_timer); spin_unlock_bh(&mfc_unres_lock); - if (uc) { + if (found) { ipmr_cache_resolve(net, mrt, uc, c); ipmr_cache_free(uc); } |