diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:28:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:28:00 -0400 |
commit | 22cdbd1d5789cc16c37102eb6f62c3ae377b849e (patch) | |
tree | f86d3d798351c4bde69afbfa80e940aad01abaad /net | |
parent | 55f335a8857db2ee22c068e7ab7141fc79928296 (diff) | |
parent | ce45b873028fdf94a24f0850cd554e6fda593e16 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (108 commits)
ehea: Fixing statistics
bonding: Fix lockdep warning after bond_vlan_rx_register()
tunnels: Fix tunnels change rcu protection
caif-u5500: Build config for CAIF shared mem driver
caif-u5500: CAIF shared memory mailbox interface
caif-u5500: CAIF shared memory transport protocol
caif-u5500: Adding shared memory include
drivers/isdn: delete double assignment
drivers/net/typhoon.c: delete double assignment
drivers/net/sb1000.c: delete double assignment
qlcnic: define valid vlan id range
qlcnic: reduce rx ring size
qlcnic: fix mac learning
ehea: fix use after free
inetpeer: __rcu annotations
fib_rules: __rcu annotates ctarget
tunnels: add __rcu annotations
net: add __rcu annotations to protocol
ipv4: add __rcu annotations to routes.c
qlge: bugfix: Restoring the vlan setting.
...
Diffstat (limited to 'net')
43 files changed, 400 insertions, 320 deletions
diff --git a/net/802/garp.c b/net/802/garp.c index 941f2a324d3a..c1df2dad8c6b 100644 --- a/net/802/garp.c +++ b/net/802/garp.c | |||
@@ -346,8 +346,8 @@ int garp_request_join(const struct net_device *dev, | |||
346 | const struct garp_application *appl, | 346 | const struct garp_application *appl, |
347 | const void *data, u8 len, u8 type) | 347 | const void *data, u8 len, u8 type) |
348 | { | 348 | { |
349 | struct garp_port *port = dev->garp_port; | 349 | struct garp_port *port = rtnl_dereference(dev->garp_port); |
350 | struct garp_applicant *app = port->applicants[appl->type]; | 350 | struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); |
351 | struct garp_attr *attr; | 351 | struct garp_attr *attr; |
352 | 352 | ||
353 | spin_lock_bh(&app->lock); | 353 | spin_lock_bh(&app->lock); |
@@ -366,8 +366,8 @@ void garp_request_leave(const struct net_device *dev, | |||
366 | const struct garp_application *appl, | 366 | const struct garp_application *appl, |
367 | const void *data, u8 len, u8 type) | 367 | const void *data, u8 len, u8 type) |
368 | { | 368 | { |
369 | struct garp_port *port = dev->garp_port; | 369 | struct garp_port *port = rtnl_dereference(dev->garp_port); |
370 | struct garp_applicant *app = port->applicants[appl->type]; | 370 | struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); |
371 | struct garp_attr *attr; | 371 | struct garp_attr *attr; |
372 | 372 | ||
373 | spin_lock_bh(&app->lock); | 373 | spin_lock_bh(&app->lock); |
@@ -546,11 +546,11 @@ static int garp_init_port(struct net_device *dev) | |||
546 | 546 | ||
547 | static void garp_release_port(struct net_device *dev) | 547 | static void garp_release_port(struct net_device *dev) |
548 | { | 548 | { |
549 | struct garp_port *port = dev->garp_port; | 549 | struct garp_port *port = rtnl_dereference(dev->garp_port); |
550 | unsigned int i; | 550 | unsigned int i; |
551 | 551 | ||
552 | for (i = 0; i <= GARP_APPLICATION_MAX; i++) { | 552 | for (i = 0; i <= GARP_APPLICATION_MAX; i++) { |
553 | if (port->applicants[i]) | 553 | if (rtnl_dereference(port->applicants[i])) |
554 | return; | 554 | return; |
555 | } | 555 | } |
556 | rcu_assign_pointer(dev->garp_port, NULL); | 556 | rcu_assign_pointer(dev->garp_port, NULL); |
@@ -565,7 +565,7 @@ int garp_init_applicant(struct net_device *dev, struct garp_application *appl) | |||
565 | 565 | ||
566 | ASSERT_RTNL(); | 566 | ASSERT_RTNL(); |
567 | 567 | ||
568 | if (!dev->garp_port) { | 568 | if (!rtnl_dereference(dev->garp_port)) { |
569 | err = garp_init_port(dev); | 569 | err = garp_init_port(dev); |
570 | if (err < 0) | 570 | if (err < 0) |
571 | goto err1; | 571 | goto err1; |
@@ -601,8 +601,8 @@ EXPORT_SYMBOL_GPL(garp_init_applicant); | |||
601 | 601 | ||
602 | void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl) | 602 | void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl) |
603 | { | 603 | { |
604 | struct garp_port *port = dev->garp_port; | 604 | struct garp_port *port = rtnl_dereference(dev->garp_port); |
605 | struct garp_applicant *app = port->applicants[appl->type]; | 605 | struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]); |
606 | 606 | ||
607 | ASSERT_RTNL(); | 607 | ASSERT_RTNL(); |
608 | 608 | ||
diff --git a/net/802/stp.c b/net/802/stp.c index 53c8f77f0ccd..978c30b1b36b 100644 --- a/net/802/stp.c +++ b/net/802/stp.c | |||
@@ -21,8 +21,8 @@ | |||
21 | #define GARP_ADDR_MAX 0x2F | 21 | #define GARP_ADDR_MAX 0x2F |
22 | #define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN) | 22 | #define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN) |
23 | 23 | ||
24 | static const struct stp_proto *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly; | 24 | static const struct stp_proto __rcu *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly; |
25 | static const struct stp_proto *stp_proto __read_mostly; | 25 | static const struct stp_proto __rcu *stp_proto __read_mostly; |
26 | 26 | ||
27 | static struct llc_sap *sap __read_mostly; | 27 | static struct llc_sap *sap __read_mostly; |
28 | static unsigned int sap_registered; | 28 | static unsigned int sap_registered; |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 05b867e43757..52077ca22072 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -112,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
112 | 112 | ||
113 | ASSERT_RTNL(); | 113 | ASSERT_RTNL(); |
114 | 114 | ||
115 | grp = real_dev->vlgrp; | 115 | grp = rtnl_dereference(real_dev->vlgrp); |
116 | BUG_ON(!grp); | 116 | BUG_ON(!grp); |
117 | 117 | ||
118 | /* Take it out of our own structures, but be sure to interlock with | 118 | /* Take it out of our own structures, but be sure to interlock with |
@@ -177,7 +177,7 @@ int register_vlan_dev(struct net_device *dev) | |||
177 | struct vlan_group *grp, *ngrp = NULL; | 177 | struct vlan_group *grp, *ngrp = NULL; |
178 | int err; | 178 | int err; |
179 | 179 | ||
180 | grp = real_dev->vlgrp; | 180 | grp = rtnl_dereference(real_dev->vlgrp); |
181 | if (!grp) { | 181 | if (!grp) { |
182 | ngrp = grp = vlan_group_alloc(real_dev); | 182 | ngrp = grp = vlan_group_alloc(real_dev); |
183 | if (!grp) | 183 | if (!grp) |
@@ -385,7 +385,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
385 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); | 385 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); |
386 | } | 386 | } |
387 | 387 | ||
388 | grp = dev->vlgrp; | 388 | grp = rtnl_dereference(dev->vlgrp); |
389 | if (!grp) | 389 | if (!grp) |
390 | goto out; | 390 | goto out; |
391 | 391 | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 78b5a89b0f40..35dfb8318483 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1685,10 +1685,10 @@ EXPORT_SYMBOL(netif_device_attach); | |||
1685 | 1685 | ||
1686 | static bool can_checksum_protocol(unsigned long features, __be16 protocol) | 1686 | static bool can_checksum_protocol(unsigned long features, __be16 protocol) |
1687 | { | 1687 | { |
1688 | return ((features & NETIF_F_GEN_CSUM) || | 1688 | return ((features & NETIF_F_NO_CSUM) || |
1689 | ((features & NETIF_F_IP_CSUM) && | 1689 | ((features & NETIF_F_V4_CSUM) && |
1690 | protocol == htons(ETH_P_IP)) || | 1690 | protocol == htons(ETH_P_IP)) || |
1691 | ((features & NETIF_F_IPV6_CSUM) && | 1691 | ((features & NETIF_F_V6_CSUM) && |
1692 | protocol == htons(ETH_P_IPV6)) || | 1692 | protocol == htons(ETH_P_IPV6)) || |
1693 | ((features & NETIF_F_FCOE_CRC) && | 1693 | ((features & NETIF_F_FCOE_CRC) && |
1694 | protocol == htons(ETH_P_FCOE))); | 1694 | protocol == htons(ETH_P_FCOE))); |
@@ -1696,22 +1696,18 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol) | |||
1696 | 1696 | ||
1697 | static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb) | 1697 | static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb) |
1698 | { | 1698 | { |
1699 | __be16 protocol = skb->protocol; | ||
1699 | int features = dev->features; | 1700 | int features = dev->features; |
1700 | 1701 | ||
1701 | if (vlan_tx_tag_present(skb)) | 1702 | if (vlan_tx_tag_present(skb)) { |
1702 | features &= dev->vlan_features; | 1703 | features &= dev->vlan_features; |
1703 | 1704 | } else if (protocol == htons(ETH_P_8021Q)) { | |
1704 | if (can_checksum_protocol(features, skb->protocol)) | ||
1705 | return true; | ||
1706 | |||
1707 | if (skb->protocol == htons(ETH_P_8021Q)) { | ||
1708 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; | 1705 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; |
1709 | if (can_checksum_protocol(dev->features & dev->vlan_features, | 1706 | protocol = veh->h_vlan_encapsulated_proto; |
1710 | veh->h_vlan_encapsulated_proto)) | 1707 | features &= dev->vlan_features; |
1711 | return true; | ||
1712 | } | 1708 | } |
1713 | 1709 | ||
1714 | return false; | 1710 | return can_checksum_protocol(features, protocol); |
1715 | } | 1711 | } |
1716 | 1712 | ||
1717 | /** | 1713 | /** |
@@ -2213,7 +2209,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, | |||
2213 | } | 2209 | } |
2214 | 2210 | ||
2215 | static DEFINE_PER_CPU(int, xmit_recursion); | 2211 | static DEFINE_PER_CPU(int, xmit_recursion); |
2216 | #define RECURSION_LIMIT 3 | 2212 | #define RECURSION_LIMIT 10 |
2217 | 2213 | ||
2218 | /** | 2214 | /** |
2219 | * dev_queue_xmit - transmit a buffer | 2215 | * dev_queue_xmit - transmit a buffer |
@@ -2413,7 +2409,7 @@ EXPORT_SYMBOL(__skb_get_rxhash); | |||
2413 | #ifdef CONFIG_RPS | 2409 | #ifdef CONFIG_RPS |
2414 | 2410 | ||
2415 | /* One global table that all flow-based protocols share. */ | 2411 | /* One global table that all flow-based protocols share. */ |
2416 | struct rps_sock_flow_table *rps_sock_flow_table __read_mostly; | 2412 | struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly; |
2417 | EXPORT_SYMBOL(rps_sock_flow_table); | 2413 | EXPORT_SYMBOL(rps_sock_flow_table); |
2418 | 2414 | ||
2419 | /* | 2415 | /* |
@@ -2425,7 +2421,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
2425 | struct rps_dev_flow **rflowp) | 2421 | struct rps_dev_flow **rflowp) |
2426 | { | 2422 | { |
2427 | struct netdev_rx_queue *rxqueue; | 2423 | struct netdev_rx_queue *rxqueue; |
2428 | struct rps_map *map = NULL; | 2424 | struct rps_map *map; |
2429 | struct rps_dev_flow_table *flow_table; | 2425 | struct rps_dev_flow_table *flow_table; |
2430 | struct rps_sock_flow_table *sock_flow_table; | 2426 | struct rps_sock_flow_table *sock_flow_table; |
2431 | int cpu = -1; | 2427 | int cpu = -1; |
@@ -2444,15 +2440,15 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
2444 | } else | 2440 | } else |
2445 | rxqueue = dev->_rx; | 2441 | rxqueue = dev->_rx; |
2446 | 2442 | ||
2447 | if (rxqueue->rps_map) { | 2443 | map = rcu_dereference(rxqueue->rps_map); |
2448 | map = rcu_dereference(rxqueue->rps_map); | 2444 | if (map) { |
2449 | if (map && map->len == 1) { | 2445 | if (map->len == 1) { |
2450 | tcpu = map->cpus[0]; | 2446 | tcpu = map->cpus[0]; |
2451 | if (cpu_online(tcpu)) | 2447 | if (cpu_online(tcpu)) |
2452 | cpu = tcpu; | 2448 | cpu = tcpu; |
2453 | goto done; | 2449 | goto done; |
2454 | } | 2450 | } |
2455 | } else if (!rxqueue->rps_flow_table) { | 2451 | } else if (!rcu_dereference_raw(rxqueue->rps_flow_table)) { |
2456 | goto done; | 2452 | goto done; |
2457 | } | 2453 | } |
2458 | 2454 | ||
@@ -5416,7 +5412,7 @@ void netdev_run_todo(void) | |||
5416 | /* paranoia */ | 5412 | /* paranoia */ |
5417 | BUG_ON(netdev_refcnt_read(dev)); | 5413 | BUG_ON(netdev_refcnt_read(dev)); |
5418 | WARN_ON(rcu_dereference_raw(dev->ip_ptr)); | 5414 | WARN_ON(rcu_dereference_raw(dev->ip_ptr)); |
5419 | WARN_ON(dev->ip6_ptr); | 5415 | WARN_ON(rcu_dereference_raw(dev->ip6_ptr)); |
5420 | WARN_ON(dev->dn_ptr); | 5416 | WARN_ON(dev->dn_ptr); |
5421 | 5417 | ||
5422 | if (dev->destructor) | 5418 | if (dev->destructor) |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 1bc3f253ba6c..82a4369ae150 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -351,12 +351,12 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
351 | 351 | ||
352 | list_for_each_entry(r, &ops->rules_list, list) { | 352 | list_for_each_entry(r, &ops->rules_list, list) { |
353 | if (r->pref == rule->target) { | 353 | if (r->pref == rule->target) { |
354 | rule->ctarget = r; | 354 | RCU_INIT_POINTER(rule->ctarget, r); |
355 | break; | 355 | break; |
356 | } | 356 | } |
357 | } | 357 | } |
358 | 358 | ||
359 | if (rule->ctarget == NULL) | 359 | if (rcu_dereference_protected(rule->ctarget, 1) == NULL) |
360 | unresolved = 1; | 360 | unresolved = 1; |
361 | } else if (rule->action == FR_ACT_GOTO) | 361 | } else if (rule->action == FR_ACT_GOTO) |
362 | goto errout_free; | 362 | goto errout_free; |
@@ -373,6 +373,11 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
373 | 373 | ||
374 | fib_rule_get(rule); | 374 | fib_rule_get(rule); |
375 | 375 | ||
376 | if (last) | ||
377 | list_add_rcu(&rule->list, &last->list); | ||
378 | else | ||
379 | list_add_rcu(&rule->list, &ops->rules_list); | ||
380 | |||
376 | if (ops->unresolved_rules) { | 381 | if (ops->unresolved_rules) { |
377 | /* | 382 | /* |
378 | * There are unresolved goto rules in the list, check if | 383 | * There are unresolved goto rules in the list, check if |
@@ -381,7 +386,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
381 | list_for_each_entry(r, &ops->rules_list, list) { | 386 | list_for_each_entry(r, &ops->rules_list, list) { |
382 | if (r->action == FR_ACT_GOTO && | 387 | if (r->action == FR_ACT_GOTO && |
383 | r->target == rule->pref) { | 388 | r->target == rule->pref) { |
384 | BUG_ON(r->ctarget != NULL); | 389 | BUG_ON(rtnl_dereference(r->ctarget) != NULL); |
385 | rcu_assign_pointer(r->ctarget, rule); | 390 | rcu_assign_pointer(r->ctarget, rule); |
386 | if (--ops->unresolved_rules == 0) | 391 | if (--ops->unresolved_rules == 0) |
387 | break; | 392 | break; |
@@ -395,11 +400,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
395 | if (unresolved) | 400 | if (unresolved) |
396 | ops->unresolved_rules++; | 401 | ops->unresolved_rules++; |
397 | 402 | ||
398 | if (last) | ||
399 | list_add_rcu(&rule->list, &last->list); | ||
400 | else | ||
401 | list_add_rcu(&rule->list, &ops->rules_list); | ||
402 | |||
403 | notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid); | 403 | notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid); |
404 | flush_route_cache(ops); | 404 | flush_route_cache(ops); |
405 | rules_ops_put(ops); | 405 | rules_ops_put(ops); |
@@ -487,7 +487,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
487 | */ | 487 | */ |
488 | if (ops->nr_goto_rules > 0) { | 488 | if (ops->nr_goto_rules > 0) { |
489 | list_for_each_entry(tmp, &ops->rules_list, list) { | 489 | list_for_each_entry(tmp, &ops->rules_list, list) { |
490 | if (tmp->ctarget == rule) { | 490 | if (rtnl_dereference(tmp->ctarget) == rule) { |
491 | rcu_assign_pointer(tmp->ctarget, NULL); | 491 | rcu_assign_pointer(tmp->ctarget, NULL); |
492 | ops->unresolved_rules++; | 492 | ops->unresolved_rules++; |
493 | } | 493 | } |
@@ -545,7 +545,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | |||
545 | frh->action = rule->action; | 545 | frh->action = rule->action; |
546 | frh->flags = rule->flags; | 546 | frh->flags = rule->flags; |
547 | 547 | ||
548 | if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL) | 548 | if (rule->action == FR_ACT_GOTO && |
549 | rcu_dereference_raw(rule->ctarget) == NULL) | ||
549 | frh->flags |= FIB_RULE_UNRESOLVED; | 550 | frh->flags |= FIB_RULE_UNRESOLVED; |
550 | 551 | ||
551 | if (rule->iifname[0]) { | 552 | if (rule->iifname[0]) { |
diff --git a/net/core/filter.c b/net/core/filter.c index 7adf50352918..7beaec36b541 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -89,8 +89,8 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) | |||
89 | rcu_read_lock_bh(); | 89 | rcu_read_lock_bh(); |
90 | filter = rcu_dereference_bh(sk->sk_filter); | 90 | filter = rcu_dereference_bh(sk->sk_filter); |
91 | if (filter) { | 91 | if (filter) { |
92 | unsigned int pkt_len = sk_run_filter(skb, filter->insns, | 92 | unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len); |
93 | filter->len); | 93 | |
94 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; | 94 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; |
95 | } | 95 | } |
96 | rcu_read_unlock_bh(); | 96 | rcu_read_unlock_bh(); |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b143173e3eb2..a5ff5a89f376 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -598,7 +598,8 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue, | |||
598 | } | 598 | } |
599 | 599 | ||
600 | spin_lock(&rps_map_lock); | 600 | spin_lock(&rps_map_lock); |
601 | old_map = queue->rps_map; | 601 | old_map = rcu_dereference_protected(queue->rps_map, |
602 | lockdep_is_held(&rps_map_lock)); | ||
602 | rcu_assign_pointer(queue->rps_map, map); | 603 | rcu_assign_pointer(queue->rps_map, map); |
603 | spin_unlock(&rps_map_lock); | 604 | spin_unlock(&rps_map_lock); |
604 | 605 | ||
@@ -677,7 +678,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, | |||
677 | table = NULL; | 678 | table = NULL; |
678 | 679 | ||
679 | spin_lock(&rps_dev_flow_lock); | 680 | spin_lock(&rps_dev_flow_lock); |
680 | old_table = queue->rps_flow_table; | 681 | old_table = rcu_dereference_protected(queue->rps_flow_table, |
682 | lockdep_is_held(&rps_dev_flow_lock)); | ||
681 | rcu_assign_pointer(queue->rps_flow_table, table); | 683 | rcu_assign_pointer(queue->rps_flow_table, table); |
682 | spin_unlock(&rps_dev_flow_lock); | 684 | spin_unlock(&rps_dev_flow_lock); |
683 | 685 | ||
@@ -705,13 +707,17 @@ static void rx_queue_release(struct kobject *kobj) | |||
705 | { | 707 | { |
706 | struct netdev_rx_queue *queue = to_rx_queue(kobj); | 708 | struct netdev_rx_queue *queue = to_rx_queue(kobj); |
707 | struct netdev_rx_queue *first = queue->first; | 709 | struct netdev_rx_queue *first = queue->first; |
710 | struct rps_map *map; | ||
711 | struct rps_dev_flow_table *flow_table; | ||
708 | 712 | ||
709 | if (queue->rps_map) | ||
710 | call_rcu(&queue->rps_map->rcu, rps_map_release); | ||
711 | 713 | ||
712 | if (queue->rps_flow_table) | 714 | map = rcu_dereference_raw(queue->rps_map); |
713 | call_rcu(&queue->rps_flow_table->rcu, | 715 | if (map) |
714 | rps_dev_flow_table_release); | 716 | call_rcu(&map->rcu, rps_map_release); |
717 | |||
718 | flow_table = rcu_dereference_raw(queue->rps_flow_table); | ||
719 | if (flow_table) | ||
720 | call_rcu(&flow_table->rcu, rps_dev_flow_table_release); | ||
715 | 721 | ||
716 | if (atomic_dec_and_test(&first->count)) | 722 | if (atomic_dec_and_test(&first->count)) |
717 | kfree(first); | 723 | kfree(first); |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index c988e685433a..3f860261c5ee 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -42,7 +42,9 @@ static int net_assign_generic(struct net *net, int id, void *data) | |||
42 | BUG_ON(!mutex_is_locked(&net_mutex)); | 42 | BUG_ON(!mutex_is_locked(&net_mutex)); |
43 | BUG_ON(id == 0); | 43 | BUG_ON(id == 0); |
44 | 44 | ||
45 | ng = old_ng = net->gen; | 45 | old_ng = rcu_dereference_protected(net->gen, |
46 | lockdep_is_held(&net_mutex)); | ||
47 | ng = old_ng; | ||
46 | if (old_ng->len >= id) | 48 | if (old_ng->len >= id) |
47 | goto assign; | 49 | goto assign; |
48 | 50 | ||
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2c0df0f95b3d..679b797d06b1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -771,10 +771,10 @@ done: | |||
771 | static unsigned long num_arg(const char __user * user_buffer, | 771 | static unsigned long num_arg(const char __user * user_buffer, |
772 | unsigned long maxlen, unsigned long *num) | 772 | unsigned long maxlen, unsigned long *num) |
773 | { | 773 | { |
774 | int i = 0; | 774 | int i; |
775 | *num = 0; | 775 | *num = 0; |
776 | 776 | ||
777 | for (; i < maxlen; i++) { | 777 | for (i = 0; i < maxlen; i++) { |
778 | char c; | 778 | char c; |
779 | if (get_user(c, &user_buffer[i])) | 779 | if (get_user(c, &user_buffer[i])) |
780 | return -EFAULT; | 780 | return -EFAULT; |
@@ -789,9 +789,9 @@ static unsigned long num_arg(const char __user * user_buffer, | |||
789 | 789 | ||
790 | static int strn_len(const char __user * user_buffer, unsigned int maxlen) | 790 | static int strn_len(const char __user * user_buffer, unsigned int maxlen) |
791 | { | 791 | { |
792 | int i = 0; | 792 | int i; |
793 | 793 | ||
794 | for (; i < maxlen; i++) { | 794 | for (i = 0; i < maxlen; i++) { |
795 | char c; | 795 | char c; |
796 | if (get_user(c, &user_buffer[i])) | 796 | if (get_user(c, &user_buffer[i])) |
797 | return -EFAULT; | 797 | return -EFAULT; |
@@ -846,7 +846,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
846 | { | 846 | { |
847 | struct seq_file *seq = file->private_data; | 847 | struct seq_file *seq = file->private_data; |
848 | struct pktgen_dev *pkt_dev = seq->private; | 848 | struct pktgen_dev *pkt_dev = seq->private; |
849 | int i = 0, max, len; | 849 | int i, max, len; |
850 | char name[16], valstr[32]; | 850 | char name[16], valstr[32]; |
851 | unsigned long value = 0; | 851 | unsigned long value = 0; |
852 | char *pg_result = NULL; | 852 | char *pg_result = NULL; |
@@ -860,13 +860,13 @@ static ssize_t pktgen_if_write(struct file *file, | |||
860 | return -EINVAL; | 860 | return -EINVAL; |
861 | } | 861 | } |
862 | 862 | ||
863 | max = count - i; | 863 | max = count; |
864 | tmp = count_trail_chars(&user_buffer[i], max); | 864 | tmp = count_trail_chars(user_buffer, max); |
865 | if (tmp < 0) { | 865 | if (tmp < 0) { |
866 | pr_warning("illegal format\n"); | 866 | pr_warning("illegal format\n"); |
867 | return tmp; | 867 | return tmp; |
868 | } | 868 | } |
869 | i += tmp; | 869 | i = tmp; |
870 | 870 | ||
871 | /* Read variable name */ | 871 | /* Read variable name */ |
872 | 872 | ||
@@ -1764,7 +1764,7 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1764 | { | 1764 | { |
1765 | struct seq_file *seq = file->private_data; | 1765 | struct seq_file *seq = file->private_data; |
1766 | struct pktgen_thread *t = seq->private; | 1766 | struct pktgen_thread *t = seq->private; |
1767 | int i = 0, max, len, ret; | 1767 | int i, max, len, ret; |
1768 | char name[40]; | 1768 | char name[40]; |
1769 | char *pg_result; | 1769 | char *pg_result; |
1770 | 1770 | ||
@@ -1773,12 +1773,12 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1773 | return -EINVAL; | 1773 | return -EINVAL; |
1774 | } | 1774 | } |
1775 | 1775 | ||
1776 | max = count - i; | 1776 | max = count; |
1777 | len = count_trail_chars(&user_buffer[i], max); | 1777 | len = count_trail_chars(user_buffer, max); |
1778 | if (len < 0) | 1778 | if (len < 0) |
1779 | return len; | 1779 | return len; |
1780 | 1780 | ||
1781 | i += len; | 1781 | i = len; |
1782 | 1782 | ||
1783 | /* Read variable name */ | 1783 | /* Read variable name */ |
1784 | 1784 | ||
@@ -1975,7 +1975,7 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, | |||
1975 | const char *ifname) | 1975 | const char *ifname) |
1976 | { | 1976 | { |
1977 | char b[IFNAMSIZ+5]; | 1977 | char b[IFNAMSIZ+5]; |
1978 | int i = 0; | 1978 | int i; |
1979 | 1979 | ||
1980 | for (i = 0; ifname[i] != '@'; i++) { | 1980 | for (i = 0; ifname[i] != '@'; i++) { |
1981 | if (i == IFNAMSIZ) | 1981 | if (i == IFNAMSIZ) |
@@ -2519,8 +2519,8 @@ static void free_SAs(struct pktgen_dev *pkt_dev) | |||
2519 | { | 2519 | { |
2520 | if (pkt_dev->cflows) { | 2520 | if (pkt_dev->cflows) { |
2521 | /* let go of the SAs if we have them */ | 2521 | /* let go of the SAs if we have them */ |
2522 | int i = 0; | 2522 | int i; |
2523 | for (; i < pkt_dev->cflows; i++) { | 2523 | for (i = 0; i < pkt_dev->cflows; i++) { |
2524 | struct xfrm_state *x = pkt_dev->flows[i].x; | 2524 | struct xfrm_state *x = pkt_dev->flows[i].x; |
2525 | if (x) { | 2525 | if (x) { |
2526 | xfrm_state_put(x); | 2526 | xfrm_state_put(x); |
diff --git a/net/core/sock.c b/net/core/sock.c index 11db43632df8..3eed5424e659 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1225,7 +1225,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) | |||
1225 | sock_reset_flag(newsk, SOCK_DONE); | 1225 | sock_reset_flag(newsk, SOCK_DONE); |
1226 | skb_queue_head_init(&newsk->sk_error_queue); | 1226 | skb_queue_head_init(&newsk->sk_error_queue); |
1227 | 1227 | ||
1228 | filter = newsk->sk_filter; | 1228 | filter = rcu_dereference_protected(newsk->sk_filter, 1); |
1229 | if (filter != NULL) | 1229 | if (filter != NULL) |
1230 | sk_filter_charge(newsk, filter); | 1230 | sk_filter_charge(newsk, filter); |
1231 | 1231 | ||
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 01eee5d984be..385b6095fdc4 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -34,7 +34,8 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write, | |||
34 | 34 | ||
35 | mutex_lock(&sock_flow_mutex); | 35 | mutex_lock(&sock_flow_mutex); |
36 | 36 | ||
37 | orig_sock_table = rps_sock_flow_table; | 37 | orig_sock_table = rcu_dereference_protected(rps_sock_flow_table, |
38 | lockdep_is_held(&sock_flow_mutex)); | ||
38 | size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0; | 39 | size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0; |
39 | 40 | ||
40 | ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); | 41 | ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); |
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 43e1c594ce8f..b232375a0b75 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -120,11 +120,12 @@ static inline void fn_rebuild_zone(struct fn_zone *fz, | |||
120 | struct fib_node *f; | 120 | struct fib_node *f; |
121 | 121 | ||
122 | hlist_for_each_entry_safe(f, node, n, &old_ht[i], fn_hash) { | 122 | hlist_for_each_entry_safe(f, node, n, &old_ht[i], fn_hash) { |
123 | struct hlist_head __rcu *new_head; | 123 | struct hlist_head *new_head; |
124 | 124 | ||
125 | hlist_del_rcu(&f->fn_hash); | 125 | hlist_del_rcu(&f->fn_hash); |
126 | 126 | ||
127 | new_head = &fz->fz_hash[fn_hash(f->fn_key, fz)]; | 127 | new_head = rcu_dereference_protected(fz->fz_hash, 1) + |
128 | fn_hash(f->fn_key, fz); | ||
128 | hlist_add_head_rcu(&f->fn_hash, new_head); | 129 | hlist_add_head_rcu(&f->fn_hash, new_head); |
129 | } | 130 | } |
130 | } | 131 | } |
@@ -179,8 +180,8 @@ static void fn_rehash_zone(struct fn_zone *fz) | |||
179 | memcpy(&nfz, fz, sizeof(nfz)); | 180 | memcpy(&nfz, fz, sizeof(nfz)); |
180 | 181 | ||
181 | write_seqlock_bh(&fz->fz_lock); | 182 | write_seqlock_bh(&fz->fz_lock); |
182 | old_ht = fz->fz_hash; | 183 | old_ht = rcu_dereference_protected(fz->fz_hash, 1); |
183 | nfz.fz_hash = ht; | 184 | RCU_INIT_POINTER(nfz.fz_hash, ht); |
184 | nfz.fz_hashmask = new_hashmask; | 185 | nfz.fz_hashmask = new_hashmask; |
185 | nfz.fz_divisor = new_divisor; | 186 | nfz.fz_divisor = new_divisor; |
186 | fn_rebuild_zone(&nfz, old_ht, old_divisor); | 187 | fn_rebuild_zone(&nfz, old_ht, old_divisor); |
@@ -236,7 +237,7 @@ fn_new_zone(struct fn_hash *table, int z) | |||
236 | seqlock_init(&fz->fz_lock); | 237 | seqlock_init(&fz->fz_lock); |
237 | fz->fz_divisor = z ? EMBEDDED_HASH_SIZE : 1; | 238 | fz->fz_divisor = z ? EMBEDDED_HASH_SIZE : 1; |
238 | fz->fz_hashmask = fz->fz_divisor - 1; | 239 | fz->fz_hashmask = fz->fz_divisor - 1; |
239 | fz->fz_hash = fz->fz_embedded_hash; | 240 | RCU_INIT_POINTER(fz->fz_hash, fz->fz_embedded_hash); |
240 | fz->fz_order = z; | 241 | fz->fz_order = z; |
241 | fz->fz_revorder = 32 - z; | 242 | fz->fz_revorder = 32 - z; |
242 | fz->fz_mask = inet_make_mask(z); | 243 | fz->fz_mask = inet_make_mask(z); |
@@ -272,7 +273,7 @@ int fib_table_lookup(struct fib_table *tb, | |||
272 | for (fz = rcu_dereference(t->fn_zone_list); | 273 | for (fz = rcu_dereference(t->fn_zone_list); |
273 | fz != NULL; | 274 | fz != NULL; |
274 | fz = rcu_dereference(fz->fz_next)) { | 275 | fz = rcu_dereference(fz->fz_next)) { |
275 | struct hlist_head __rcu *head; | 276 | struct hlist_head *head; |
276 | struct hlist_node *node; | 277 | struct hlist_node *node; |
277 | struct fib_node *f; | 278 | struct fib_node *f; |
278 | __be32 k; | 279 | __be32 k; |
@@ -282,7 +283,7 @@ int fib_table_lookup(struct fib_table *tb, | |||
282 | seq = read_seqbegin(&fz->fz_lock); | 283 | seq = read_seqbegin(&fz->fz_lock); |
283 | k = fz_key(flp->fl4_dst, fz); | 284 | k = fz_key(flp->fl4_dst, fz); |
284 | 285 | ||
285 | head = &fz->fz_hash[fn_hash(k, fz)]; | 286 | head = rcu_dereference(fz->fz_hash) + fn_hash(k, fz); |
286 | hlist_for_each_entry_rcu(f, node, head, fn_hash) { | 287 | hlist_for_each_entry_rcu(f, node, head, fn_hash) { |
287 | if (f->fn_key != k) | 288 | if (f->fn_key != k) |
288 | continue; | 289 | continue; |
@@ -311,6 +312,7 @@ void fib_table_select_default(struct fib_table *tb, | |||
311 | struct fib_info *last_resort; | 312 | struct fib_info *last_resort; |
312 | struct fn_hash *t = (struct fn_hash *)tb->tb_data; | 313 | struct fn_hash *t = (struct fn_hash *)tb->tb_data; |
313 | struct fn_zone *fz = t->fn_zones[0]; | 314 | struct fn_zone *fz = t->fn_zones[0]; |
315 | struct hlist_head *head; | ||
314 | 316 | ||
315 | if (fz == NULL) | 317 | if (fz == NULL) |
316 | return; | 318 | return; |
@@ -320,7 +322,8 @@ void fib_table_select_default(struct fib_table *tb, | |||
320 | order = -1; | 322 | order = -1; |
321 | 323 | ||
322 | rcu_read_lock(); | 324 | rcu_read_lock(); |
323 | hlist_for_each_entry_rcu(f, node, &fz->fz_hash[0], fn_hash) { | 325 | head = rcu_dereference(fz->fz_hash); |
326 | hlist_for_each_entry_rcu(f, node, head, fn_hash) { | ||
324 | struct fib_alias *fa; | 327 | struct fib_alias *fa; |
325 | 328 | ||
326 | list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) { | 329 | list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) { |
@@ -374,7 +377,7 @@ out: | |||
374 | /* Insert node F to FZ. */ | 377 | /* Insert node F to FZ. */ |
375 | static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) | 378 | static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) |
376 | { | 379 | { |
377 | struct hlist_head *head = &fz->fz_hash[fn_hash(f->fn_key, fz)]; | 380 | struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(f->fn_key, fz); |
378 | 381 | ||
379 | hlist_add_head_rcu(&f->fn_hash, head); | 382 | hlist_add_head_rcu(&f->fn_hash, head); |
380 | } | 383 | } |
@@ -382,7 +385,7 @@ static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) | |||
382 | /* Return the node in FZ matching KEY. */ | 385 | /* Return the node in FZ matching KEY. */ |
383 | static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key) | 386 | static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key) |
384 | { | 387 | { |
385 | struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)]; | 388 | struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(key, fz); |
386 | struct hlist_node *node; | 389 | struct hlist_node *node; |
387 | struct fib_node *f; | 390 | struct fib_node *f; |
388 | 391 | ||
@@ -662,7 +665,7 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) | |||
662 | 665 | ||
663 | static int fn_flush_list(struct fn_zone *fz, int idx) | 666 | static int fn_flush_list(struct fn_zone *fz, int idx) |
664 | { | 667 | { |
665 | struct hlist_head *head = &fz->fz_hash[idx]; | 668 | struct hlist_head *head = rtnl_dereference(fz->fz_hash) + idx; |
666 | struct hlist_node *node, *n; | 669 | struct hlist_node *node, *n; |
667 | struct fib_node *f; | 670 | struct fib_node *f; |
668 | int found = 0; | 671 | int found = 0; |
@@ -761,14 +764,15 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, | |||
761 | struct fn_zone *fz) | 764 | struct fn_zone *fz) |
762 | { | 765 | { |
763 | int h, s_h; | 766 | int h, s_h; |
767 | struct hlist_head *head = rcu_dereference(fz->fz_hash); | ||
764 | 768 | ||
765 | if (fz->fz_hash == NULL) | 769 | if (head == NULL) |
766 | return skb->len; | 770 | return skb->len; |
767 | s_h = cb->args[3]; | 771 | s_h = cb->args[3]; |
768 | for (h = s_h; h < fz->fz_divisor; h++) { | 772 | for (h = s_h; h < fz->fz_divisor; h++) { |
769 | if (hlist_empty(&fz->fz_hash[h])) | 773 | if (hlist_empty(head + h)) |
770 | continue; | 774 | continue; |
771 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) { | 775 | if (fn_hash_dump_bucket(skb, cb, tb, fz, head + h) < 0) { |
772 | cb->args[3] = h; | 776 | cb->args[3] = h; |
773 | return -1; | 777 | return -1; |
774 | } | 778 | } |
@@ -872,7 +876,7 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) | |||
872 | if (!iter->zone->fz_nent) | 876 | if (!iter->zone->fz_nent) |
873 | continue; | 877 | continue; |
874 | 878 | ||
875 | iter->hash_head = iter->zone->fz_hash; | 879 | iter->hash_head = rcu_dereference(iter->zone->fz_hash); |
876 | maxslot = iter->zone->fz_divisor; | 880 | maxslot = iter->zone->fz_divisor; |
877 | 881 | ||
878 | for (iter->bucket = 0; iter->bucket < maxslot; | 882 | for (iter->bucket = 0; iter->bucket < maxslot; |
@@ -957,7 +961,7 @@ static struct fib_alias *fib_get_next(struct seq_file *seq) | |||
957 | goto out; | 961 | goto out; |
958 | 962 | ||
959 | iter->bucket = 0; | 963 | iter->bucket = 0; |
960 | iter->hash_head = iter->zone->fz_hash; | 964 | iter->hash_head = rcu_dereference(iter->zone->fz_hash); |
961 | 965 | ||
962 | hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) { | 966 | hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) { |
963 | list_for_each_entry(fa, &fn->fn_alias, fa_list) { | 967 | list_for_each_entry(fa, &fn->fn_alias, fa_list) { |
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c index caea6885fdbd..c6933f2ea310 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <net/gre.h> | 22 | #include <net/gre.h> |
23 | 23 | ||
24 | 24 | ||
25 | static const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly; | 25 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; |
26 | static DEFINE_SPINLOCK(gre_proto_lock); | 26 | static DEFINE_SPINLOCK(gre_proto_lock); |
27 | 27 | ||
28 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) | 28 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) |
@@ -51,7 +51,8 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version) | |||
51 | goto err_out; | 51 | goto err_out; |
52 | 52 | ||
53 | spin_lock(&gre_proto_lock); | 53 | spin_lock(&gre_proto_lock); |
54 | if (gre_proto[version] != proto) | 54 | if (rcu_dereference_protected(gre_proto[version], |
55 | lockdep_is_held(&gre_proto_lock)) != proto) | ||
55 | goto err_out_unlock; | 56 | goto err_out_unlock; |
56 | rcu_assign_pointer(gre_proto[version], NULL); | 57 | rcu_assign_pointer(gre_proto[version], NULL); |
57 | spin_unlock(&gre_proto_lock); | 58 | spin_unlock(&gre_proto_lock); |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 9ffa24b9a804..9e94d7cf4f8a 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -72,18 +72,19 @@ static struct kmem_cache *peer_cachep __read_mostly; | |||
72 | #define node_height(x) x->avl_height | 72 | #define node_height(x) x->avl_height |
73 | 73 | ||
74 | #define peer_avl_empty ((struct inet_peer *)&peer_fake_node) | 74 | #define peer_avl_empty ((struct inet_peer *)&peer_fake_node) |
75 | #define peer_avl_empty_rcu ((struct inet_peer __rcu __force *)&peer_fake_node) | ||
75 | static const struct inet_peer peer_fake_node = { | 76 | static const struct inet_peer peer_fake_node = { |
76 | .avl_left = peer_avl_empty, | 77 | .avl_left = peer_avl_empty_rcu, |
77 | .avl_right = peer_avl_empty, | 78 | .avl_right = peer_avl_empty_rcu, |
78 | .avl_height = 0 | 79 | .avl_height = 0 |
79 | }; | 80 | }; |
80 | 81 | ||
81 | static struct { | 82 | static struct { |
82 | struct inet_peer *root; | 83 | struct inet_peer __rcu *root; |
83 | spinlock_t lock; | 84 | spinlock_t lock; |
84 | int total; | 85 | int total; |
85 | } peers = { | 86 | } peers = { |
86 | .root = peer_avl_empty, | 87 | .root = peer_avl_empty_rcu, |
87 | .lock = __SPIN_LOCK_UNLOCKED(peers.lock), | 88 | .lock = __SPIN_LOCK_UNLOCKED(peers.lock), |
88 | .total = 0, | 89 | .total = 0, |
89 | }; | 90 | }; |
@@ -156,11 +157,14 @@ static void unlink_from_unused(struct inet_peer *p) | |||
156 | */ | 157 | */ |
157 | #define lookup(_daddr, _stack) \ | 158 | #define lookup(_daddr, _stack) \ |
158 | ({ \ | 159 | ({ \ |
159 | struct inet_peer *u, **v; \ | 160 | struct inet_peer *u; \ |
161 | struct inet_peer __rcu **v; \ | ||
160 | \ | 162 | \ |
161 | stackptr = _stack; \ | 163 | stackptr = _stack; \ |
162 | *stackptr++ = &peers.root; \ | 164 | *stackptr++ = &peers.root; \ |
163 | for (u = peers.root; u != peer_avl_empty; ) { \ | 165 | for (u = rcu_dereference_protected(peers.root, \ |
166 | lockdep_is_held(&peers.lock)); \ | ||
167 | u != peer_avl_empty; ) { \ | ||
164 | if (_daddr == u->v4daddr) \ | 168 | if (_daddr == u->v4daddr) \ |
165 | break; \ | 169 | break; \ |
166 | if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \ | 170 | if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \ |
@@ -168,7 +172,8 @@ static void unlink_from_unused(struct inet_peer *p) | |||
168 | else \ | 172 | else \ |
169 | v = &u->avl_right; \ | 173 | v = &u->avl_right; \ |
170 | *stackptr++ = v; \ | 174 | *stackptr++ = v; \ |
171 | u = *v; \ | 175 | u = rcu_dereference_protected(*v, \ |
176 | lockdep_is_held(&peers.lock)); \ | ||
172 | } \ | 177 | } \ |
173 | u; \ | 178 | u; \ |
174 | }) | 179 | }) |
@@ -209,13 +214,17 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr) | |||
209 | /* Called with local BH disabled and the pool lock held. */ | 214 | /* Called with local BH disabled and the pool lock held. */ |
210 | #define lookup_rightempty(start) \ | 215 | #define lookup_rightempty(start) \ |
211 | ({ \ | 216 | ({ \ |
212 | struct inet_peer *u, **v; \ | 217 | struct inet_peer *u; \ |
218 | struct inet_peer __rcu **v; \ | ||
213 | *stackptr++ = &start->avl_left; \ | 219 | *stackptr++ = &start->avl_left; \ |
214 | v = &start->avl_left; \ | 220 | v = &start->avl_left; \ |
215 | for (u = *v; u->avl_right != peer_avl_empty; ) { \ | 221 | for (u = rcu_dereference_protected(*v, \ |
222 | lockdep_is_held(&peers.lock)); \ | ||
223 | u->avl_right != peer_avl_empty_rcu; ) { \ | ||
216 | v = &u->avl_right; \ | 224 | v = &u->avl_right; \ |
217 | *stackptr++ = v; \ | 225 | *stackptr++ = v; \ |
218 | u = *v; \ | 226 | u = rcu_dereference_protected(*v, \ |
227 | lockdep_is_held(&peers.lock)); \ | ||
219 | } \ | 228 | } \ |
220 | u; \ | 229 | u; \ |
221 | }) | 230 | }) |
@@ -224,74 +233,86 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr) | |||
224 | * Variable names are the proof of operation correctness. | 233 | * Variable names are the proof of operation correctness. |
225 | * Look into mm/map_avl.c for more detail description of the ideas. | 234 | * Look into mm/map_avl.c for more detail description of the ideas. |
226 | */ | 235 | */ |
227 | static void peer_avl_rebalance(struct inet_peer **stack[], | 236 | static void peer_avl_rebalance(struct inet_peer __rcu **stack[], |
228 | struct inet_peer ***stackend) | 237 | struct inet_peer __rcu ***stackend) |
229 | { | 238 | { |
230 | struct inet_peer **nodep, *node, *l, *r; | 239 | struct inet_peer __rcu **nodep; |
240 | struct inet_peer *node, *l, *r; | ||
231 | int lh, rh; | 241 | int lh, rh; |
232 | 242 | ||
233 | while (stackend > stack) { | 243 | while (stackend > stack) { |
234 | nodep = *--stackend; | 244 | nodep = *--stackend; |
235 | node = *nodep; | 245 | node = rcu_dereference_protected(*nodep, |
236 | l = node->avl_left; | 246 | lockdep_is_held(&peers.lock)); |
237 | r = node->avl_right; | 247 | l = rcu_dereference_protected(node->avl_left, |
248 | lockdep_is_held(&peers.lock)); | ||
249 | r = rcu_dereference_protected(node->avl_right, | ||
250 | lockdep_is_held(&peers.lock)); | ||
238 | lh = node_height(l); | 251 | lh = node_height(l); |
239 | rh = node_height(r); | 252 | rh = node_height(r); |
240 | if (lh > rh + 1) { /* l: RH+2 */ | 253 | if (lh > rh + 1) { /* l: RH+2 */ |
241 | struct inet_peer *ll, *lr, *lrl, *lrr; | 254 | struct inet_peer *ll, *lr, *lrl, *lrr; |
242 | int lrh; | 255 | int lrh; |
243 | ll = l->avl_left; | 256 | ll = rcu_dereference_protected(l->avl_left, |
244 | lr = l->avl_right; | 257 | lockdep_is_held(&peers.lock)); |
258 | lr = rcu_dereference_protected(l->avl_right, | ||
259 | lockdep_is_held(&peers.lock)); | ||
245 | lrh = node_height(lr); | 260 | lrh = node_height(lr); |
246 | if (lrh <= node_height(ll)) { /* ll: RH+1 */ | 261 | if (lrh <= node_height(ll)) { /* ll: RH+1 */ |
247 | node->avl_left = lr; /* lr: RH or RH+1 */ | 262 | RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */ |
248 | node->avl_right = r; /* r: RH */ | 263 | RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ |
249 | node->avl_height = lrh + 1; /* RH+1 or RH+2 */ | 264 | node->avl_height = lrh + 1; /* RH+1 or RH+2 */ |
250 | l->avl_left = ll; /* ll: RH+1 */ | 265 | RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH+1 */ |
251 | l->avl_right = node; /* node: RH+1 or RH+2 */ | 266 | RCU_INIT_POINTER(l->avl_right, node); /* node: RH+1 or RH+2 */ |
252 | l->avl_height = node->avl_height + 1; | 267 | l->avl_height = node->avl_height + 1; |
253 | *nodep = l; | 268 | RCU_INIT_POINTER(*nodep, l); |
254 | } else { /* ll: RH, lr: RH+1 */ | 269 | } else { /* ll: RH, lr: RH+1 */ |
255 | lrl = lr->avl_left; /* lrl: RH or RH-1 */ | 270 | lrl = rcu_dereference_protected(lr->avl_left, |
256 | lrr = lr->avl_right; /* lrr: RH or RH-1 */ | 271 | lockdep_is_held(&peers.lock)); /* lrl: RH or RH-1 */ |
257 | node->avl_left = lrr; /* lrr: RH or RH-1 */ | 272 | lrr = rcu_dereference_protected(lr->avl_right, |
258 | node->avl_right = r; /* r: RH */ | 273 | lockdep_is_held(&peers.lock)); /* lrr: RH or RH-1 */ |
274 | RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */ | ||
275 | RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ | ||
259 | node->avl_height = rh + 1; /* node: RH+1 */ | 276 | node->avl_height = rh + 1; /* node: RH+1 */ |
260 | l->avl_left = ll; /* ll: RH */ | 277 | RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH */ |
261 | l->avl_right = lrl; /* lrl: RH or RH-1 */ | 278 | RCU_INIT_POINTER(l->avl_right, lrl); /* lrl: RH or RH-1 */ |
262 | l->avl_height = rh + 1; /* l: RH+1 */ | 279 | l->avl_height = rh + 1; /* l: RH+1 */ |
263 | lr->avl_left = l; /* l: RH+1 */ | 280 | RCU_INIT_POINTER(lr->avl_left, l); /* l: RH+1 */ |
264 | lr->avl_right = node; /* node: RH+1 */ | 281 | RCU_INIT_POINTER(lr->avl_right, node); /* node: RH+1 */ |
265 | lr->avl_height = rh + 2; | 282 | lr->avl_height = rh + 2; |
266 | *nodep = lr; | 283 | RCU_INIT_POINTER(*nodep, lr); |
267 | } | 284 | } |
268 | } else if (rh > lh + 1) { /* r: LH+2 */ | 285 | } else if (rh > lh + 1) { /* r: LH+2 */ |
269 | struct inet_peer *rr, *rl, *rlr, *rll; | 286 | struct inet_peer *rr, *rl, *rlr, *rll; |
270 | int rlh; | 287 | int rlh; |
271 | rr = r->avl_right; | 288 | rr = rcu_dereference_protected(r->avl_right, |
272 | rl = r->avl_left; | 289 | lockdep_is_held(&peers.lock)); |
290 | rl = rcu_dereference_protected(r->avl_left, | ||
291 | lockdep_is_held(&peers.lock)); | ||
273 | rlh = node_height(rl); | 292 | rlh = node_height(rl); |
274 | if (rlh <= node_height(rr)) { /* rr: LH+1 */ | 293 | if (rlh <= node_height(rr)) { /* rr: LH+1 */ |
275 | node->avl_right = rl; /* rl: LH or LH+1 */ | 294 | RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */ |
276 | node->avl_left = l; /* l: LH */ | 295 | RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ |
277 | node->avl_height = rlh + 1; /* LH+1 or LH+2 */ | 296 | node->avl_height = rlh + 1; /* LH+1 or LH+2 */ |
278 | r->avl_right = rr; /* rr: LH+1 */ | 297 | RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH+1 */ |
279 | r->avl_left = node; /* node: LH+1 or LH+2 */ | 298 | RCU_INIT_POINTER(r->avl_left, node); /* node: LH+1 or LH+2 */ |
280 | r->avl_height = node->avl_height + 1; | 299 | r->avl_height = node->avl_height + 1; |
281 | *nodep = r; | 300 | RCU_INIT_POINTER(*nodep, r); |
282 | } else { /* rr: RH, rl: RH+1 */ | 301 | } else { /* rr: RH, rl: RH+1 */ |
283 | rlr = rl->avl_right; /* rlr: LH or LH-1 */ | 302 | rlr = rcu_dereference_protected(rl->avl_right, |
284 | rll = rl->avl_left; /* rll: LH or LH-1 */ | 303 | lockdep_is_held(&peers.lock)); /* rlr: LH or LH-1 */ |
285 | node->avl_right = rll; /* rll: LH or LH-1 */ | 304 | rll = rcu_dereference_protected(rl->avl_left, |
286 | node->avl_left = l; /* l: LH */ | 305 | lockdep_is_held(&peers.lock)); /* rll: LH or LH-1 */ |
306 | RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */ | ||
307 | RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ | ||
287 | node->avl_height = lh + 1; /* node: LH+1 */ | 308 | node->avl_height = lh + 1; /* node: LH+1 */ |
288 | r->avl_right = rr; /* rr: LH */ | 309 | RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH */ |
289 | r->avl_left = rlr; /* rlr: LH or LH-1 */ | 310 | RCU_INIT_POINTER(r->avl_left, rlr); /* rlr: LH or LH-1 */ |
290 | r->avl_height = lh + 1; /* r: LH+1 */ | 311 | r->avl_height = lh + 1; /* r: LH+1 */ |
291 | rl->avl_right = r; /* r: LH+1 */ | 312 | RCU_INIT_POINTER(rl->avl_right, r); /* r: LH+1 */ |
292 | rl->avl_left = node; /* node: LH+1 */ | 313 | RCU_INIT_POINTER(rl->avl_left, node); /* node: LH+1 */ |
293 | rl->avl_height = lh + 2; | 314 | rl->avl_height = lh + 2; |
294 | *nodep = rl; | 315 | RCU_INIT_POINTER(*nodep, rl); |
295 | } | 316 | } |
296 | } else { | 317 | } else { |
297 | node->avl_height = (lh > rh ? lh : rh) + 1; | 318 | node->avl_height = (lh > rh ? lh : rh) + 1; |
@@ -303,10 +324,10 @@ static void peer_avl_rebalance(struct inet_peer **stack[], | |||
303 | #define link_to_pool(n) \ | 324 | #define link_to_pool(n) \ |
304 | do { \ | 325 | do { \ |
305 | n->avl_height = 1; \ | 326 | n->avl_height = 1; \ |
306 | n->avl_left = peer_avl_empty; \ | 327 | n->avl_left = peer_avl_empty_rcu; \ |
307 | n->avl_right = peer_avl_empty; \ | 328 | n->avl_right = peer_avl_empty_rcu; \ |
308 | smp_wmb(); /* lockless readers can catch us now */ \ | 329 | /* lockless readers can catch us now */ \ |
309 | **--stackptr = n; \ | 330 | rcu_assign_pointer(**--stackptr, n); \ |
310 | peer_avl_rebalance(stack, stackptr); \ | 331 | peer_avl_rebalance(stack, stackptr); \ |
311 | } while (0) | 332 | } while (0) |
312 | 333 | ||
@@ -330,24 +351,25 @@ static void unlink_from_pool(struct inet_peer *p) | |||
330 | * We use refcnt=-1 to alert lockless readers this entry is deleted. | 351 | * We use refcnt=-1 to alert lockless readers this entry is deleted. |
331 | */ | 352 | */ |
332 | if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) { | 353 | if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) { |
333 | struct inet_peer **stack[PEER_MAXDEPTH]; | 354 | struct inet_peer __rcu **stack[PEER_MAXDEPTH]; |
334 | struct inet_peer ***stackptr, ***delp; | 355 | struct inet_peer __rcu ***stackptr, ***delp; |
335 | if (lookup(p->v4daddr, stack) != p) | 356 | if (lookup(p->v4daddr, stack) != p) |
336 | BUG(); | 357 | BUG(); |
337 | delp = stackptr - 1; /* *delp[0] == p */ | 358 | delp = stackptr - 1; /* *delp[0] == p */ |
338 | if (p->avl_left == peer_avl_empty) { | 359 | if (p->avl_left == peer_avl_empty_rcu) { |
339 | *delp[0] = p->avl_right; | 360 | *delp[0] = p->avl_right; |
340 | --stackptr; | 361 | --stackptr; |
341 | } else { | 362 | } else { |
342 | /* look for a node to insert instead of p */ | 363 | /* look for a node to insert instead of p */ |
343 | struct inet_peer *t; | 364 | struct inet_peer *t; |
344 | t = lookup_rightempty(p); | 365 | t = lookup_rightempty(p); |
345 | BUG_ON(*stackptr[-1] != t); | 366 | BUG_ON(rcu_dereference_protected(*stackptr[-1], |
367 | lockdep_is_held(&peers.lock)) != t); | ||
346 | **--stackptr = t->avl_left; | 368 | **--stackptr = t->avl_left; |
347 | /* t is removed, t->v4daddr > x->v4daddr for any | 369 | /* t is removed, t->v4daddr > x->v4daddr for any |
348 | * x in p->avl_left subtree. | 370 | * x in p->avl_left subtree. |
349 | * Put t in the old place of p. */ | 371 | * Put t in the old place of p. */ |
350 | *delp[0] = t; | 372 | RCU_INIT_POINTER(*delp[0], t); |
351 | t->avl_left = p->avl_left; | 373 | t->avl_left = p->avl_left; |
352 | t->avl_right = p->avl_right; | 374 | t->avl_right = p->avl_right; |
353 | t->avl_height = p->avl_height; | 375 | t->avl_height = p->avl_height; |
@@ -414,7 +436,7 @@ static int cleanup_once(unsigned long ttl) | |||
414 | struct inet_peer *inet_getpeer(__be32 daddr, int create) | 436 | struct inet_peer *inet_getpeer(__be32 daddr, int create) |
415 | { | 437 | { |
416 | struct inet_peer *p; | 438 | struct inet_peer *p; |
417 | struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr; | 439 | struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr; |
418 | 440 | ||
419 | /* Look up for the address quickly, lockless. | 441 | /* Look up for the address quickly, lockless. |
420 | * Because of a concurrent writer, we might not find an existing entry. | 442 | * Because of a concurrent writer, we might not find an existing entry. |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d0ffcbe369b7..01087e035b7d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -1072,6 +1072,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1072 | break; | 1072 | break; |
1073 | } | 1073 | } |
1074 | ipgre_tunnel_unlink(ign, t); | 1074 | ipgre_tunnel_unlink(ign, t); |
1075 | synchronize_net(); | ||
1075 | t->parms.iph.saddr = p.iph.saddr; | 1076 | t->parms.iph.saddr = p.iph.saddr; |
1076 | t->parms.iph.daddr = p.iph.daddr; | 1077 | t->parms.iph.daddr = p.iph.daddr; |
1077 | t->parms.i_key = p.i_key; | 1078 | t->parms.i_key = p.i_key; |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 64b70ad162e3..3948c86e59ca 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -238,7 +238,7 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) | |||
238 | but receiver should be enough clever f.e. to forward mtrace requests, | 238 | but receiver should be enough clever f.e. to forward mtrace requests, |
239 | sent to multicast group to reach destination designated router. | 239 | sent to multicast group to reach destination designated router. |
240 | */ | 240 | */ |
241 | struct ip_ra_chain *ip_ra_chain; | 241 | struct ip_ra_chain __rcu *ip_ra_chain; |
242 | static DEFINE_SPINLOCK(ip_ra_lock); | 242 | static DEFINE_SPINLOCK(ip_ra_lock); |
243 | 243 | ||
244 | 244 | ||
@@ -253,7 +253,8 @@ static void ip_ra_destroy_rcu(struct rcu_head *head) | |||
253 | int ip_ra_control(struct sock *sk, unsigned char on, | 253 | int ip_ra_control(struct sock *sk, unsigned char on, |
254 | void (*destructor)(struct sock *)) | 254 | void (*destructor)(struct sock *)) |
255 | { | 255 | { |
256 | struct ip_ra_chain *ra, *new_ra, **rap; | 256 | struct ip_ra_chain *ra, *new_ra; |
257 | struct ip_ra_chain __rcu **rap; | ||
257 | 258 | ||
258 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW) | 259 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW) |
259 | return -EINVAL; | 260 | return -EINVAL; |
@@ -261,7 +262,10 @@ int ip_ra_control(struct sock *sk, unsigned char on, | |||
261 | new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; | 262 | new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
262 | 263 | ||
263 | spin_lock_bh(&ip_ra_lock); | 264 | spin_lock_bh(&ip_ra_lock); |
264 | for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { | 265 | for (rap = &ip_ra_chain; |
266 | (ra = rcu_dereference_protected(*rap, | ||
267 | lockdep_is_held(&ip_ra_lock))) != NULL; | ||
268 | rap = &ra->next) { | ||
265 | if (ra->sk == sk) { | 269 | if (ra->sk == sk) { |
266 | if (on) { | 270 | if (on) { |
267 | spin_unlock_bh(&ip_ra_lock); | 271 | spin_unlock_bh(&ip_ra_lock); |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index e9b816e6cd73..cd300aaee78f 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -676,6 +676,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
676 | } | 676 | } |
677 | t = netdev_priv(dev); | 677 | t = netdev_priv(dev); |
678 | ipip_tunnel_unlink(ipn, t); | 678 | ipip_tunnel_unlink(ipn, t); |
679 | synchronize_net(); | ||
679 | t->parms.iph.saddr = p.iph.saddr; | 680 | t->parms.iph.saddr = p.iph.saddr; |
680 | t->parms.iph.daddr = p.iph.daddr; | 681 | t->parms.iph.daddr = p.iph.daddr; |
681 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | 682 | memcpy(dev->dev_addr, &p.iph.saddr, 4); |
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index 65699c24411c..9ae5c01cd0b2 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <net/protocol.h> | 29 | #include <net/protocol.h> |
30 | 30 | ||
31 | const struct net_protocol *inet_protos[MAX_INET_PROTOS] __read_mostly; | 31 | const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly; |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Add a protocol handler to the hash tables | 34 | * Add a protocol handler to the hash tables |
@@ -38,7 +38,8 @@ int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) | |||
38 | { | 38 | { |
39 | int hash = protocol & (MAX_INET_PROTOS - 1); | 39 | int hash = protocol & (MAX_INET_PROTOS - 1); |
40 | 40 | ||
41 | return !cmpxchg(&inet_protos[hash], NULL, prot) ? 0 : -1; | 41 | return !cmpxchg((const struct net_protocol **)&inet_protos[hash], |
42 | NULL, prot) ? 0 : -1; | ||
42 | } | 43 | } |
43 | EXPORT_SYMBOL(inet_add_protocol); | 44 | EXPORT_SYMBOL(inet_add_protocol); |
44 | 45 | ||
@@ -50,7 +51,8 @@ int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol) | |||
50 | { | 51 | { |
51 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 52 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); |
52 | 53 | ||
53 | ret = (cmpxchg(&inet_protos[hash], prot, NULL) == prot) ? 0 : -1; | 54 | ret = (cmpxchg((const struct net_protocol **)&inet_protos[hash], |
55 | prot, NULL) == prot) ? 0 : -1; | ||
54 | 56 | ||
55 | synchronize_net(); | 57 | synchronize_net(); |
56 | 58 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d6cb2bfcd8e1..987bf9adb318 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -198,7 +198,7 @@ const __u8 ip_tos2prio[16] = { | |||
198 | */ | 198 | */ |
199 | 199 | ||
200 | struct rt_hash_bucket { | 200 | struct rt_hash_bucket { |
201 | struct rtable *chain; | 201 | struct rtable __rcu *chain; |
202 | }; | 202 | }; |
203 | 203 | ||
204 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \ | 204 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \ |
@@ -280,7 +280,7 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq) | |||
280 | struct rtable *r = NULL; | 280 | struct rtable *r = NULL; |
281 | 281 | ||
282 | for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { | 282 | for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { |
283 | if (!rt_hash_table[st->bucket].chain) | 283 | if (!rcu_dereference_raw(rt_hash_table[st->bucket].chain)) |
284 | continue; | 284 | continue; |
285 | rcu_read_lock_bh(); | 285 | rcu_read_lock_bh(); |
286 | r = rcu_dereference_bh(rt_hash_table[st->bucket].chain); | 286 | r = rcu_dereference_bh(rt_hash_table[st->bucket].chain); |
@@ -300,17 +300,17 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq, | |||
300 | { | 300 | { |
301 | struct rt_cache_iter_state *st = seq->private; | 301 | struct rt_cache_iter_state *st = seq->private; |
302 | 302 | ||
303 | r = r->dst.rt_next; | 303 | r = rcu_dereference_bh(r->dst.rt_next); |
304 | while (!r) { | 304 | while (!r) { |
305 | rcu_read_unlock_bh(); | 305 | rcu_read_unlock_bh(); |
306 | do { | 306 | do { |
307 | if (--st->bucket < 0) | 307 | if (--st->bucket < 0) |
308 | return NULL; | 308 | return NULL; |
309 | } while (!rt_hash_table[st->bucket].chain); | 309 | } while (!rcu_dereference_raw(rt_hash_table[st->bucket].chain)); |
310 | rcu_read_lock_bh(); | 310 | rcu_read_lock_bh(); |
311 | r = rt_hash_table[st->bucket].chain; | 311 | r = rcu_dereference_bh(rt_hash_table[st->bucket].chain); |
312 | } | 312 | } |
313 | return rcu_dereference_bh(r); | 313 | return r; |
314 | } | 314 | } |
315 | 315 | ||
316 | static struct rtable *rt_cache_get_next(struct seq_file *seq, | 316 | static struct rtable *rt_cache_get_next(struct seq_file *seq, |
@@ -721,19 +721,23 @@ static void rt_do_flush(int process_context) | |||
721 | for (i = 0; i <= rt_hash_mask; i++) { | 721 | for (i = 0; i <= rt_hash_mask; i++) { |
722 | if (process_context && need_resched()) | 722 | if (process_context && need_resched()) |
723 | cond_resched(); | 723 | cond_resched(); |
724 | rth = rt_hash_table[i].chain; | 724 | rth = rcu_dereference_raw(rt_hash_table[i].chain); |
725 | if (!rth) | 725 | if (!rth) |
726 | continue; | 726 | continue; |
727 | 727 | ||
728 | spin_lock_bh(rt_hash_lock_addr(i)); | 728 | spin_lock_bh(rt_hash_lock_addr(i)); |
729 | #ifdef CONFIG_NET_NS | 729 | #ifdef CONFIG_NET_NS |
730 | { | 730 | { |
731 | struct rtable ** prev, * p; | 731 | struct rtable __rcu **prev; |
732 | struct rtable *p; | ||
732 | 733 | ||
733 | rth = rt_hash_table[i].chain; | 734 | rth = rcu_dereference_protected(rt_hash_table[i].chain, |
735 | lockdep_is_held(rt_hash_lock_addr(i))); | ||
734 | 736 | ||
735 | /* defer releasing the head of the list after spin_unlock */ | 737 | /* defer releasing the head of the list after spin_unlock */ |
736 | for (tail = rth; tail; tail = tail->dst.rt_next) | 738 | for (tail = rth; tail; |
739 | tail = rcu_dereference_protected(tail->dst.rt_next, | ||
740 | lockdep_is_held(rt_hash_lock_addr(i)))) | ||
737 | if (!rt_is_expired(tail)) | 741 | if (!rt_is_expired(tail)) |
738 | break; | 742 | break; |
739 | if (rth != tail) | 743 | if (rth != tail) |
@@ -741,8 +745,12 @@ static void rt_do_flush(int process_context) | |||
741 | 745 | ||
742 | /* call rt_free on entries after the tail requiring flush */ | 746 | /* call rt_free on entries after the tail requiring flush */ |
743 | prev = &rt_hash_table[i].chain; | 747 | prev = &rt_hash_table[i].chain; |
744 | for (p = *prev; p; p = next) { | 748 | for (p = rcu_dereference_protected(*prev, |
745 | next = p->dst.rt_next; | 749 | lockdep_is_held(rt_hash_lock_addr(i))); |
750 | p != NULL; | ||
751 | p = next) { | ||
752 | next = rcu_dereference_protected(p->dst.rt_next, | ||
753 | lockdep_is_held(rt_hash_lock_addr(i))); | ||
746 | if (!rt_is_expired(p)) { | 754 | if (!rt_is_expired(p)) { |
747 | prev = &p->dst.rt_next; | 755 | prev = &p->dst.rt_next; |
748 | } else { | 756 | } else { |
@@ -752,14 +760,15 @@ static void rt_do_flush(int process_context) | |||
752 | } | 760 | } |
753 | } | 761 | } |
754 | #else | 762 | #else |
755 | rth = rt_hash_table[i].chain; | 763 | rth = rcu_dereference_protected(rt_hash_table[i].chain, |
756 | rt_hash_table[i].chain = NULL; | 764 | lockdep_is_held(rt_hash_lock_addr(i))); |
765 | rcu_assign_pointer(rt_hash_table[i].chain, NULL); | ||
757 | tail = NULL; | 766 | tail = NULL; |
758 | #endif | 767 | #endif |
759 | spin_unlock_bh(rt_hash_lock_addr(i)); | 768 | spin_unlock_bh(rt_hash_lock_addr(i)); |
760 | 769 | ||
761 | for (; rth != tail; rth = next) { | 770 | for (; rth != tail; rth = next) { |
762 | next = rth->dst.rt_next; | 771 | next = rcu_dereference_protected(rth->dst.rt_next, 1); |
763 | rt_free(rth); | 772 | rt_free(rth); |
764 | } | 773 | } |
765 | } | 774 | } |
@@ -790,7 +799,7 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth) | |||
790 | while (aux != rth) { | 799 | while (aux != rth) { |
791 | if (compare_hash_inputs(&aux->fl, &rth->fl)) | 800 | if (compare_hash_inputs(&aux->fl, &rth->fl)) |
792 | return 0; | 801 | return 0; |
793 | aux = aux->dst.rt_next; | 802 | aux = rcu_dereference_protected(aux->dst.rt_next, 1); |
794 | } | 803 | } |
795 | return ONE; | 804 | return ONE; |
796 | } | 805 | } |
@@ -799,7 +808,8 @@ static void rt_check_expire(void) | |||
799 | { | 808 | { |
800 | static unsigned int rover; | 809 | static unsigned int rover; |
801 | unsigned int i = rover, goal; | 810 | unsigned int i = rover, goal; |
802 | struct rtable *rth, **rthp; | 811 | struct rtable *rth; |
812 | struct rtable __rcu **rthp; | ||
803 | unsigned long samples = 0; | 813 | unsigned long samples = 0; |
804 | unsigned long sum = 0, sum2 = 0; | 814 | unsigned long sum = 0, sum2 = 0; |
805 | unsigned long delta; | 815 | unsigned long delta; |
@@ -825,11 +835,12 @@ static void rt_check_expire(void) | |||
825 | 835 | ||
826 | samples++; | 836 | samples++; |
827 | 837 | ||
828 | if (*rthp == NULL) | 838 | if (rcu_dereference_raw(*rthp) == NULL) |
829 | continue; | 839 | continue; |
830 | length = 0; | 840 | length = 0; |
831 | spin_lock_bh(rt_hash_lock_addr(i)); | 841 | spin_lock_bh(rt_hash_lock_addr(i)); |
832 | while ((rth = *rthp) != NULL) { | 842 | while ((rth = rcu_dereference_protected(*rthp, |
843 | lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) { | ||
833 | prefetch(rth->dst.rt_next); | 844 | prefetch(rth->dst.rt_next); |
834 | if (rt_is_expired(rth)) { | 845 | if (rt_is_expired(rth)) { |
835 | *rthp = rth->dst.rt_next; | 846 | *rthp = rth->dst.rt_next; |
@@ -941,7 +952,8 @@ static int rt_garbage_collect(struct dst_ops *ops) | |||
941 | static unsigned long last_gc; | 952 | static unsigned long last_gc; |
942 | static int rover; | 953 | static int rover; |
943 | static int equilibrium; | 954 | static int equilibrium; |
944 | struct rtable *rth, **rthp; | 955 | struct rtable *rth; |
956 | struct rtable __rcu **rthp; | ||
945 | unsigned long now = jiffies; | 957 | unsigned long now = jiffies; |
946 | int goal; | 958 | int goal; |
947 | int entries = dst_entries_get_fast(&ipv4_dst_ops); | 959 | int entries = dst_entries_get_fast(&ipv4_dst_ops); |
@@ -995,7 +1007,8 @@ static int rt_garbage_collect(struct dst_ops *ops) | |||
995 | k = (k + 1) & rt_hash_mask; | 1007 | k = (k + 1) & rt_hash_mask; |
996 | rthp = &rt_hash_table[k].chain; | 1008 | rthp = &rt_hash_table[k].chain; |
997 | spin_lock_bh(rt_hash_lock_addr(k)); | 1009 | spin_lock_bh(rt_hash_lock_addr(k)); |
998 | while ((rth = *rthp) != NULL) { | 1010 | while ((rth = rcu_dereference_protected(*rthp, |
1011 | lockdep_is_held(rt_hash_lock_addr(k)))) != NULL) { | ||
999 | if (!rt_is_expired(rth) && | 1012 | if (!rt_is_expired(rth) && |
1000 | !rt_may_expire(rth, tmo, expire)) { | 1013 | !rt_may_expire(rth, tmo, expire)) { |
1001 | tmo >>= 1; | 1014 | tmo >>= 1; |
@@ -1071,7 +1084,7 @@ static int slow_chain_length(const struct rtable *head) | |||
1071 | 1084 | ||
1072 | while (rth) { | 1085 | while (rth) { |
1073 | length += has_noalias(head, rth); | 1086 | length += has_noalias(head, rth); |
1074 | rth = rth->dst.rt_next; | 1087 | rth = rcu_dereference_protected(rth->dst.rt_next, 1); |
1075 | } | 1088 | } |
1076 | return length >> FRACT_BITS; | 1089 | return length >> FRACT_BITS; |
1077 | } | 1090 | } |
@@ -1079,9 +1092,9 @@ static int slow_chain_length(const struct rtable *head) | |||
1079 | static int rt_intern_hash(unsigned hash, struct rtable *rt, | 1092 | static int rt_intern_hash(unsigned hash, struct rtable *rt, |
1080 | struct rtable **rp, struct sk_buff *skb, int ifindex) | 1093 | struct rtable **rp, struct sk_buff *skb, int ifindex) |
1081 | { | 1094 | { |
1082 | struct rtable *rth, **rthp; | 1095 | struct rtable *rth, *cand; |
1096 | struct rtable __rcu **rthp, **candp; | ||
1083 | unsigned long now; | 1097 | unsigned long now; |
1084 | struct rtable *cand, **candp; | ||
1085 | u32 min_score; | 1098 | u32 min_score; |
1086 | int chain_length; | 1099 | int chain_length; |
1087 | int attempts = !in_softirq(); | 1100 | int attempts = !in_softirq(); |
@@ -1128,7 +1141,8 @@ restart: | |||
1128 | rthp = &rt_hash_table[hash].chain; | 1141 | rthp = &rt_hash_table[hash].chain; |
1129 | 1142 | ||
1130 | spin_lock_bh(rt_hash_lock_addr(hash)); | 1143 | spin_lock_bh(rt_hash_lock_addr(hash)); |
1131 | while ((rth = *rthp) != NULL) { | 1144 | while ((rth = rcu_dereference_protected(*rthp, |
1145 | lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) { | ||
1132 | if (rt_is_expired(rth)) { | 1146 | if (rt_is_expired(rth)) { |
1133 | *rthp = rth->dst.rt_next; | 1147 | *rthp = rth->dst.rt_next; |
1134 | rt_free(rth); | 1148 | rt_free(rth); |
@@ -1324,12 +1338,14 @@ EXPORT_SYMBOL(__ip_select_ident); | |||
1324 | 1338 | ||
1325 | static void rt_del(unsigned hash, struct rtable *rt) | 1339 | static void rt_del(unsigned hash, struct rtable *rt) |
1326 | { | 1340 | { |
1327 | struct rtable **rthp, *aux; | 1341 | struct rtable __rcu **rthp; |
1342 | struct rtable *aux; | ||
1328 | 1343 | ||
1329 | rthp = &rt_hash_table[hash].chain; | 1344 | rthp = &rt_hash_table[hash].chain; |
1330 | spin_lock_bh(rt_hash_lock_addr(hash)); | 1345 | spin_lock_bh(rt_hash_lock_addr(hash)); |
1331 | ip_rt_put(rt); | 1346 | ip_rt_put(rt); |
1332 | while ((aux = *rthp) != NULL) { | 1347 | while ((aux = rcu_dereference_protected(*rthp, |
1348 | lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) { | ||
1333 | if (aux == rt || rt_is_expired(aux)) { | 1349 | if (aux == rt || rt_is_expired(aux)) { |
1334 | *rthp = aux->dst.rt_next; | 1350 | *rthp = aux->dst.rt_next; |
1335 | rt_free(aux); | 1351 | rt_free(aux); |
@@ -1346,7 +1362,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1346 | { | 1362 | { |
1347 | int i, k; | 1363 | int i, k; |
1348 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 1364 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1349 | struct rtable *rth, **rthp; | 1365 | struct rtable *rth; |
1366 | struct rtable __rcu **rthp; | ||
1350 | __be32 skeys[2] = { saddr, 0 }; | 1367 | __be32 skeys[2] = { saddr, 0 }; |
1351 | int ikeys[2] = { dev->ifindex, 0 }; | 1368 | int ikeys[2] = { dev->ifindex, 0 }; |
1352 | struct netevent_redirect netevent; | 1369 | struct netevent_redirect netevent; |
@@ -1379,7 +1396,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1379 | unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], | 1396 | unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], |
1380 | rt_genid(net)); | 1397 | rt_genid(net)); |
1381 | 1398 | ||
1382 | rthp=&rt_hash_table[hash].chain; | 1399 | rthp = &rt_hash_table[hash].chain; |
1383 | 1400 | ||
1384 | while ((rth = rcu_dereference(*rthp)) != NULL) { | 1401 | while ((rth = rcu_dereference(*rthp)) != NULL) { |
1385 | struct rtable *rt; | 1402 | struct rtable *rt; |
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 9a17bd2a0a37..ac3b3ee4b07c 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c | |||
@@ -14,27 +14,32 @@ | |||
14 | #include <net/protocol.h> | 14 | #include <net/protocol.h> |
15 | #include <net/xfrm.h> | 15 | #include <net/xfrm.h> |
16 | 16 | ||
17 | static struct xfrm_tunnel *tunnel4_handlers __read_mostly; | 17 | static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; |
18 | static struct xfrm_tunnel *tunnel64_handlers __read_mostly; | 18 | static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; |
19 | static DEFINE_MUTEX(tunnel4_mutex); | 19 | static DEFINE_MUTEX(tunnel4_mutex); |
20 | 20 | ||
21 | static inline struct xfrm_tunnel **fam_handlers(unsigned short family) | 21 | static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) |
22 | { | 22 | { |
23 | return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; | 23 | return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; |
24 | } | 24 | } |
25 | 25 | ||
26 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) | 26 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) |
27 | { | 27 | { |
28 | struct xfrm_tunnel **pprev; | 28 | struct xfrm_tunnel __rcu **pprev; |
29 | struct xfrm_tunnel *t; | ||
30 | |||
29 | int ret = -EEXIST; | 31 | int ret = -EEXIST; |
30 | int priority = handler->priority; | 32 | int priority = handler->priority; |
31 | 33 | ||
32 | mutex_lock(&tunnel4_mutex); | 34 | mutex_lock(&tunnel4_mutex); |
33 | 35 | ||
34 | for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { | 36 | for (pprev = fam_handlers(family); |
35 | if ((*pprev)->priority > priority) | 37 | (t = rcu_dereference_protected(*pprev, |
38 | lockdep_is_held(&tunnel4_mutex))) != NULL; | ||
39 | pprev = &t->next) { | ||
40 | if (t->priority > priority) | ||
36 | break; | 41 | break; |
37 | if ((*pprev)->priority == priority) | 42 | if (t->priority == priority) |
38 | goto err; | 43 | goto err; |
39 | } | 44 | } |
40 | 45 | ||
@@ -52,13 +57,17 @@ EXPORT_SYMBOL(xfrm4_tunnel_register); | |||
52 | 57 | ||
53 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) | 58 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) |
54 | { | 59 | { |
55 | struct xfrm_tunnel **pprev; | 60 | struct xfrm_tunnel __rcu **pprev; |
61 | struct xfrm_tunnel *t; | ||
56 | int ret = -ENOENT; | 62 | int ret = -ENOENT; |
57 | 63 | ||
58 | mutex_lock(&tunnel4_mutex); | 64 | mutex_lock(&tunnel4_mutex); |
59 | 65 | ||
60 | for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { | 66 | for (pprev = fam_handlers(family); |
61 | if (*pprev == handler) { | 67 | (t = rcu_dereference_protected(*pprev, |
68 | lockdep_is_held(&tunnel4_mutex))) != NULL; | ||
69 | pprev = &t->next) { | ||
70 | if (t == handler) { | ||
62 | *pprev = handler->next; | 71 | *pprev = handler->next; |
63 | ret = 0; | 72 | ret = 0; |
64 | break; | 73 | break; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b3f7e8cf18ac..28cb2d733a3c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1413,7 +1413,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
1413 | } | 1413 | } |
1414 | } | 1414 | } |
1415 | 1415 | ||
1416 | if (sk->sk_filter) { | 1416 | if (rcu_dereference_raw(sk->sk_filter)) { |
1417 | if (udp_lib_checksum_complete(skb)) | 1417 | if (udp_lib_checksum_complete(skb)) |
1418 | goto drop; | 1418 | goto drop; |
1419 | } | 1419 | } |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ec7a91d9e865..e048ec62d109 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -836,7 +836,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
836 | { | 836 | { |
837 | struct inet6_dev *idev = ifp->idev; | 837 | struct inet6_dev *idev = ifp->idev; |
838 | struct in6_addr addr, *tmpaddr; | 838 | struct in6_addr addr, *tmpaddr; |
839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp; | 839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age; |
840 | unsigned long regen_advance; | 840 | unsigned long regen_advance; |
841 | int tmp_plen; | 841 | int tmp_plen; |
842 | int ret = 0; | 842 | int ret = 0; |
@@ -886,12 +886,13 @@ retry: | |||
886 | goto out; | 886 | goto out; |
887 | } | 887 | } |
888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); | 888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); |
889 | age = (jiffies - ifp->tstamp) / HZ; | ||
889 | tmp_valid_lft = min_t(__u32, | 890 | tmp_valid_lft = min_t(__u32, |
890 | ifp->valid_lft, | 891 | ifp->valid_lft, |
891 | idev->cnf.temp_valid_lft); | 892 | idev->cnf.temp_valid_lft + age); |
892 | tmp_prefered_lft = min_t(__u32, | 893 | tmp_prefered_lft = min_t(__u32, |
893 | ifp->prefered_lft, | 894 | ifp->prefered_lft, |
894 | idev->cnf.temp_prefered_lft - | 895 | idev->cnf.temp_prefered_lft + age - |
895 | idev->cnf.max_desync_factor); | 896 | idev->cnf.max_desync_factor); |
896 | tmp_plen = ifp->prefix_len; | 897 | tmp_plen = ifp->prefix_len; |
897 | max_addresses = idev->cnf.max_addresses; | 898 | max_addresses = idev->cnf.max_addresses; |
@@ -1426,8 +1427,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1426 | { | 1427 | { |
1427 | struct inet6_dev *idev = ifp->idev; | 1428 | struct inet6_dev *idev = ifp->idev; |
1428 | 1429 | ||
1429 | if (addrconf_dad_end(ifp)) | 1430 | if (addrconf_dad_end(ifp)) { |
1431 | in6_ifa_put(ifp); | ||
1430 | return; | 1432 | return; |
1433 | } | ||
1431 | 1434 | ||
1432 | if (net_ratelimit()) | 1435 | if (net_ratelimit()) |
1433 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", | 1436 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", |
@@ -2021,10 +2024,11 @@ ok: | |||
2021 | ipv6_ifa_notify(0, ift); | 2024 | ipv6_ifa_notify(0, ift); |
2022 | } | 2025 | } |
2023 | 2026 | ||
2024 | if (create && in6_dev->cnf.use_tempaddr > 0) { | 2027 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { |
2025 | /* | 2028 | /* |
2026 | * When a new public address is created as described in [ADDRCONF], | 2029 | * When a new public address is created as described in [ADDRCONF], |
2027 | * also create a new temporary address. | 2030 | * also create a new temporary address. Also create a temporary |
2031 | * address if it's enabled but no temporary address currently exists. | ||
2028 | */ | 2032 | */ |
2029 | read_unlock_bh(&in6_dev->lock); | 2033 | read_unlock_bh(&in6_dev->lock); |
2030 | ipv6_create_tempaddr(ifp, NULL); | 2034 | ipv6_create_tempaddr(ifp, NULL); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c2c0f89397b1..2a59610c2a58 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -1284,6 +1284,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1284 | t = netdev_priv(dev); | 1284 | t = netdev_priv(dev); |
1285 | 1285 | ||
1286 | ip6_tnl_unlink(ip6n, t); | 1286 | ip6_tnl_unlink(ip6n, t); |
1287 | synchronize_net(); | ||
1287 | err = ip6_tnl_change(t, &p); | 1288 | err = ip6_tnl_change(t, &p); |
1288 | ip6_tnl_link(ip6n, t); | 1289 | ip6_tnl_link(ip6n, t); |
1289 | netdev_state_change(dev); | 1290 | netdev_state_change(dev); |
@@ -1371,6 +1372,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev) | |||
1371 | dev->flags |= IFF_NOARP; | 1372 | dev->flags |= IFF_NOARP; |
1372 | dev->addr_len = sizeof(struct in6_addr); | 1373 | dev->addr_len = sizeof(struct in6_addr); |
1373 | dev->features |= NETIF_F_NETNS_LOCAL; | 1374 | dev->features |= NETIF_F_NETNS_LOCAL; |
1375 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
1374 | } | 1376 | } |
1375 | 1377 | ||
1376 | 1378 | ||
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0553867a317f..d1770e061c08 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -343,6 +343,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
343 | break; | 343 | break; |
344 | 344 | ||
345 | case IPV6_TRANSPARENT: | 345 | case IPV6_TRANSPARENT: |
346 | if (!capable(CAP_NET_ADMIN)) { | ||
347 | retv = -EPERM; | ||
348 | break; | ||
349 | } | ||
346 | if (optlen < sizeof(int)) | 350 | if (optlen < sizeof(int)) |
347 | goto e_inval; | 351 | goto e_inval; |
348 | /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ | 352 | /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 44d2eeac089b..448464844a25 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -5,10 +5,15 @@ | |||
5 | menu "IPv6: Netfilter Configuration" | 5 | menu "IPv6: Netfilter Configuration" |
6 | depends on INET && IPV6 && NETFILTER | 6 | depends on INET && IPV6 && NETFILTER |
7 | 7 | ||
8 | config NF_DEFRAG_IPV6 | ||
9 | tristate | ||
10 | default n | ||
11 | |||
8 | config NF_CONNTRACK_IPV6 | 12 | config NF_CONNTRACK_IPV6 |
9 | tristate "IPv6 connection tracking support" | 13 | tristate "IPv6 connection tracking support" |
10 | depends on INET && IPV6 && NF_CONNTRACK | 14 | depends on INET && IPV6 && NF_CONNTRACK |
11 | default m if NETFILTER_ADVANCED=n | 15 | default m if NETFILTER_ADVANCED=n |
16 | select NF_DEFRAG_IPV6 | ||
12 | ---help--- | 17 | ---help--- |
13 | Connection tracking keeps a record of what packets have passed | 18 | Connection tracking keeps a record of what packets have passed |
14 | through your machine, in order to figure out how they are related | 19 | through your machine, in order to figure out how they are related |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 3f8e4a3d83ce..0a432c9b0795 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -12,11 +12,14 @@ obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | |||
12 | 12 | ||
13 | # objects for l3 independent conntrack | 13 | # objects for l3 independent conntrack |
14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o | 14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o |
15 | nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | ||
16 | 15 | ||
17 | # l3 independent conntrack | 16 | # l3 independent conntrack |
18 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o |
19 | 18 | ||
19 | # defrag | ||
20 | nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | ||
21 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | ||
22 | |||
20 | # matches | 23 | # matches |
21 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 24 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
22 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o | 25 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 489d71b844ac..3a3f129a44cb 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -625,21 +625,24 @@ int nf_ct_frag6_init(void) | |||
625 | inet_frags_init_net(&nf_init_frags); | 625 | inet_frags_init_net(&nf_init_frags); |
626 | inet_frags_init(&nf_frags); | 626 | inet_frags_init(&nf_frags); |
627 | 627 | ||
628 | #ifdef CONFIG_SYSCTL | ||
628 | nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path, | 629 | nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path, |
629 | nf_ct_frag6_sysctl_table); | 630 | nf_ct_frag6_sysctl_table); |
630 | if (!nf_ct_frag6_sysctl_header) { | 631 | if (!nf_ct_frag6_sysctl_header) { |
631 | inet_frags_fini(&nf_frags); | 632 | inet_frags_fini(&nf_frags); |
632 | return -ENOMEM; | 633 | return -ENOMEM; |
633 | } | 634 | } |
635 | #endif | ||
634 | 636 | ||
635 | return 0; | 637 | return 0; |
636 | } | 638 | } |
637 | 639 | ||
638 | void nf_ct_frag6_cleanup(void) | 640 | void nf_ct_frag6_cleanup(void) |
639 | { | 641 | { |
642 | #ifdef CONFIG_SYSCTL | ||
640 | unregister_sysctl_table(nf_ct_frag6_sysctl_header); | 643 | unregister_sysctl_table(nf_ct_frag6_sysctl_header); |
641 | nf_ct_frag6_sysctl_header = NULL; | 644 | nf_ct_frag6_sysctl_header = NULL; |
642 | 645 | #endif | |
643 | inet_frags_fini(&nf_frags); | 646 | inet_frags_fini(&nf_frags); |
644 | 647 | ||
645 | nf_init_frags.low_thresh = 0; | 648 | nf_init_frags.low_thresh = 0; |
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 9bb936ae2452..9a7978fdc02a 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -25,13 +25,14 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
27 | 27 | ||
28 | const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] __read_mostly; | 28 | const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; |
29 | 29 | ||
30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
31 | { | 31 | { |
32 | int hash = protocol & (MAX_INET_PROTOS - 1); | 32 | int hash = protocol & (MAX_INET_PROTOS - 1); |
33 | 33 | ||
34 | return !cmpxchg(&inet6_protos[hash], NULL, prot) ? 0 : -1; | 34 | return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
35 | NULL, prot) ? 0 : -1; | ||
35 | } | 36 | } |
36 | EXPORT_SYMBOL(inet6_add_protocol); | 37 | EXPORT_SYMBOL(inet6_add_protocol); |
37 | 38 | ||
@@ -43,7 +44,8 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
43 | { | 44 | { |
44 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 45 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); |
45 | 46 | ||
46 | ret = (cmpxchg(&inet6_protos[hash], prot, NULL) == prot) ? 0 : -1; | 47 | ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
48 | prot, NULL) == prot) ? 0 : -1; | ||
47 | 49 | ||
48 | synchronize_net(); | 50 | synchronize_net(); |
49 | 51 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 45e6efb7f171..86c39526ba5e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -373,7 +373,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
373 | 373 | ||
374 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 374 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
375 | { | 375 | { |
376 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 376 | if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) && |
377 | skb_checksum_complete(skb)) { | 377 | skb_checksum_complete(skb)) { |
378 | atomic_inc(&sk->sk_drops); | 378 | atomic_inc(&sk->sk_drops); |
379 | kfree_skb(skb); | 379 | kfree_skb(skb); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 367a6cc584cc..d6bfaec3bbbf 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -963,6 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
963 | } | 963 | } |
964 | t = netdev_priv(dev); | 964 | t = netdev_priv(dev); |
965 | ipip6_tunnel_unlink(sitn, t); | 965 | ipip6_tunnel_unlink(sitn, t); |
966 | synchronize_net(); | ||
966 | t->parms.iph.saddr = p.iph.saddr; | 967 | t->parms.iph.saddr = p.iph.saddr; |
967 | t->parms.iph.daddr = p.iph.daddr; | 968 | t->parms.iph.daddr = p.iph.daddr; |
968 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | 969 | memcpy(dev->dev_addr, &p.iph.saddr, 4); |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index d9864725d0c6..4f3cec12aa85 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -30,23 +30,26 @@ | |||
30 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
31 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
32 | 32 | ||
33 | static struct xfrm6_tunnel *tunnel6_handlers __read_mostly; | 33 | static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly; |
34 | static struct xfrm6_tunnel *tunnel46_handlers __read_mostly; | 34 | static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly; |
35 | static DEFINE_MUTEX(tunnel6_mutex); | 35 | static DEFINE_MUTEX(tunnel6_mutex); |
36 | 36 | ||
37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) | 37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) |
38 | { | 38 | { |
39 | struct xfrm6_tunnel **pprev; | 39 | struct xfrm6_tunnel __rcu **pprev; |
40 | struct xfrm6_tunnel *t; | ||
40 | int ret = -EEXIST; | 41 | int ret = -EEXIST; |
41 | int priority = handler->priority; | 42 | int priority = handler->priority; |
42 | 43 | ||
43 | mutex_lock(&tunnel6_mutex); | 44 | mutex_lock(&tunnel6_mutex); |
44 | 45 | ||
45 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 46 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
46 | *pprev; pprev = &(*pprev)->next) { | 47 | (t = rcu_dereference_protected(*pprev, |
47 | if ((*pprev)->priority > priority) | 48 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
49 | pprev = &t->next) { | ||
50 | if (t->priority > priority) | ||
48 | break; | 51 | break; |
49 | if ((*pprev)->priority == priority) | 52 | if (t->priority == priority) |
50 | goto err; | 53 | goto err; |
51 | } | 54 | } |
52 | 55 | ||
@@ -65,14 +68,17 @@ EXPORT_SYMBOL(xfrm6_tunnel_register); | |||
65 | 68 | ||
66 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | 69 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) |
67 | { | 70 | { |
68 | struct xfrm6_tunnel **pprev; | 71 | struct xfrm6_tunnel __rcu **pprev; |
72 | struct xfrm6_tunnel *t; | ||
69 | int ret = -ENOENT; | 73 | int ret = -ENOENT; |
70 | 74 | ||
71 | mutex_lock(&tunnel6_mutex); | 75 | mutex_lock(&tunnel6_mutex); |
72 | 76 | ||
73 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 77 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
74 | *pprev; pprev = &(*pprev)->next) { | 78 | (t = rcu_dereference_protected(*pprev, |
75 | if (*pprev == handler) { | 79 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
80 | pprev = &t->next) { | ||
81 | if (t == handler) { | ||
76 | *pprev = handler->next; | 82 | *pprev = handler->next; |
77 | ret = 0; | 83 | ret = 0; |
78 | break; | 84 | break; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c84dad432114..91def93bec85 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -527,7 +527,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
527 | } | 527 | } |
528 | } | 528 | } |
529 | 529 | ||
530 | if (sk->sk_filter) { | 530 | if (rcu_dereference_raw(sk->sk_filter)) { |
531 | if (udp_lib_checksum_complete(skb)) | 531 | if (udp_lib_checksum_complete(skb)) |
532 | goto drop; | 532 | goto drop; |
533 | } | 533 | } |
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 1712af1c7b3f..c64ce0a0bb03 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -111,6 +111,10 @@ struct l2tp_net { | |||
111 | spinlock_t l2tp_session_hlist_lock; | 111 | spinlock_t l2tp_session_hlist_lock; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | static void l2tp_session_set_header_len(struct l2tp_session *session, int version); | ||
115 | static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); | ||
116 | static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); | ||
117 | |||
114 | static inline struct l2tp_net *l2tp_pernet(struct net *net) | 118 | static inline struct l2tp_net *l2tp_pernet(struct net *net) |
115 | { | 119 | { |
116 | BUG_ON(!net); | 120 | BUG_ON(!net); |
@@ -118,6 +122,34 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net) | |||
118 | return net_generic(net, l2tp_net_id); | 122 | return net_generic(net, l2tp_net_id); |
119 | } | 123 | } |
120 | 124 | ||
125 | |||
126 | /* Tunnel reference counts. Incremented per session that is added to | ||
127 | * the tunnel. | ||
128 | */ | ||
129 | static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel) | ||
130 | { | ||
131 | atomic_inc(&tunnel->ref_count); | ||
132 | } | ||
133 | |||
134 | static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel) | ||
135 | { | ||
136 | if (atomic_dec_and_test(&tunnel->ref_count)) | ||
137 | l2tp_tunnel_free(tunnel); | ||
138 | } | ||
139 | #ifdef L2TP_REFCNT_DEBUG | ||
140 | #define l2tp_tunnel_inc_refcount(_t) do { \ | ||
141 | printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ | ||
142 | l2tp_tunnel_inc_refcount_1(_t); \ | ||
143 | } while (0) | ||
144 | #define l2tp_tunnel_dec_refcount(_t) do { \ | ||
145 | printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ | ||
146 | l2tp_tunnel_dec_refcount_1(_t); \ | ||
147 | } while (0) | ||
148 | #else | ||
149 | #define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t) | ||
150 | #define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t) | ||
151 | #endif | ||
152 | |||
121 | /* Session hash global list for L2TPv3. | 153 | /* Session hash global list for L2TPv3. |
122 | * The session_id SHOULD be random according to RFC3931, but several | 154 | * The session_id SHOULD be random according to RFC3931, but several |
123 | * L2TP implementations use incrementing session_ids. So we do a real | 155 | * L2TP implementations use incrementing session_ids. So we do a real |
@@ -699,8 +731,8 @@ EXPORT_SYMBOL(l2tp_recv_common); | |||
699 | * Returns 1 if the packet was not a good data packet and could not be | 731 | * Returns 1 if the packet was not a good data packet and could not be |
700 | * forwarded. All such packets are passed up to userspace to deal with. | 732 | * forwarded. All such packets are passed up to userspace to deal with. |
701 | */ | 733 | */ |
702 | int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | 734 | static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, |
703 | int (*payload_hook)(struct sk_buff *skb)) | 735 | int (*payload_hook)(struct sk_buff *skb)) |
704 | { | 736 | { |
705 | struct l2tp_session *session = NULL; | 737 | struct l2tp_session *session = NULL; |
706 | unsigned char *ptr, *optr; | 738 | unsigned char *ptr, *optr; |
@@ -812,7 +844,6 @@ error: | |||
812 | 844 | ||
813 | return 1; | 845 | return 1; |
814 | } | 846 | } |
815 | EXPORT_SYMBOL_GPL(l2tp_udp_recv_core); | ||
816 | 847 | ||
817 | /* UDP encapsulation receive handler. See net/ipv4/udp.c. | 848 | /* UDP encapsulation receive handler. See net/ipv4/udp.c. |
818 | * Return codes: | 849 | * Return codes: |
@@ -922,7 +953,8 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) | |||
922 | return bufp - optr; | 953 | return bufp - optr; |
923 | } | 954 | } |
924 | 955 | ||
925 | int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len) | 956 | static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, |
957 | size_t data_len) | ||
926 | { | 958 | { |
927 | struct l2tp_tunnel *tunnel = session->tunnel; | 959 | struct l2tp_tunnel *tunnel = session->tunnel; |
928 | unsigned int len = skb->len; | 960 | unsigned int len = skb->len; |
@@ -970,7 +1002,6 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat | |||
970 | 1002 | ||
971 | return 0; | 1003 | return 0; |
972 | } | 1004 | } |
973 | EXPORT_SYMBOL_GPL(l2tp_xmit_core); | ||
974 | 1005 | ||
975 | /* Automatically called when the skb is freed. | 1006 | /* Automatically called when the skb is freed. |
976 | */ | 1007 | */ |
@@ -1089,7 +1120,7 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb); | |||
1089 | * The tunnel context is deleted only when all session sockets have been | 1120 | * The tunnel context is deleted only when all session sockets have been |
1090 | * closed. | 1121 | * closed. |
1091 | */ | 1122 | */ |
1092 | void l2tp_tunnel_destruct(struct sock *sk) | 1123 | static void l2tp_tunnel_destruct(struct sock *sk) |
1093 | { | 1124 | { |
1094 | struct l2tp_tunnel *tunnel; | 1125 | struct l2tp_tunnel *tunnel; |
1095 | 1126 | ||
@@ -1128,11 +1159,10 @@ void l2tp_tunnel_destruct(struct sock *sk) | |||
1128 | end: | 1159 | end: |
1129 | return; | 1160 | return; |
1130 | } | 1161 | } |
1131 | EXPORT_SYMBOL(l2tp_tunnel_destruct); | ||
1132 | 1162 | ||
1133 | /* When the tunnel is closed, all the attached sessions need to go too. | 1163 | /* When the tunnel is closed, all the attached sessions need to go too. |
1134 | */ | 1164 | */ |
1135 | void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) | 1165 | static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) |
1136 | { | 1166 | { |
1137 | int hash; | 1167 | int hash; |
1138 | struct hlist_node *walk; | 1168 | struct hlist_node *walk; |
@@ -1193,12 +1223,11 @@ again: | |||
1193 | } | 1223 | } |
1194 | write_unlock_bh(&tunnel->hlist_lock); | 1224 | write_unlock_bh(&tunnel->hlist_lock); |
1195 | } | 1225 | } |
1196 | EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); | ||
1197 | 1226 | ||
1198 | /* Really kill the tunnel. | 1227 | /* Really kill the tunnel. |
1199 | * Come here only when all sessions have been cleared from the tunnel. | 1228 | * Come here only when all sessions have been cleared from the tunnel. |
1200 | */ | 1229 | */ |
1201 | void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) | 1230 | static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) |
1202 | { | 1231 | { |
1203 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | 1232 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); |
1204 | 1233 | ||
@@ -1217,7 +1246,6 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) | |||
1217 | atomic_dec(&l2tp_tunnel_count); | 1246 | atomic_dec(&l2tp_tunnel_count); |
1218 | kfree(tunnel); | 1247 | kfree(tunnel); |
1219 | } | 1248 | } |
1220 | EXPORT_SYMBOL_GPL(l2tp_tunnel_free); | ||
1221 | 1249 | ||
1222 | /* Create a socket for the tunnel, if one isn't set up by | 1250 | /* Create a socket for the tunnel, if one isn't set up by |
1223 | * userspace. This is used for static tunnels where there is no | 1251 | * userspace. This is used for static tunnels where there is no |
@@ -1512,7 +1540,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete); | |||
1512 | /* We come here whenever a session's send_seq, cookie_len or | 1540 | /* We come here whenever a session's send_seq, cookie_len or |
1513 | * l2specific_len parameters are set. | 1541 | * l2specific_len parameters are set. |
1514 | */ | 1542 | */ |
1515 | void l2tp_session_set_header_len(struct l2tp_session *session, int version) | 1543 | static void l2tp_session_set_header_len(struct l2tp_session *session, int version) |
1516 | { | 1544 | { |
1517 | if (version == L2TP_HDR_VER_2) { | 1545 | if (version == L2TP_HDR_VER_2) { |
1518 | session->hdr_len = 6; | 1546 | session->hdr_len = 6; |
@@ -1525,7 +1553,6 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version) | |||
1525 | } | 1553 | } |
1526 | 1554 | ||
1527 | } | 1555 | } |
1528 | EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); | ||
1529 | 1556 | ||
1530 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | 1557 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) |
1531 | { | 1558 | { |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index f0f318edd3f1..a16a48e79fab 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -231,48 +231,15 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i | |||
231 | extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); | 231 | extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); |
232 | extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); | 232 | extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); |
233 | extern int l2tp_session_delete(struct l2tp_session *session); | 233 | extern int l2tp_session_delete(struct l2tp_session *session); |
234 | extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); | ||
235 | extern void l2tp_session_free(struct l2tp_session *session); | 234 | extern void l2tp_session_free(struct l2tp_session *session); |
236 | extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); | 235 | extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); |
237 | extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb)); | ||
238 | extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); | 236 | extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); |
239 | 237 | ||
240 | extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len); | ||
241 | extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); | 238 | extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); |
242 | extern void l2tp_tunnel_destruct(struct sock *sk); | ||
243 | extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); | ||
244 | extern void l2tp_session_set_header_len(struct l2tp_session *session, int version); | ||
245 | 239 | ||
246 | extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops); | 240 | extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops); |
247 | extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); | 241 | extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); |
248 | 242 | ||
249 | /* Tunnel reference counts. Incremented per session that is added to | ||
250 | * the tunnel. | ||
251 | */ | ||
252 | static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel) | ||
253 | { | ||
254 | atomic_inc(&tunnel->ref_count); | ||
255 | } | ||
256 | |||
257 | static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel) | ||
258 | { | ||
259 | if (atomic_dec_and_test(&tunnel->ref_count)) | ||
260 | l2tp_tunnel_free(tunnel); | ||
261 | } | ||
262 | #ifdef L2TP_REFCNT_DEBUG | ||
263 | #define l2tp_tunnel_inc_refcount(_t) do { \ | ||
264 | printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ | ||
265 | l2tp_tunnel_inc_refcount_1(_t); \ | ||
266 | } while (0) | ||
267 | #define l2tp_tunnel_dec_refcount(_t) do { \ | ||
268 | printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ | ||
269 | l2tp_tunnel_dec_refcount_1(_t); \ | ||
270 | } while (0) | ||
271 | #else | ||
272 | #define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t) | ||
273 | #define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t) | ||
274 | #endif | ||
275 | |||
276 | /* Session reference counts. Incremented when code obtains a reference | 243 | /* Session reference counts. Incremented when code obtains a reference |
277 | * to a session. | 244 | * to a session. |
278 | */ | 245 | */ |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 1c770c0644d1..0bf6a59545ab 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -576,7 +576,7 @@ out: | |||
576 | return copied; | 576 | return copied; |
577 | } | 577 | } |
578 | 578 | ||
579 | struct proto l2tp_ip_prot = { | 579 | static struct proto l2tp_ip_prot = { |
580 | .name = "L2TP/IP", | 580 | .name = "L2TP/IP", |
581 | .owner = THIS_MODULE, | 581 | .owner = THIS_MODULE, |
582 | .init = l2tp_ip_open, | 582 | .init = l2tp_ip_open, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ff60c022f51d..239c4836a946 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -456,6 +456,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
456 | if (!sta) | 456 | if (!sta) |
457 | return NULL; | 457 | return NULL; |
458 | 458 | ||
459 | sta->last_rx = jiffies; | ||
459 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | 460 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); |
460 | 461 | ||
461 | /* make sure mandatory rates are always added */ | 462 | /* make sure mandatory rates are always added */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 22bc42b18991..6b322fa681f5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -748,7 +748,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
748 | hw->queues = IEEE80211_MAX_QUEUES; | 748 | hw->queues = IEEE80211_MAX_QUEUES; |
749 | 749 | ||
750 | local->workqueue = | 750 | local->workqueue = |
751 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); | 751 | alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0); |
752 | if (!local->workqueue) { | 752 | if (!local->workqueue) { |
753 | result = -ENOMEM; | 753 | result = -ENOMEM; |
754 | goto fail_workqueue; | 754 | goto fail_workqueue; |
@@ -962,12 +962,6 @@ static void __exit ieee80211_exit(void) | |||
962 | rc80211_minstrel_ht_exit(); | 962 | rc80211_minstrel_ht_exit(); |
963 | rc80211_minstrel_exit(); | 963 | rc80211_minstrel_exit(); |
964 | 964 | ||
965 | /* | ||
966 | * For key todo, it'll be empty by now but the work | ||
967 | * might still be scheduled. | ||
968 | */ | ||
969 | flush_scheduled_work(); | ||
970 | |||
971 | if (mesh_allocated) | 965 | if (mesh_allocated) |
972 | ieee80211s_stop(); | 966 | ieee80211s_stop(); |
973 | 967 | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 809cf230d251..33f76993da08 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -329,6 +329,9 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
329 | * if needed. | 329 | * if needed. |
330 | */ | 330 | */ |
331 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 331 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
332 | /* Skip invalid rates */ | ||
333 | if (info->control.rates[i].idx < 0) | ||
334 | break; | ||
332 | /* Rate masking supports only legacy rates for now */ | 335 | /* Rate masking supports only legacy rates for now */ |
333 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) | 336 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) |
334 | continue; | 337 | continue; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 43288259f4a1..1534f2b44caf 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -525,6 +525,7 @@ config NETFILTER_XT_TARGET_TPROXY | |||
525 | depends on NETFILTER_XTABLES | 525 | depends on NETFILTER_XTABLES |
526 | depends on NETFILTER_ADVANCED | 526 | depends on NETFILTER_ADVANCED |
527 | select NF_DEFRAG_IPV4 | 527 | select NF_DEFRAG_IPV4 |
528 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES | ||
528 | help | 529 | help |
529 | This option adds a `TPROXY' target, which is somewhat similar to | 530 | This option adds a `TPROXY' target, which is somewhat similar to |
530 | REDIRECT. It can only be used in the mangle table and is useful | 531 | REDIRECT. It can only be used in the mangle table and is useful |
@@ -927,6 +928,7 @@ config NETFILTER_XT_MATCH_SOCKET | |||
927 | depends on NETFILTER_ADVANCED | 928 | depends on NETFILTER_ADVANCED |
928 | depends on !NF_CONNTRACK || NF_CONNTRACK | 929 | depends on !NF_CONNTRACK || NF_CONNTRACK |
929 | select NF_DEFRAG_IPV4 | 930 | select NF_DEFRAG_IPV4 |
931 | select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES | ||
930 | help | 932 | help |
931 | This option adds a `socket' match, which can be used to match | 933 | This option adds a `socket' match, which can be used to match |
932 | packets for which a TCP or UDP socket lookup finds a valid socket. | 934 | packets for which a TCP or UDP socket lookup finds a valid socket. |
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index 19c482caf30b..640678f47a2a 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
@@ -21,7 +21,9 @@ | |||
21 | #include <linux/netfilter_ipv4/ip_tables.h> | 21 | #include <linux/netfilter_ipv4/ip_tables.h> |
22 | 22 | ||
23 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | 23 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
24 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 24 | |
25 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | ||
26 | #define XT_TPROXY_HAVE_IPV6 1 | ||
25 | #include <net/if_inet6.h> | 27 | #include <net/if_inet6.h> |
26 | #include <net/addrconf.h> | 28 | #include <net/addrconf.h> |
27 | #include <linux/netfilter_ipv6/ip6_tables.h> | 29 | #include <linux/netfilter_ipv6/ip6_tables.h> |
@@ -172,7 +174,7 @@ tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par) | |||
172 | return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value); | 174 | return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value); |
173 | } | 175 | } |
174 | 176 | ||
175 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 177 | #ifdef XT_TPROXY_HAVE_IPV6 |
176 | 178 | ||
177 | static inline const struct in6_addr * | 179 | static inline const struct in6_addr * |
178 | tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | 180 | tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, |
@@ -372,7 +374,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = { | |||
372 | .hooks = 1 << NF_INET_PRE_ROUTING, | 374 | .hooks = 1 << NF_INET_PRE_ROUTING, |
373 | .me = THIS_MODULE, | 375 | .me = THIS_MODULE, |
374 | }, | 376 | }, |
375 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 377 | #ifdef XT_TPROXY_HAVE_IPV6 |
376 | { | 378 | { |
377 | .name = "TPROXY", | 379 | .name = "TPROXY", |
378 | .family = NFPROTO_IPV6, | 380 | .family = NFPROTO_IPV6, |
@@ -391,7 +393,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = { | |||
391 | static int __init tproxy_tg_init(void) | 393 | static int __init tproxy_tg_init(void) |
392 | { | 394 | { |
393 | nf_defrag_ipv4_enable(); | 395 | nf_defrag_ipv4_enable(); |
394 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 396 | #ifdef XT_TPROXY_HAVE_IPV6 |
395 | nf_defrag_ipv6_enable(); | 397 | nf_defrag_ipv6_enable(); |
396 | #endif | 398 | #endif |
397 | 399 | ||
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 2dbd4c857735..d94a858dc52a 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <linux/netfilter/x_tables.h> | 15 | #include <linux/netfilter/x_tables.h> |
16 | #include <linux/netfilter_ipv4/ip_tables.h> | 16 | #include <linux/netfilter_ipv4/ip_tables.h> |
17 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
18 | #include <net/tcp.h> | 17 | #include <net/tcp.h> |
19 | #include <net/udp.h> | 18 | #include <net/udp.h> |
20 | #include <net/icmp.h> | 19 | #include <net/icmp.h> |
@@ -22,7 +21,12 @@ | |||
22 | #include <net/inet_sock.h> | 21 | #include <net/inet_sock.h> |
23 | #include <net/netfilter/nf_tproxy_core.h> | 22 | #include <net/netfilter/nf_tproxy_core.h> |
24 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | 23 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
24 | |||
25 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | ||
26 | #define XT_SOCKET_HAVE_IPV6 1 | ||
27 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
25 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | 28 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
29 | #endif | ||
26 | 30 | ||
27 | #include <linux/netfilter/xt_socket.h> | 31 | #include <linux/netfilter/xt_socket.h> |
28 | 32 | ||
@@ -186,7 +190,7 @@ socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par) | |||
186 | return socket_match(skb, par, par->matchinfo); | 190 | return socket_match(skb, par, par->matchinfo); |
187 | } | 191 | } |
188 | 192 | ||
189 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 193 | #ifdef XT_SOCKET_HAVE_IPV6 |
190 | 194 | ||
191 | static int | 195 | static int |
192 | extract_icmp6_fields(const struct sk_buff *skb, | 196 | extract_icmp6_fields(const struct sk_buff *skb, |
@@ -331,7 +335,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = { | |||
331 | (1 << NF_INET_LOCAL_IN), | 335 | (1 << NF_INET_LOCAL_IN), |
332 | .me = THIS_MODULE, | 336 | .me = THIS_MODULE, |
333 | }, | 337 | }, |
334 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 338 | #ifdef XT_SOCKET_HAVE_IPV6 |
335 | { | 339 | { |
336 | .name = "socket", | 340 | .name = "socket", |
337 | .revision = 1, | 341 | .revision = 1, |
@@ -348,7 +352,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = { | |||
348 | static int __init socket_mt_init(void) | 352 | static int __init socket_mt_init(void) |
349 | { | 353 | { |
350 | nf_defrag_ipv4_enable(); | 354 | nf_defrag_ipv4_enable(); |
351 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 355 | #ifdef XT_SOCKET_HAVE_IPV6 |
352 | nf_defrag_ipv6_enable(); | 356 | nf_defrag_ipv6_enable(); |
353 | #endif | 357 | #endif |
354 | 358 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index cd96ed3ccee4..478181d53c55 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -83,9 +83,9 @@ struct netlink_sock { | |||
83 | struct module *module; | 83 | struct module *module; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | struct listeners_rcu_head { | 86 | struct listeners { |
87 | struct rcu_head rcu_head; | 87 | struct rcu_head rcu; |
88 | void *ptr; | 88 | unsigned long masks[0]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | #define NETLINK_KERNEL_SOCKET 0x1 | 91 | #define NETLINK_KERNEL_SOCKET 0x1 |
@@ -119,7 +119,7 @@ struct nl_pid_hash { | |||
119 | struct netlink_table { | 119 | struct netlink_table { |
120 | struct nl_pid_hash hash; | 120 | struct nl_pid_hash hash; |
121 | struct hlist_head mc_list; | 121 | struct hlist_head mc_list; |
122 | unsigned long *listeners; | 122 | struct listeners __rcu *listeners; |
123 | unsigned int nl_nonroot; | 123 | unsigned int nl_nonroot; |
124 | unsigned int groups; | 124 | unsigned int groups; |
125 | struct mutex *cb_mutex; | 125 | struct mutex *cb_mutex; |
@@ -338,7 +338,7 @@ netlink_update_listeners(struct sock *sk) | |||
338 | if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) | 338 | if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) |
339 | mask |= nlk_sk(sk)->groups[i]; | 339 | mask |= nlk_sk(sk)->groups[i]; |
340 | } | 340 | } |
341 | tbl->listeners[i] = mask; | 341 | tbl->listeners->masks[i] = mask; |
342 | } | 342 | } |
343 | /* this function is only called with the netlink table "grabbed", which | 343 | /* this function is only called with the netlink table "grabbed", which |
344 | * makes sure updates are visible before bind or setsockopt return. */ | 344 | * makes sure updates are visible before bind or setsockopt return. */ |
@@ -936,7 +936,7 @@ EXPORT_SYMBOL(netlink_unicast); | |||
936 | int netlink_has_listeners(struct sock *sk, unsigned int group) | 936 | int netlink_has_listeners(struct sock *sk, unsigned int group) |
937 | { | 937 | { |
938 | int res = 0; | 938 | int res = 0; |
939 | unsigned long *listeners; | 939 | struct listeners *listeners; |
940 | 940 | ||
941 | BUG_ON(!netlink_is_kernel(sk)); | 941 | BUG_ON(!netlink_is_kernel(sk)); |
942 | 942 | ||
@@ -944,7 +944,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group) | |||
944 | listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); | 944 | listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); |
945 | 945 | ||
946 | if (group - 1 < nl_table[sk->sk_protocol].groups) | 946 | if (group - 1 < nl_table[sk->sk_protocol].groups) |
947 | res = test_bit(group - 1, listeners); | 947 | res = test_bit(group - 1, listeners->masks); |
948 | 948 | ||
949 | rcu_read_unlock(); | 949 | rcu_read_unlock(); |
950 | 950 | ||
@@ -1498,7 +1498,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1498 | struct socket *sock; | 1498 | struct socket *sock; |
1499 | struct sock *sk; | 1499 | struct sock *sk; |
1500 | struct netlink_sock *nlk; | 1500 | struct netlink_sock *nlk; |
1501 | unsigned long *listeners = NULL; | 1501 | struct listeners *listeners = NULL; |
1502 | 1502 | ||
1503 | BUG_ON(!nl_table); | 1503 | BUG_ON(!nl_table); |
1504 | 1504 | ||
@@ -1523,8 +1523,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1523 | if (groups < 32) | 1523 | if (groups < 32) |
1524 | groups = 32; | 1524 | groups = 32; |
1525 | 1525 | ||
1526 | listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), | 1526 | listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); |
1527 | GFP_KERNEL); | ||
1528 | if (!listeners) | 1527 | if (!listeners) |
1529 | goto out_sock_release; | 1528 | goto out_sock_release; |
1530 | 1529 | ||
@@ -1541,7 +1540,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1541 | netlink_table_grab(); | 1540 | netlink_table_grab(); |
1542 | if (!nl_table[unit].registered) { | 1541 | if (!nl_table[unit].registered) { |
1543 | nl_table[unit].groups = groups; | 1542 | nl_table[unit].groups = groups; |
1544 | nl_table[unit].listeners = listeners; | 1543 | rcu_assign_pointer(nl_table[unit].listeners, listeners); |
1545 | nl_table[unit].cb_mutex = cb_mutex; | 1544 | nl_table[unit].cb_mutex = cb_mutex; |
1546 | nl_table[unit].module = module; | 1545 | nl_table[unit].module = module; |
1547 | nl_table[unit].registered = 1; | 1546 | nl_table[unit].registered = 1; |
@@ -1572,43 +1571,28 @@ netlink_kernel_release(struct sock *sk) | |||
1572 | EXPORT_SYMBOL(netlink_kernel_release); | 1571 | EXPORT_SYMBOL(netlink_kernel_release); |
1573 | 1572 | ||
1574 | 1573 | ||
1575 | static void netlink_free_old_listeners(struct rcu_head *rcu_head) | 1574 | static void listeners_free_rcu(struct rcu_head *head) |
1576 | { | 1575 | { |
1577 | struct listeners_rcu_head *lrh; | 1576 | kfree(container_of(head, struct listeners, rcu)); |
1578 | |||
1579 | lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head); | ||
1580 | kfree(lrh->ptr); | ||
1581 | } | 1577 | } |
1582 | 1578 | ||
1583 | int __netlink_change_ngroups(struct sock *sk, unsigned int groups) | 1579 | int __netlink_change_ngroups(struct sock *sk, unsigned int groups) |
1584 | { | 1580 | { |
1585 | unsigned long *listeners, *old = NULL; | 1581 | struct listeners *new, *old; |
1586 | struct listeners_rcu_head *old_rcu_head; | ||
1587 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; | 1582 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; |
1588 | 1583 | ||
1589 | if (groups < 32) | 1584 | if (groups < 32) |
1590 | groups = 32; | 1585 | groups = 32; |
1591 | 1586 | ||
1592 | if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { | 1587 | if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { |
1593 | listeners = kzalloc(NLGRPSZ(groups) + | 1588 | new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); |
1594 | sizeof(struct listeners_rcu_head), | 1589 | if (!new) |
1595 | GFP_ATOMIC); | ||
1596 | if (!listeners) | ||
1597 | return -ENOMEM; | 1590 | return -ENOMEM; |
1598 | old = tbl->listeners; | 1591 | old = rcu_dereference_raw(tbl->listeners); |
1599 | memcpy(listeners, old, NLGRPSZ(tbl->groups)); | 1592 | memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); |
1600 | rcu_assign_pointer(tbl->listeners, listeners); | 1593 | rcu_assign_pointer(tbl->listeners, new); |
1601 | /* | 1594 | |
1602 | * Free the old memory after an RCU grace period so we | 1595 | call_rcu(&old->rcu, listeners_free_rcu); |
1603 | * don't leak it. We use call_rcu() here in order to be | ||
1604 | * able to call this function from atomic contexts. The | ||
1605 | * allocation of this memory will have reserved enough | ||
1606 | * space for struct listeners_rcu_head at the end. | ||
1607 | */ | ||
1608 | old_rcu_head = (void *)(tbl->listeners + | ||
1609 | NLGRPLONGS(tbl->groups)); | ||
1610 | old_rcu_head->ptr = old; | ||
1611 | call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners); | ||
1612 | } | 1596 | } |
1613 | tbl->groups = groups; | 1597 | tbl->groups = groups; |
1614 | 1598 | ||
@@ -2104,18 +2088,17 @@ static void __net_exit netlink_net_exit(struct net *net) | |||
2104 | 2088 | ||
2105 | static void __init netlink_add_usersock_entry(void) | 2089 | static void __init netlink_add_usersock_entry(void) |
2106 | { | 2090 | { |
2107 | unsigned long *listeners; | 2091 | struct listeners *listeners; |
2108 | int groups = 32; | 2092 | int groups = 32; |
2109 | 2093 | ||
2110 | listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), | 2094 | listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); |
2111 | GFP_KERNEL); | ||
2112 | if (!listeners) | 2095 | if (!listeners) |
2113 | panic("netlink_add_usersock_entry: Cannot allocate listneres\n"); | 2096 | panic("netlink_add_usersock_entry: Cannot allocate listeners\n"); |
2114 | 2097 | ||
2115 | netlink_table_grab(); | 2098 | netlink_table_grab(); |
2116 | 2099 | ||
2117 | nl_table[NETLINK_USERSOCK].groups = groups; | 2100 | nl_table[NETLINK_USERSOCK].groups = groups; |
2118 | nl_table[NETLINK_USERSOCK].listeners = listeners; | 2101 | rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); |
2119 | nl_table[NETLINK_USERSOCK].module = THIS_MODULE; | 2102 | nl_table[NETLINK_USERSOCK].module = THIS_MODULE; |
2120 | nl_table[NETLINK_USERSOCK].registered = 1; | 2103 | nl_table[NETLINK_USERSOCK].registered = 1; |
2121 | 2104 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d14bbf960c18..4b9f8912526c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1167,7 +1167,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1167 | return 0; | 1167 | return 0; |
1168 | return -EALREADY; | 1168 | return -EALREADY; |
1169 | } | 1169 | } |
1170 | return REG_INTERSECT; | 1170 | return 0; |
1171 | case NL80211_REGDOM_SET_BY_DRIVER: | 1171 | case NL80211_REGDOM_SET_BY_DRIVER: |
1172 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { | 1172 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { |
1173 | if (regdom_changes(pending_request->alpha2)) | 1173 | if (regdom_changes(pending_request->alpha2)) |