diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-29 10:55:45 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-29 10:55:45 -0400 |
| commit | 3dacbdad2401c06b97d8d754974233a70c165536 (patch) | |
| tree | dc33467f26190572eabf49f7dcac3cd8aa50a101 /net | |
| parent | 56a50adda49b2020156616c4eb15353e0f9ad7de (diff) | |
| parent | ac7c992cac0c8f276aa8e4a8273204a6db707bb3 (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: (24 commits)
e100: do not go D3 in shutdown unless system is powering off
netfilter: revised locking for x_tables
Bluetooth: Fix connection establishment with low security requirement
Bluetooth: Add different pairing timeout for Legacy Pairing
Bluetooth: Ensure that HCI sysfs add/del is preempt safe
net: Avoid extra wakeups of threads blocked in wait_for_packet()
net: Fix typo in net_device_ops description.
ipv4: Limit size of route cache hash table
Add reference to CAPI 2.0 standard
Documentation/isdn/INTERFACE.CAPI
update Documentation/isdn/00-INDEX
ixgbe: Fix WoL functionality for 82599 KX4 devices
veth: prevent oops caused by netdev destructor
xfrm: wrong hash value for temporary SA
forcedeth: tx timeout fix
net: Fix LL_MAX_HEADER for CONFIG_TR_MODULE
mlx4_en: Handle page allocation failure during receive
mlx4_en: Fix cleanup flow on cq activation
vlan: update vlan carrier state for admin up/down
netfilter: xt_recent: fix stack overread in compat code
...
Diffstat (limited to 'net')
| -rw-r--r-- | net/8021q/vlan.c | 2 | ||||
| -rw-r--r-- | net/8021q/vlan_dev.c | 5 | ||||
| -rw-r--r-- | net/bluetooth/hci_conn.c | 10 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 36 | ||||
| -rw-r--r-- | net/bluetooth/hci_sysfs.c | 37 | ||||
| -rw-r--r-- | net/bridge/br_netfilter.c | 10 | ||||
| -rw-r--r-- | net/core/datagram.c | 14 | ||||
| -rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 125 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 126 | ||||
| -rw-r--r-- | net/ipv4/route.c | 2 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 123 | ||||
| -rw-r--r-- | net/netfilter/Kconfig | 4 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_proto_dccp.c | 16 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_proto_udplite.c | 1 | ||||
| -rw-r--r-- | net/netfilter/x_tables.c | 53 | ||||
| -rw-r--r-- | net/netfilter/xt_recent.c | 9 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 6 |
17 files changed, 246 insertions, 333 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 2b7390e377b3..d1e10546eb85 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
| @@ -492,6 +492,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
| 492 | continue; | 492 | continue; |
| 493 | 493 | ||
| 494 | dev_change_flags(vlandev, flgs & ~IFF_UP); | 494 | dev_change_flags(vlandev, flgs & ~IFF_UP); |
| 495 | vlan_transfer_operstate(dev, vlandev); | ||
| 495 | } | 496 | } |
| 496 | break; | 497 | break; |
| 497 | 498 | ||
| @@ -507,6 +508,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
| 507 | continue; | 508 | continue; |
| 508 | 509 | ||
| 509 | dev_change_flags(vlandev, flgs | IFF_UP); | 510 | dev_change_flags(vlandev, flgs | IFF_UP); |
| 511 | vlan_transfer_operstate(dev, vlandev); | ||
| 510 | } | 512 | } |
| 511 | break; | 513 | break; |
| 512 | 514 | ||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6b0921364014..b4b9068e55a7 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -462,6 +462,7 @@ static int vlan_dev_open(struct net_device *dev) | |||
| 462 | if (vlan->flags & VLAN_FLAG_GVRP) | 462 | if (vlan->flags & VLAN_FLAG_GVRP) |
| 463 | vlan_gvrp_request_join(dev); | 463 | vlan_gvrp_request_join(dev); |
| 464 | 464 | ||
| 465 | netif_carrier_on(dev); | ||
| 465 | return 0; | 466 | return 0; |
| 466 | 467 | ||
| 467 | clear_allmulti: | 468 | clear_allmulti: |
| @@ -471,6 +472,7 @@ del_unicast: | |||
| 471 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) | 472 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
| 472 | dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); | 473 | dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); |
| 473 | out: | 474 | out: |
| 475 | netif_carrier_off(dev); | ||
| 474 | return err; | 476 | return err; |
| 475 | } | 477 | } |
| 476 | 478 | ||
| @@ -492,6 +494,7 @@ static int vlan_dev_stop(struct net_device *dev) | |||
| 492 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) | 494 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
| 493 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); | 495 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); |
| 494 | 496 | ||
| 497 | netif_carrier_off(dev); | ||
| 495 | return 0; | 498 | return 0; |
| 496 | } | 499 | } |
| 497 | 500 | ||
| @@ -612,6 +615,8 @@ static int vlan_dev_init(struct net_device *dev) | |||
| 612 | struct net_device *real_dev = vlan_dev_info(dev)->real_dev; | 615 | struct net_device *real_dev = vlan_dev_info(dev)->real_dev; |
| 613 | int subclass = 0; | 616 | int subclass = 0; |
| 614 | 617 | ||
| 618 | netif_carrier_off(dev); | ||
| 619 | |||
| 615 | /* IFF_BROADCAST|IFF_MULTICAST; ??? */ | 620 | /* IFF_BROADCAST|IFF_MULTICAST; ??? */ |
| 616 | dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI); | 621 | dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI); |
| 617 | dev->iflink = real_dev->ifindex; | 622 | dev->iflink = real_dev->ifindex; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1181db08d9de..375f4b4f7f79 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
| @@ -215,6 +215,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
| 215 | conn->state = BT_OPEN; | 215 | conn->state = BT_OPEN; |
| 216 | 216 | ||
| 217 | conn->power_save = 1; | 217 | conn->power_save = 1; |
| 218 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | ||
| 218 | 219 | ||
| 219 | switch (type) { | 220 | switch (type) { |
| 220 | case ACL_LINK: | 221 | case ACL_LINK: |
| @@ -424,12 +425,9 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) | |||
| 424 | if (sec_level == BT_SECURITY_SDP) | 425 | if (sec_level == BT_SECURITY_SDP) |
| 425 | return 1; | 426 | return 1; |
| 426 | 427 | ||
| 427 | if (sec_level == BT_SECURITY_LOW) { | 428 | if (sec_level == BT_SECURITY_LOW && |
| 428 | if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) | 429 | (!conn->ssp_mode || !conn->hdev->ssp_mode)) |
| 429 | return hci_conn_auth(conn, sec_level, auth_type); | 430 | return 1; |
| 430 | else | ||
| 431 | return 1; | ||
| 432 | } | ||
| 433 | 431 | ||
| 434 | if (conn->link_mode & HCI_LM_ENCRYPT) | 432 | if (conn->link_mode & HCI_LM_ENCRYPT) |
| 435 | return hci_conn_auth(conn, sec_level, auth_type); | 433 | return hci_conn_auth(conn, sec_level, auth_type); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 15f40ea8d544..4e7cb88e5da9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -883,6 +883,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
| 883 | if (conn->type == ACL_LINK) { | 883 | if (conn->type == ACL_LINK) { |
| 884 | conn->state = BT_CONFIG; | 884 | conn->state = BT_CONFIG; |
| 885 | hci_conn_hold(conn); | 885 | hci_conn_hold(conn); |
| 886 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | ||
| 886 | } else | 887 | } else |
| 887 | conn->state = BT_CONNECTED; | 888 | conn->state = BT_CONNECTED; |
| 888 | 889 | ||
| @@ -1063,9 +1064,14 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
| 1063 | hci_proto_connect_cfm(conn, ev->status); | 1064 | hci_proto_connect_cfm(conn, ev->status); |
| 1064 | hci_conn_put(conn); | 1065 | hci_conn_put(conn); |
| 1065 | } | 1066 | } |
| 1066 | } else | 1067 | } else { |
| 1067 | hci_auth_cfm(conn, ev->status); | 1068 | hci_auth_cfm(conn, ev->status); |
| 1068 | 1069 | ||
| 1070 | hci_conn_hold(conn); | ||
| 1071 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | ||
| 1072 | hci_conn_put(conn); | ||
| 1073 | } | ||
| 1074 | |||
| 1069 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { | 1075 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { |
| 1070 | if (!ev->status) { | 1076 | if (!ev->status) { |
| 1071 | struct hci_cp_set_conn_encrypt cp; | 1077 | struct hci_cp_set_conn_encrypt cp; |
| @@ -1479,7 +1485,21 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb | |||
| 1479 | 1485 | ||
| 1480 | static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1486 | static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 1481 | { | 1487 | { |
| 1488 | struct hci_ev_pin_code_req *ev = (void *) skb->data; | ||
| 1489 | struct hci_conn *conn; | ||
| 1490 | |||
| 1482 | BT_DBG("%s", hdev->name); | 1491 | BT_DBG("%s", hdev->name); |
| 1492 | |||
| 1493 | hci_dev_lock(hdev); | ||
| 1494 | |||
| 1495 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
| 1496 | if (conn) { | ||
| 1497 | hci_conn_hold(conn); | ||
| 1498 | conn->disc_timeout = HCI_PAIRING_TIMEOUT; | ||
| 1499 | hci_conn_put(conn); | ||
| 1500 | } | ||
| 1501 | |||
| 1502 | hci_dev_unlock(hdev); | ||
| 1483 | } | 1503 | } |
| 1484 | 1504 | ||
| 1485 | static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1505 | static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -1489,7 +1509,21 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff | |||
| 1489 | 1509 | ||
| 1490 | static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1510 | static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 1491 | { | 1511 | { |
| 1512 | struct hci_ev_link_key_notify *ev = (void *) skb->data; | ||
| 1513 | struct hci_conn *conn; | ||
| 1514 | |||
| 1492 | BT_DBG("%s", hdev->name); | 1515 | BT_DBG("%s", hdev->name); |
| 1516 | |||
| 1517 | hci_dev_lock(hdev); | ||
| 1518 | |||
| 1519 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
| 1520 | if (conn) { | ||
| 1521 | hci_conn_hold(conn); | ||
| 1522 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | ||
| 1523 | hci_conn_put(conn); | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | hci_dev_unlock(hdev); | ||
| 1493 | } | 1527 | } |
| 1494 | 1528 | ||
| 1495 | static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1529 | static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) |
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index ed82796d4a0f..b7c51082ddeb 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c | |||
| @@ -9,8 +9,7 @@ | |||
| 9 | struct class *bt_class = NULL; | 9 | struct class *bt_class = NULL; |
| 10 | EXPORT_SYMBOL_GPL(bt_class); | 10 | EXPORT_SYMBOL_GPL(bt_class); |
| 11 | 11 | ||
| 12 | static struct workqueue_struct *btaddconn; | 12 | static struct workqueue_struct *bluetooth; |
| 13 | static struct workqueue_struct *btdelconn; | ||
| 14 | 13 | ||
| 15 | static inline char *link_typetostr(int type) | 14 | static inline char *link_typetostr(int type) |
| 16 | { | 15 | { |
| @@ -88,9 +87,10 @@ static struct device_type bt_link = { | |||
| 88 | 87 | ||
| 89 | static void add_conn(struct work_struct *work) | 88 | static void add_conn(struct work_struct *work) |
| 90 | { | 89 | { |
| 91 | struct hci_conn *conn = container_of(work, struct hci_conn, work); | 90 | struct hci_conn *conn = container_of(work, struct hci_conn, work_add); |
| 92 | 91 | ||
| 93 | flush_workqueue(btdelconn); | 92 | /* ensure previous add/del is complete */ |
| 93 | flush_workqueue(bluetooth); | ||
| 94 | 94 | ||
| 95 | if (device_add(&conn->dev) < 0) { | 95 | if (device_add(&conn->dev) < 0) { |
| 96 | BT_ERR("Failed to register connection device"); | 96 | BT_ERR("Failed to register connection device"); |
| @@ -114,9 +114,9 @@ void hci_conn_add_sysfs(struct hci_conn *conn) | |||
| 114 | 114 | ||
| 115 | device_initialize(&conn->dev); | 115 | device_initialize(&conn->dev); |
| 116 | 116 | ||
| 117 | INIT_WORK(&conn->work, add_conn); | 117 | INIT_WORK(&conn->work_add, add_conn); |
| 118 | 118 | ||
| 119 | queue_work(btaddconn, &conn->work); | 119 | queue_work(bluetooth, &conn->work_add); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | /* | 122 | /* |
| @@ -131,9 +131,12 @@ static int __match_tty(struct device *dev, void *data) | |||
| 131 | 131 | ||
| 132 | static void del_conn(struct work_struct *work) | 132 | static void del_conn(struct work_struct *work) |
| 133 | { | 133 | { |
| 134 | struct hci_conn *conn = container_of(work, struct hci_conn, work); | 134 | struct hci_conn *conn = container_of(work, struct hci_conn, work_del); |
| 135 | struct hci_dev *hdev = conn->hdev; | 135 | struct hci_dev *hdev = conn->hdev; |
| 136 | 136 | ||
| 137 | /* ensure previous add/del is complete */ | ||
| 138 | flush_workqueue(bluetooth); | ||
| 139 | |||
| 137 | while (1) { | 140 | while (1) { |
| 138 | struct device *dev; | 141 | struct device *dev; |
| 139 | 142 | ||
| @@ -156,9 +159,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn) | |||
| 156 | if (!device_is_registered(&conn->dev)) | 159 | if (!device_is_registered(&conn->dev)) |
| 157 | return; | 160 | return; |
| 158 | 161 | ||
| 159 | INIT_WORK(&conn->work, del_conn); | 162 | INIT_WORK(&conn->work_del, del_conn); |
| 160 | 163 | ||
| 161 | queue_work(btdelconn, &conn->work); | 164 | queue_work(bluetooth, &conn->work_del); |
| 162 | } | 165 | } |
| 163 | 166 | ||
| 164 | static inline char *host_typetostr(int type) | 167 | static inline char *host_typetostr(int type) |
| @@ -435,20 +438,13 @@ void hci_unregister_sysfs(struct hci_dev *hdev) | |||
| 435 | 438 | ||
| 436 | int __init bt_sysfs_init(void) | 439 | int __init bt_sysfs_init(void) |
| 437 | { | 440 | { |
| 438 | btaddconn = create_singlethread_workqueue("btaddconn"); | 441 | bluetooth = create_singlethread_workqueue("bluetooth"); |
| 439 | if (!btaddconn) | 442 | if (!bluetooth) |
| 440 | return -ENOMEM; | ||
| 441 | |||
| 442 | btdelconn = create_singlethread_workqueue("btdelconn"); | ||
| 443 | if (!btdelconn) { | ||
| 444 | destroy_workqueue(btaddconn); | ||
| 445 | return -ENOMEM; | 443 | return -ENOMEM; |
| 446 | } | ||
| 447 | 444 | ||
| 448 | bt_class = class_create(THIS_MODULE, "bluetooth"); | 445 | bt_class = class_create(THIS_MODULE, "bluetooth"); |
| 449 | if (IS_ERR(bt_class)) { | 446 | if (IS_ERR(bt_class)) { |
| 450 | destroy_workqueue(btdelconn); | 447 | destroy_workqueue(bluetooth); |
| 451 | destroy_workqueue(btaddconn); | ||
| 452 | return PTR_ERR(bt_class); | 448 | return PTR_ERR(bt_class); |
| 453 | } | 449 | } |
| 454 | 450 | ||
| @@ -457,8 +453,7 @@ int __init bt_sysfs_init(void) | |||
| 457 | 453 | ||
| 458 | void bt_sysfs_cleanup(void) | 454 | void bt_sysfs_cleanup(void) |
| 459 | { | 455 | { |
| 460 | destroy_workqueue(btaddconn); | 456 | destroy_workqueue(bluetooth); |
| 461 | destroy_workqueue(btdelconn); | ||
| 462 | 457 | ||
| 463 | class_destroy(bt_class); | 458 | class_destroy(bt_class); |
| 464 | } | 459 | } |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 3953ac4214c8..e4a418fcb35b 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
| @@ -788,15 +788,23 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb, | |||
| 788 | return NF_STOLEN; | 788 | return NF_STOLEN; |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) | ||
| 791 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) | 792 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) |
| 792 | { | 793 | { |
| 793 | if (skb->protocol == htons(ETH_P_IP) && | 794 | if (skb->nfct != NULL && |
| 795 | (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) && | ||
| 794 | skb->len > skb->dev->mtu && | 796 | skb->len > skb->dev->mtu && |
| 795 | !skb_is_gso(skb)) | 797 | !skb_is_gso(skb)) |
| 796 | return ip_fragment(skb, br_dev_queue_push_xmit); | 798 | return ip_fragment(skb, br_dev_queue_push_xmit); |
| 797 | else | 799 | else |
| 798 | return br_dev_queue_push_xmit(skb); | 800 | return br_dev_queue_push_xmit(skb); |
| 799 | } | 801 | } |
| 802 | #else | ||
| 803 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) | ||
| 804 | { | ||
| 805 | return br_dev_queue_push_xmit(skb); | ||
| 806 | } | ||
| 807 | #endif | ||
| 800 | 808 | ||
| 801 | /* PF_BRIDGE/POST_ROUTING ********************************************/ | 809 | /* PF_BRIDGE/POST_ROUTING ********************************************/ |
| 802 | static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, | 810 | static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, |
diff --git a/net/core/datagram.c b/net/core/datagram.c index d0de644b378d..b01a76abe1d2 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
| @@ -64,13 +64,25 @@ static inline int connection_based(struct sock *sk) | |||
| 64 | return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM; | 64 | return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static int receiver_wake_function(wait_queue_t *wait, unsigned mode, int sync, | ||
| 68 | void *key) | ||
| 69 | { | ||
| 70 | unsigned long bits = (unsigned long)key; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * Avoid a wakeup if event not interesting for us | ||
| 74 | */ | ||
| 75 | if (bits && !(bits & (POLLIN | POLLERR))) | ||
| 76 | return 0; | ||
| 77 | return autoremove_wake_function(wait, mode, sync, key); | ||
| 78 | } | ||
| 67 | /* | 79 | /* |
| 68 | * Wait for a packet.. | 80 | * Wait for a packet.. |
| 69 | */ | 81 | */ |
| 70 | static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) | 82 | static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) |
| 71 | { | 83 | { |
| 72 | int error; | 84 | int error; |
| 73 | DEFINE_WAIT(wait); | 85 | DEFINE_WAIT_FUNC(wait, receiver_wake_function); |
| 74 | 86 | ||
| 75 | prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); | 87 | prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); |
| 76 | 88 | ||
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 5ba533d234db..831fe1879dc0 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
| @@ -253,9 +253,9 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
| 253 | indev = in ? in->name : nulldevname; | 253 | indev = in ? in->name : nulldevname; |
| 254 | outdev = out ? out->name : nulldevname; | 254 | outdev = out ? out->name : nulldevname; |
| 255 | 255 | ||
| 256 | rcu_read_lock_bh(); | 256 | xt_info_rdlock_bh(); |
| 257 | private = rcu_dereference(table->private); | 257 | private = table->private; |
| 258 | table_base = rcu_dereference(private->entries[smp_processor_id()]); | 258 | table_base = private->entries[smp_processor_id()]; |
| 259 | 259 | ||
| 260 | e = get_entry(table_base, private->hook_entry[hook]); | 260 | e = get_entry(table_base, private->hook_entry[hook]); |
| 261 | back = get_entry(table_base, private->underflow[hook]); | 261 | back = get_entry(table_base, private->underflow[hook]); |
| @@ -273,6 +273,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
| 273 | 273 | ||
| 274 | hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + | 274 | hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + |
| 275 | (2 * skb->dev->addr_len); | 275 | (2 * skb->dev->addr_len); |
| 276 | |||
| 276 | ADD_COUNTER(e->counters, hdr_len, 1); | 277 | ADD_COUNTER(e->counters, hdr_len, 1); |
| 277 | 278 | ||
| 278 | t = arpt_get_target(e); | 279 | t = arpt_get_target(e); |
| @@ -328,8 +329,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
| 328 | e = (void *)e + e->next_offset; | 329 | e = (void *)e + e->next_offset; |
| 329 | } | 330 | } |
| 330 | } while (!hotdrop); | 331 | } while (!hotdrop); |
| 331 | 332 | xt_info_rdunlock_bh(); | |
| 332 | rcu_read_unlock_bh(); | ||
| 333 | 333 | ||
| 334 | if (hotdrop) | 334 | if (hotdrop) |
| 335 | return NF_DROP; | 335 | return NF_DROP; |
| @@ -711,9 +711,12 @@ static void get_counters(const struct xt_table_info *t, | |||
| 711 | /* Instead of clearing (by a previous call to memset()) | 711 | /* Instead of clearing (by a previous call to memset()) |
| 712 | * the counters and using adds, we set the counters | 712 | * the counters and using adds, we set the counters |
| 713 | * with data used by 'current' CPU | 713 | * with data used by 'current' CPU |
| 714 | * We dont care about preemption here. | 714 | * |
| 715 | * Bottom half has to be disabled to prevent deadlock | ||
| 716 | * if new softirq were to run and call ipt_do_table | ||
| 715 | */ | 717 | */ |
| 716 | curcpu = raw_smp_processor_id(); | 718 | local_bh_disable(); |
| 719 | curcpu = smp_processor_id(); | ||
| 717 | 720 | ||
| 718 | i = 0; | 721 | i = 0; |
| 719 | ARPT_ENTRY_ITERATE(t->entries[curcpu], | 722 | ARPT_ENTRY_ITERATE(t->entries[curcpu], |
| @@ -726,73 +729,22 @@ static void get_counters(const struct xt_table_info *t, | |||
| 726 | if (cpu == curcpu) | 729 | if (cpu == curcpu) |
| 727 | continue; | 730 | continue; |
| 728 | i = 0; | 731 | i = 0; |
| 732 | xt_info_wrlock(cpu); | ||
| 729 | ARPT_ENTRY_ITERATE(t->entries[cpu], | 733 | ARPT_ENTRY_ITERATE(t->entries[cpu], |
| 730 | t->size, | 734 | t->size, |
| 731 | add_entry_to_counter, | 735 | add_entry_to_counter, |
| 732 | counters, | 736 | counters, |
| 733 | &i); | 737 | &i); |
| 738 | xt_info_wrunlock(cpu); | ||
| 734 | } | 739 | } |
| 735 | } | ||
| 736 | |||
| 737 | |||
| 738 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 739 | * and everything is OK. */ | ||
| 740 | static int | ||
| 741 | add_counter_to_entry(struct arpt_entry *e, | ||
| 742 | const struct xt_counters addme[], | ||
| 743 | unsigned int *i) | ||
| 744 | { | ||
| 745 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 746 | |||
| 747 | (*i)++; | ||
| 748 | return 0; | ||
| 749 | } | ||
| 750 | |||
| 751 | /* Take values from counters and add them back onto the current cpu */ | ||
| 752 | static void put_counters(struct xt_table_info *t, | ||
| 753 | const struct xt_counters counters[]) | ||
| 754 | { | ||
| 755 | unsigned int i, cpu; | ||
| 756 | |||
| 757 | local_bh_disable(); | ||
| 758 | cpu = smp_processor_id(); | ||
| 759 | i = 0; | ||
| 760 | ARPT_ENTRY_ITERATE(t->entries[cpu], | ||
| 761 | t->size, | ||
| 762 | add_counter_to_entry, | ||
| 763 | counters, | ||
| 764 | &i); | ||
| 765 | local_bh_enable(); | 740 | local_bh_enable(); |
| 766 | } | 741 | } |
| 767 | 742 | ||
| 768 | static inline int | ||
| 769 | zero_entry_counter(struct arpt_entry *e, void *arg) | ||
| 770 | { | ||
| 771 | e->counters.bcnt = 0; | ||
| 772 | e->counters.pcnt = 0; | ||
| 773 | return 0; | ||
| 774 | } | ||
| 775 | |||
| 776 | static void | ||
| 777 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
| 778 | { | ||
| 779 | unsigned int cpu; | ||
| 780 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
| 781 | |||
| 782 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
| 783 | for_each_possible_cpu(cpu) { | ||
| 784 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
| 785 | ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
| 786 | zero_entry_counter, NULL); | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | static struct xt_counters *alloc_counters(struct xt_table *table) | 743 | static struct xt_counters *alloc_counters(struct xt_table *table) |
| 791 | { | 744 | { |
| 792 | unsigned int countersize; | 745 | unsigned int countersize; |
| 793 | struct xt_counters *counters; | 746 | struct xt_counters *counters; |
| 794 | struct xt_table_info *private = table->private; | 747 | struct xt_table_info *private = table->private; |
| 795 | struct xt_table_info *info; | ||
| 796 | 748 | ||
| 797 | /* We need atomic snapshot of counters: rest doesn't change | 749 | /* We need atomic snapshot of counters: rest doesn't change |
| 798 | * (other than comefrom, which userspace doesn't care | 750 | * (other than comefrom, which userspace doesn't care |
| @@ -802,30 +754,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) | |||
| 802 | counters = vmalloc_node(countersize, numa_node_id()); | 754 | counters = vmalloc_node(countersize, numa_node_id()); |
| 803 | 755 | ||
| 804 | if (counters == NULL) | 756 | if (counters == NULL) |
| 805 | goto nomem; | 757 | return ERR_PTR(-ENOMEM); |
| 806 | |||
| 807 | info = xt_alloc_table_info(private->size); | ||
| 808 | if (!info) | ||
| 809 | goto free_counters; | ||
| 810 | |||
| 811 | clone_counters(info, private); | ||
| 812 | |||
| 813 | mutex_lock(&table->lock); | ||
| 814 | xt_table_entry_swap_rcu(private, info); | ||
| 815 | synchronize_net(); /* Wait until smoke has cleared */ | ||
| 816 | 758 | ||
| 817 | get_counters(info, counters); | 759 | get_counters(private, counters); |
| 818 | put_counters(private, counters); | ||
| 819 | mutex_unlock(&table->lock); | ||
| 820 | |||
| 821 | xt_free_table_info(info); | ||
| 822 | 760 | ||
| 823 | return counters; | 761 | return counters; |
| 824 | |||
| 825 | free_counters: | ||
| 826 | vfree(counters); | ||
| 827 | nomem: | ||
| 828 | return ERR_PTR(-ENOMEM); | ||
| 829 | } | 762 | } |
| 830 | 763 | ||
| 831 | static int copy_entries_to_user(unsigned int total_size, | 764 | static int copy_entries_to_user(unsigned int total_size, |
| @@ -1094,8 +1027,9 @@ static int __do_replace(struct net *net, const char *name, | |||
| 1094 | (newinfo->number <= oldinfo->initial_entries)) | 1027 | (newinfo->number <= oldinfo->initial_entries)) |
| 1095 | module_put(t->me); | 1028 | module_put(t->me); |
| 1096 | 1029 | ||
| 1097 | /* Get the old counters. */ | 1030 | /* Get the old counters, and synchronize with replace */ |
| 1098 | get_counters(oldinfo, counters); | 1031 | get_counters(oldinfo, counters); |
| 1032 | |||
| 1099 | /* Decrease module usage counts and free resource */ | 1033 | /* Decrease module usage counts and free resource */ |
| 1100 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1034 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1101 | ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1035 | ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, |
| @@ -1165,10 +1099,23 @@ static int do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1165 | return ret; | 1099 | return ret; |
| 1166 | } | 1100 | } |
| 1167 | 1101 | ||
| 1102 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1103 | * and everything is OK. */ | ||
| 1104 | static int | ||
| 1105 | add_counter_to_entry(struct arpt_entry *e, | ||
| 1106 | const struct xt_counters addme[], | ||
| 1107 | unsigned int *i) | ||
| 1108 | { | ||
| 1109 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1110 | |||
| 1111 | (*i)++; | ||
| 1112 | return 0; | ||
| 1113 | } | ||
| 1114 | |||
| 1168 | static int do_add_counters(struct net *net, void __user *user, unsigned int len, | 1115 | static int do_add_counters(struct net *net, void __user *user, unsigned int len, |
| 1169 | int compat) | 1116 | int compat) |
| 1170 | { | 1117 | { |
| 1171 | unsigned int i; | 1118 | unsigned int i, curcpu; |
| 1172 | struct xt_counters_info tmp; | 1119 | struct xt_counters_info tmp; |
| 1173 | struct xt_counters *paddc; | 1120 | struct xt_counters *paddc; |
| 1174 | unsigned int num_counters; | 1121 | unsigned int num_counters; |
| @@ -1224,26 +1171,26 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
| 1224 | goto free; | 1171 | goto free; |
| 1225 | } | 1172 | } |
| 1226 | 1173 | ||
| 1227 | mutex_lock(&t->lock); | 1174 | local_bh_disable(); |
| 1228 | private = t->private; | 1175 | private = t->private; |
| 1229 | if (private->number != num_counters) { | 1176 | if (private->number != num_counters) { |
| 1230 | ret = -EINVAL; | 1177 | ret = -EINVAL; |
| 1231 | goto unlock_up_free; | 1178 | goto unlock_up_free; |
| 1232 | } | 1179 | } |
| 1233 | 1180 | ||
| 1234 | preempt_disable(); | ||
| 1235 | i = 0; | 1181 | i = 0; |
| 1236 | /* Choose the copy that is on our node */ | 1182 | /* Choose the copy that is on our node */ |
| 1237 | loc_cpu_entry = private->entries[smp_processor_id()]; | 1183 | curcpu = smp_processor_id(); |
| 1184 | loc_cpu_entry = private->entries[curcpu]; | ||
| 1185 | xt_info_wrlock(curcpu); | ||
| 1238 | ARPT_ENTRY_ITERATE(loc_cpu_entry, | 1186 | ARPT_ENTRY_ITERATE(loc_cpu_entry, |
| 1239 | private->size, | 1187 | private->size, |
| 1240 | add_counter_to_entry, | 1188 | add_counter_to_entry, |
| 1241 | paddc, | 1189 | paddc, |
| 1242 | &i); | 1190 | &i); |
| 1243 | preempt_enable(); | 1191 | xt_info_wrunlock(curcpu); |
| 1244 | unlock_up_free: | 1192 | unlock_up_free: |
| 1245 | mutex_unlock(&t->lock); | 1193 | local_bh_enable(); |
| 1246 | |||
| 1247 | xt_table_unlock(t); | 1194 | xt_table_unlock(t); |
| 1248 | module_put(t->me); | 1195 | module_put(t->me); |
| 1249 | free: | 1196 | free: |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 810c0b62c7d4..2ec8d7290c40 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
| @@ -338,10 +338,9 @@ ipt_do_table(struct sk_buff *skb, | |||
| 338 | tgpar.hooknum = hook; | 338 | tgpar.hooknum = hook; |
| 339 | 339 | ||
| 340 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 340 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
| 341 | 341 | xt_info_rdlock_bh(); | |
| 342 | rcu_read_lock_bh(); | 342 | private = table->private; |
| 343 | private = rcu_dereference(table->private); | 343 | table_base = private->entries[smp_processor_id()]; |
| 344 | table_base = rcu_dereference(private->entries[smp_processor_id()]); | ||
| 345 | 344 | ||
| 346 | e = get_entry(table_base, private->hook_entry[hook]); | 345 | e = get_entry(table_base, private->hook_entry[hook]); |
| 347 | 346 | ||
| @@ -436,8 +435,7 @@ ipt_do_table(struct sk_buff *skb, | |||
| 436 | e = (void *)e + e->next_offset; | 435 | e = (void *)e + e->next_offset; |
| 437 | } | 436 | } |
| 438 | } while (!hotdrop); | 437 | } while (!hotdrop); |
| 439 | 438 | xt_info_rdunlock_bh(); | |
| 440 | rcu_read_unlock_bh(); | ||
| 441 | 439 | ||
| 442 | #ifdef DEBUG_ALLOW_ALL | 440 | #ifdef DEBUG_ALLOW_ALL |
| 443 | return NF_ACCEPT; | 441 | return NF_ACCEPT; |
| @@ -896,10 +894,13 @@ get_counters(const struct xt_table_info *t, | |||
| 896 | 894 | ||
| 897 | /* Instead of clearing (by a previous call to memset()) | 895 | /* Instead of clearing (by a previous call to memset()) |
| 898 | * the counters and using adds, we set the counters | 896 | * the counters and using adds, we set the counters |
| 899 | * with data used by 'current' CPU | 897 | * with data used by 'current' CPU. |
| 900 | * We dont care about preemption here. | 898 | * |
| 899 | * Bottom half has to be disabled to prevent deadlock | ||
| 900 | * if new softirq were to run and call ipt_do_table | ||
| 901 | */ | 901 | */ |
| 902 | curcpu = raw_smp_processor_id(); | 902 | local_bh_disable(); |
| 903 | curcpu = smp_processor_id(); | ||
| 903 | 904 | ||
| 904 | i = 0; | 905 | i = 0; |
| 905 | IPT_ENTRY_ITERATE(t->entries[curcpu], | 906 | IPT_ENTRY_ITERATE(t->entries[curcpu], |
| @@ -912,74 +913,22 @@ get_counters(const struct xt_table_info *t, | |||
| 912 | if (cpu == curcpu) | 913 | if (cpu == curcpu) |
| 913 | continue; | 914 | continue; |
| 914 | i = 0; | 915 | i = 0; |
| 916 | xt_info_wrlock(cpu); | ||
| 915 | IPT_ENTRY_ITERATE(t->entries[cpu], | 917 | IPT_ENTRY_ITERATE(t->entries[cpu], |
| 916 | t->size, | 918 | t->size, |
| 917 | add_entry_to_counter, | 919 | add_entry_to_counter, |
| 918 | counters, | 920 | counters, |
| 919 | &i); | 921 | &i); |
| 922 | xt_info_wrunlock(cpu); | ||
| 920 | } | 923 | } |
| 921 | |||
| 922 | } | ||
| 923 | |||
| 924 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 925 | * and everything is OK. */ | ||
| 926 | static int | ||
| 927 | add_counter_to_entry(struct ipt_entry *e, | ||
| 928 | const struct xt_counters addme[], | ||
| 929 | unsigned int *i) | ||
| 930 | { | ||
| 931 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 932 | |||
| 933 | (*i)++; | ||
| 934 | return 0; | ||
| 935 | } | ||
| 936 | |||
| 937 | /* Take values from counters and add them back onto the current cpu */ | ||
| 938 | static void put_counters(struct xt_table_info *t, | ||
| 939 | const struct xt_counters counters[]) | ||
| 940 | { | ||
| 941 | unsigned int i, cpu; | ||
| 942 | |||
| 943 | local_bh_disable(); | ||
| 944 | cpu = smp_processor_id(); | ||
| 945 | i = 0; | ||
| 946 | IPT_ENTRY_ITERATE(t->entries[cpu], | ||
| 947 | t->size, | ||
| 948 | add_counter_to_entry, | ||
| 949 | counters, | ||
| 950 | &i); | ||
| 951 | local_bh_enable(); | 924 | local_bh_enable(); |
| 952 | } | 925 | } |
| 953 | 926 | ||
| 954 | |||
| 955 | static inline int | ||
| 956 | zero_entry_counter(struct ipt_entry *e, void *arg) | ||
| 957 | { | ||
| 958 | e->counters.bcnt = 0; | ||
| 959 | e->counters.pcnt = 0; | ||
| 960 | return 0; | ||
| 961 | } | ||
| 962 | |||
| 963 | static void | ||
| 964 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
| 965 | { | ||
| 966 | unsigned int cpu; | ||
| 967 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
| 968 | |||
| 969 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
| 970 | for_each_possible_cpu(cpu) { | ||
| 971 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
| 972 | IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
| 973 | zero_entry_counter, NULL); | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | static struct xt_counters * alloc_counters(struct xt_table *table) | 927 | static struct xt_counters * alloc_counters(struct xt_table *table) |
| 978 | { | 928 | { |
| 979 | unsigned int countersize; | 929 | unsigned int countersize; |
| 980 | struct xt_counters *counters; | 930 | struct xt_counters *counters; |
| 981 | struct xt_table_info *private = table->private; | 931 | struct xt_table_info *private = table->private; |
| 982 | struct xt_table_info *info; | ||
| 983 | 932 | ||
| 984 | /* We need atomic snapshot of counters: rest doesn't change | 933 | /* We need atomic snapshot of counters: rest doesn't change |
| 985 | (other than comefrom, which userspace doesn't care | 934 | (other than comefrom, which userspace doesn't care |
| @@ -988,30 +937,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table) | |||
| 988 | counters = vmalloc_node(countersize, numa_node_id()); | 937 | counters = vmalloc_node(countersize, numa_node_id()); |
| 989 | 938 | ||
| 990 | if (counters == NULL) | 939 | if (counters == NULL) |
| 991 | goto nomem; | 940 | return ERR_PTR(-ENOMEM); |
| 992 | 941 | ||
| 993 | info = xt_alloc_table_info(private->size); | 942 | get_counters(private, counters); |
| 994 | if (!info) | ||
| 995 | goto free_counters; | ||
| 996 | |||
| 997 | clone_counters(info, private); | ||
| 998 | |||
| 999 | mutex_lock(&table->lock); | ||
| 1000 | xt_table_entry_swap_rcu(private, info); | ||
| 1001 | synchronize_net(); /* Wait until smoke has cleared */ | ||
| 1002 | |||
| 1003 | get_counters(info, counters); | ||
| 1004 | put_counters(private, counters); | ||
| 1005 | mutex_unlock(&table->lock); | ||
| 1006 | |||
| 1007 | xt_free_table_info(info); | ||
| 1008 | 943 | ||
| 1009 | return counters; | 944 | return counters; |
| 1010 | |||
| 1011 | free_counters: | ||
| 1012 | vfree(counters); | ||
| 1013 | nomem: | ||
| 1014 | return ERR_PTR(-ENOMEM); | ||
| 1015 | } | 945 | } |
| 1016 | 946 | ||
| 1017 | static int | 947 | static int |
| @@ -1306,8 +1236,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1306 | (newinfo->number <= oldinfo->initial_entries)) | 1236 | (newinfo->number <= oldinfo->initial_entries)) |
| 1307 | module_put(t->me); | 1237 | module_put(t->me); |
| 1308 | 1238 | ||
| 1309 | /* Get the old counters. */ | 1239 | /* Get the old counters, and synchronize with replace */ |
| 1310 | get_counters(oldinfo, counters); | 1240 | get_counters(oldinfo, counters); |
| 1241 | |||
| 1311 | /* Decrease module usage counts and free resource */ | 1242 | /* Decrease module usage counts and free resource */ |
| 1312 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1243 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1313 | IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1244 | IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, |
| @@ -1377,11 +1308,23 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1377 | return ret; | 1308 | return ret; |
| 1378 | } | 1309 | } |
| 1379 | 1310 | ||
| 1311 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1312 | * and everything is OK. */ | ||
| 1313 | static int | ||
| 1314 | add_counter_to_entry(struct ipt_entry *e, | ||
| 1315 | const struct xt_counters addme[], | ||
| 1316 | unsigned int *i) | ||
| 1317 | { | ||
| 1318 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1319 | |||
| 1320 | (*i)++; | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1380 | 1323 | ||
| 1381 | static int | 1324 | static int |
| 1382 | do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) | 1325 | do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) |
| 1383 | { | 1326 | { |
| 1384 | unsigned int i; | 1327 | unsigned int i, curcpu; |
| 1385 | struct xt_counters_info tmp; | 1328 | struct xt_counters_info tmp; |
| 1386 | struct xt_counters *paddc; | 1329 | struct xt_counters *paddc; |
| 1387 | unsigned int num_counters; | 1330 | unsigned int num_counters; |
| @@ -1437,25 +1380,26 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat | |||
| 1437 | goto free; | 1380 | goto free; |
| 1438 | } | 1381 | } |
| 1439 | 1382 | ||
| 1440 | mutex_lock(&t->lock); | 1383 | local_bh_disable(); |
| 1441 | private = t->private; | 1384 | private = t->private; |
| 1442 | if (private->number != num_counters) { | 1385 | if (private->number != num_counters) { |
| 1443 | ret = -EINVAL; | 1386 | ret = -EINVAL; |
| 1444 | goto unlock_up_free; | 1387 | goto unlock_up_free; |
| 1445 | } | 1388 | } |
| 1446 | 1389 | ||
| 1447 | preempt_disable(); | ||
| 1448 | i = 0; | 1390 | i = 0; |
| 1449 | /* Choose the copy that is on our node */ | 1391 | /* Choose the copy that is on our node */ |
| 1450 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1392 | curcpu = smp_processor_id(); |
| 1393 | loc_cpu_entry = private->entries[curcpu]; | ||
| 1394 | xt_info_wrlock(curcpu); | ||
| 1451 | IPT_ENTRY_ITERATE(loc_cpu_entry, | 1395 | IPT_ENTRY_ITERATE(loc_cpu_entry, |
| 1452 | private->size, | 1396 | private->size, |
| 1453 | add_counter_to_entry, | 1397 | add_counter_to_entry, |
| 1454 | paddc, | 1398 | paddc, |
| 1455 | &i); | 1399 | &i); |
| 1456 | preempt_enable(); | 1400 | xt_info_wrunlock(curcpu); |
| 1457 | unlock_up_free: | 1401 | unlock_up_free: |
| 1458 | mutex_unlock(&t->lock); | 1402 | local_bh_enable(); |
| 1459 | xt_table_unlock(t); | 1403 | xt_table_unlock(t); |
| 1460 | module_put(t->me); | 1404 | module_put(t->me); |
| 1461 | free: | 1405 | free: |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c40debe51b38..c4c60e9f068a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -3397,7 +3397,7 @@ int __init ip_rt_init(void) | |||
| 3397 | 0, | 3397 | 0, |
| 3398 | &rt_hash_log, | 3398 | &rt_hash_log, |
| 3399 | &rt_hash_mask, | 3399 | &rt_hash_mask, |
| 3400 | 0); | 3400 | rhash_entries ? 0 : 512 * 1024); |
| 3401 | memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); | 3401 | memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); |
| 3402 | rt_hash_lock_init(); | 3402 | rt_hash_lock_init(); |
| 3403 | 3403 | ||
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 800ae8542471..219e165aea10 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -365,9 +365,9 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 365 | 365 | ||
| 366 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 366 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
| 367 | 367 | ||
| 368 | rcu_read_lock_bh(); | 368 | xt_info_rdlock_bh(); |
| 369 | private = rcu_dereference(table->private); | 369 | private = table->private; |
| 370 | table_base = rcu_dereference(private->entries[smp_processor_id()]); | 370 | table_base = private->entries[smp_processor_id()]; |
| 371 | 371 | ||
| 372 | e = get_entry(table_base, private->hook_entry[hook]); | 372 | e = get_entry(table_base, private->hook_entry[hook]); |
| 373 | 373 | ||
| @@ -466,7 +466,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 466 | #ifdef CONFIG_NETFILTER_DEBUG | 466 | #ifdef CONFIG_NETFILTER_DEBUG |
| 467 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; | 467 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; |
| 468 | #endif | 468 | #endif |
| 469 | rcu_read_unlock_bh(); | 469 | xt_info_rdunlock_bh(); |
| 470 | 470 | ||
| 471 | #ifdef DEBUG_ALLOW_ALL | 471 | #ifdef DEBUG_ALLOW_ALL |
| 472 | return NF_ACCEPT; | 472 | return NF_ACCEPT; |
| @@ -926,9 +926,12 @@ get_counters(const struct xt_table_info *t, | |||
| 926 | /* Instead of clearing (by a previous call to memset()) | 926 | /* Instead of clearing (by a previous call to memset()) |
| 927 | * the counters and using adds, we set the counters | 927 | * the counters and using adds, we set the counters |
| 928 | * with data used by 'current' CPU | 928 | * with data used by 'current' CPU |
| 929 | * We dont care about preemption here. | 929 | * |
| 930 | * Bottom half has to be disabled to prevent deadlock | ||
| 931 | * if new softirq were to run and call ipt_do_table | ||
| 930 | */ | 932 | */ |
| 931 | curcpu = raw_smp_processor_id(); | 933 | local_bh_disable(); |
| 934 | curcpu = smp_processor_id(); | ||
| 932 | 935 | ||
| 933 | i = 0; | 936 | i = 0; |
| 934 | IP6T_ENTRY_ITERATE(t->entries[curcpu], | 937 | IP6T_ENTRY_ITERATE(t->entries[curcpu], |
| @@ -941,72 +944,22 @@ get_counters(const struct xt_table_info *t, | |||
| 941 | if (cpu == curcpu) | 944 | if (cpu == curcpu) |
| 942 | continue; | 945 | continue; |
| 943 | i = 0; | 946 | i = 0; |
| 947 | xt_info_wrlock(cpu); | ||
| 944 | IP6T_ENTRY_ITERATE(t->entries[cpu], | 948 | IP6T_ENTRY_ITERATE(t->entries[cpu], |
| 945 | t->size, | 949 | t->size, |
| 946 | add_entry_to_counter, | 950 | add_entry_to_counter, |
| 947 | counters, | 951 | counters, |
| 948 | &i); | 952 | &i); |
| 953 | xt_info_wrunlock(cpu); | ||
| 949 | } | 954 | } |
| 950 | } | ||
| 951 | |||
| 952 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 953 | * and everything is OK. */ | ||
| 954 | static int | ||
| 955 | add_counter_to_entry(struct ip6t_entry *e, | ||
| 956 | const struct xt_counters addme[], | ||
| 957 | unsigned int *i) | ||
| 958 | { | ||
| 959 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 960 | |||
| 961 | (*i)++; | ||
| 962 | return 0; | ||
| 963 | } | ||
| 964 | |||
| 965 | /* Take values from counters and add them back onto the current cpu */ | ||
| 966 | static void put_counters(struct xt_table_info *t, | ||
| 967 | const struct xt_counters counters[]) | ||
| 968 | { | ||
| 969 | unsigned int i, cpu; | ||
| 970 | |||
| 971 | local_bh_disable(); | ||
| 972 | cpu = smp_processor_id(); | ||
| 973 | i = 0; | ||
| 974 | IP6T_ENTRY_ITERATE(t->entries[cpu], | ||
| 975 | t->size, | ||
| 976 | add_counter_to_entry, | ||
| 977 | counters, | ||
| 978 | &i); | ||
| 979 | local_bh_enable(); | 955 | local_bh_enable(); |
| 980 | } | 956 | } |
| 981 | 957 | ||
| 982 | static inline int | ||
| 983 | zero_entry_counter(struct ip6t_entry *e, void *arg) | ||
| 984 | { | ||
| 985 | e->counters.bcnt = 0; | ||
| 986 | e->counters.pcnt = 0; | ||
| 987 | return 0; | ||
| 988 | } | ||
| 989 | |||
| 990 | static void | ||
| 991 | clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | ||
| 992 | { | ||
| 993 | unsigned int cpu; | ||
| 994 | const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | ||
| 995 | |||
| 996 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | ||
| 997 | for_each_possible_cpu(cpu) { | ||
| 998 | memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | ||
| 999 | IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | ||
| 1000 | zero_entry_counter, NULL); | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static struct xt_counters *alloc_counters(struct xt_table *table) | 958 | static struct xt_counters *alloc_counters(struct xt_table *table) |
| 1005 | { | 959 | { |
| 1006 | unsigned int countersize; | 960 | unsigned int countersize; |
| 1007 | struct xt_counters *counters; | 961 | struct xt_counters *counters; |
| 1008 | struct xt_table_info *private = table->private; | 962 | struct xt_table_info *private = table->private; |
| 1009 | struct xt_table_info *info; | ||
| 1010 | 963 | ||
| 1011 | /* We need atomic snapshot of counters: rest doesn't change | 964 | /* We need atomic snapshot of counters: rest doesn't change |
| 1012 | (other than comefrom, which userspace doesn't care | 965 | (other than comefrom, which userspace doesn't care |
| @@ -1015,30 +968,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) | |||
| 1015 | counters = vmalloc_node(countersize, numa_node_id()); | 968 | counters = vmalloc_node(countersize, numa_node_id()); |
| 1016 | 969 | ||
| 1017 | if (counters == NULL) | 970 | if (counters == NULL) |
| 1018 | goto nomem; | 971 | return ERR_PTR(-ENOMEM); |
| 1019 | 972 | ||
| 1020 | info = xt_alloc_table_info(private->size); | 973 | get_counters(private, counters); |
| 1021 | if (!info) | ||
| 1022 | goto free_counters; | ||
| 1023 | |||
| 1024 | clone_counters(info, private); | ||
| 1025 | |||
| 1026 | mutex_lock(&table->lock); | ||
| 1027 | xt_table_entry_swap_rcu(private, info); | ||
| 1028 | synchronize_net(); /* Wait until smoke has cleared */ | ||
| 1029 | |||
| 1030 | get_counters(info, counters); | ||
| 1031 | put_counters(private, counters); | ||
| 1032 | mutex_unlock(&table->lock); | ||
| 1033 | |||
| 1034 | xt_free_table_info(info); | ||
| 1035 | 974 | ||
| 1036 | return counters; | 975 | return counters; |
| 1037 | |||
| 1038 | free_counters: | ||
| 1039 | vfree(counters); | ||
| 1040 | nomem: | ||
| 1041 | return ERR_PTR(-ENOMEM); | ||
| 1042 | } | 976 | } |
| 1043 | 977 | ||
| 1044 | static int | 978 | static int |
| @@ -1334,8 +1268,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1334 | (newinfo->number <= oldinfo->initial_entries)) | 1268 | (newinfo->number <= oldinfo->initial_entries)) |
| 1335 | module_put(t->me); | 1269 | module_put(t->me); |
| 1336 | 1270 | ||
| 1337 | /* Get the old counters. */ | 1271 | /* Get the old counters, and synchronize with replace */ |
| 1338 | get_counters(oldinfo, counters); | 1272 | get_counters(oldinfo, counters); |
| 1273 | |||
| 1339 | /* Decrease module usage counts and free resource */ | 1274 | /* Decrease module usage counts and free resource */ |
| 1340 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1275 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1341 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1276 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, |
| @@ -1405,11 +1340,24 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1405 | return ret; | 1340 | return ret; |
| 1406 | } | 1341 | } |
| 1407 | 1342 | ||
| 1343 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1344 | * and everything is OK. */ | ||
| 1345 | static int | ||
| 1346 | add_counter_to_entry(struct ip6t_entry *e, | ||
| 1347 | const struct xt_counters addme[], | ||
| 1348 | unsigned int *i) | ||
| 1349 | { | ||
| 1350 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1351 | |||
| 1352 | (*i)++; | ||
| 1353 | return 0; | ||
| 1354 | } | ||
| 1355 | |||
| 1408 | static int | 1356 | static int |
| 1409 | do_add_counters(struct net *net, void __user *user, unsigned int len, | 1357 | do_add_counters(struct net *net, void __user *user, unsigned int len, |
| 1410 | int compat) | 1358 | int compat) |
| 1411 | { | 1359 | { |
| 1412 | unsigned int i; | 1360 | unsigned int i, curcpu; |
| 1413 | struct xt_counters_info tmp; | 1361 | struct xt_counters_info tmp; |
| 1414 | struct xt_counters *paddc; | 1362 | struct xt_counters *paddc; |
| 1415 | unsigned int num_counters; | 1363 | unsigned int num_counters; |
| @@ -1465,25 +1413,28 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
| 1465 | goto free; | 1413 | goto free; |
| 1466 | } | 1414 | } |
| 1467 | 1415 | ||
| 1468 | mutex_lock(&t->lock); | 1416 | |
| 1417 | local_bh_disable(); | ||
| 1469 | private = t->private; | 1418 | private = t->private; |
| 1470 | if (private->number != num_counters) { | 1419 | if (private->number != num_counters) { |
| 1471 | ret = -EINVAL; | 1420 | ret = -EINVAL; |
| 1472 | goto unlock_up_free; | 1421 | goto unlock_up_free; |
| 1473 | } | 1422 | } |
| 1474 | 1423 | ||
| 1475 | preempt_disable(); | ||
| 1476 | i = 0; | 1424 | i = 0; |
| 1477 | /* Choose the copy that is on our node */ | 1425 | /* Choose the copy that is on our node */ |
| 1478 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1426 | curcpu = smp_processor_id(); |
| 1427 | xt_info_wrlock(curcpu); | ||
| 1428 | loc_cpu_entry = private->entries[curcpu]; | ||
| 1479 | IP6T_ENTRY_ITERATE(loc_cpu_entry, | 1429 | IP6T_ENTRY_ITERATE(loc_cpu_entry, |
| 1480 | private->size, | 1430 | private->size, |
| 1481 | add_counter_to_entry, | 1431 | add_counter_to_entry, |
| 1482 | paddc, | 1432 | paddc, |
| 1483 | &i); | 1433 | &i); |
| 1484 | preempt_enable(); | 1434 | xt_info_wrunlock(curcpu); |
| 1435 | |||
| 1485 | unlock_up_free: | 1436 | unlock_up_free: |
| 1486 | mutex_unlock(&t->lock); | 1437 | local_bh_enable(); |
| 1487 | xt_table_unlock(t); | 1438 | xt_table_unlock(t); |
| 1488 | module_put(t->me); | 1439 | module_put(t->me); |
| 1489 | free: | 1440 | free: |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 2329c5f50551..881203c4a142 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
| @@ -275,6 +275,8 @@ config NF_CT_NETLINK | |||
| 275 | help | 275 | help |
| 276 | This option enables support for a netlink-based userspace interface | 276 | This option enables support for a netlink-based userspace interface |
| 277 | 277 | ||
| 278 | endif # NF_CONNTRACK | ||
| 279 | |||
| 278 | # transparent proxy support | 280 | # transparent proxy support |
| 279 | config NETFILTER_TPROXY | 281 | config NETFILTER_TPROXY |
| 280 | tristate "Transparent proxying support (EXPERIMENTAL)" | 282 | tristate "Transparent proxying support (EXPERIMENTAL)" |
| @@ -290,8 +292,6 @@ config NETFILTER_TPROXY | |||
| 290 | 292 | ||
| 291 | To compile it as a module, choose M here. If unsure, say N. | 293 | To compile it as a module, choose M here. If unsure, say N. |
| 292 | 294 | ||
| 293 | endif # NF_CONNTRACK | ||
| 294 | |||
| 295 | config NETFILTER_XTABLES | 295 | config NETFILTER_XTABLES |
| 296 | tristate "Netfilter Xtables support (required for ip_tables)" | 296 | tristate "Netfilter Xtables support (required for ip_tables)" |
| 297 | default m if NETFILTER_ADVANCED=n | 297 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 50dac8dbe7d8..8e757dd53396 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
| @@ -633,6 +633,8 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, | |||
| 633 | if (!nest_parms) | 633 | if (!nest_parms) |
| 634 | goto nla_put_failure; | 634 | goto nla_put_failure; |
| 635 | NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); | 635 | NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); |
| 636 | NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE, | ||
| 637 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]); | ||
| 636 | nla_nest_end(skb, nest_parms); | 638 | nla_nest_end(skb, nest_parms); |
| 637 | read_unlock_bh(&dccp_lock); | 639 | read_unlock_bh(&dccp_lock); |
| 638 | return 0; | 640 | return 0; |
| @@ -644,6 +646,7 @@ nla_put_failure: | |||
| 644 | 646 | ||
| 645 | static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { | 647 | static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { |
| 646 | [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, | 648 | [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, |
| 649 | [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, | ||
| 647 | }; | 650 | }; |
| 648 | 651 | ||
| 649 | static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | 652 | static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) |
| @@ -661,11 +664,21 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | |||
| 661 | return err; | 664 | return err; |
| 662 | 665 | ||
| 663 | if (!tb[CTA_PROTOINFO_DCCP_STATE] || | 666 | if (!tb[CTA_PROTOINFO_DCCP_STATE] || |
| 664 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) | 667 | !tb[CTA_PROTOINFO_DCCP_ROLE] || |
| 668 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX || | ||
| 669 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) { | ||
| 665 | return -EINVAL; | 670 | return -EINVAL; |
| 671 | } | ||
| 666 | 672 | ||
| 667 | write_lock_bh(&dccp_lock); | 673 | write_lock_bh(&dccp_lock); |
| 668 | ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); | 674 | ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); |
| 675 | if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { | ||
| 676 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; | ||
| 677 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; | ||
| 678 | } else { | ||
| 679 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; | ||
| 680 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; | ||
| 681 | } | ||
| 669 | write_unlock_bh(&dccp_lock); | 682 | write_unlock_bh(&dccp_lock); |
| 670 | return 0; | 683 | return 0; |
| 671 | } | 684 | } |
| @@ -777,6 +790,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
| 777 | .print_conntrack = dccp_print_conntrack, | 790 | .print_conntrack = dccp_print_conntrack, |
| 778 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 791 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
| 779 | .to_nlattr = dccp_to_nlattr, | 792 | .to_nlattr = dccp_to_nlattr, |
| 793 | .nlattr_size = dccp_nlattr_size, | ||
| 780 | .from_nlattr = nlattr_to_dccp, | 794 | .from_nlattr = nlattr_to_dccp, |
| 781 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 795 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
| 782 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 796 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 4614696c1b88..0badedc542d3 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
| @@ -204,6 +204,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = | |||
| 204 | .error = udplite_error, | 204 | .error = udplite_error, |
| 205 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 205 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
| 206 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 206 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
| 207 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
| 207 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 208 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
| 208 | .nla_policy = nf_ct_port_nla_policy, | 209 | .nla_policy = nf_ct_port_nla_policy, |
| 209 | #endif | 210 | #endif |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 509a95621f9f..150e5cf62f85 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
| @@ -625,20 +625,6 @@ void xt_free_table_info(struct xt_table_info *info) | |||
| 625 | } | 625 | } |
| 626 | EXPORT_SYMBOL(xt_free_table_info); | 626 | EXPORT_SYMBOL(xt_free_table_info); |
| 627 | 627 | ||
| 628 | void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo, | ||
| 629 | struct xt_table_info *newinfo) | ||
| 630 | { | ||
| 631 | unsigned int cpu; | ||
| 632 | |||
| 633 | for_each_possible_cpu(cpu) { | ||
| 634 | void *p = oldinfo->entries[cpu]; | ||
| 635 | rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]); | ||
| 636 | newinfo->entries[cpu] = p; | ||
| 637 | } | ||
| 638 | |||
| 639 | } | ||
| 640 | EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu); | ||
| 641 | |||
| 642 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ | 628 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ |
| 643 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, | 629 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, |
| 644 | const char *name) | 630 | const char *name) |
| @@ -676,32 +662,43 @@ void xt_compat_unlock(u_int8_t af) | |||
| 676 | EXPORT_SYMBOL_GPL(xt_compat_unlock); | 662 | EXPORT_SYMBOL_GPL(xt_compat_unlock); |
| 677 | #endif | 663 | #endif |
| 678 | 664 | ||
| 665 | DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); | ||
| 666 | EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); | ||
| 667 | |||
| 668 | |||
| 679 | struct xt_table_info * | 669 | struct xt_table_info * |
| 680 | xt_replace_table(struct xt_table *table, | 670 | xt_replace_table(struct xt_table *table, |
| 681 | unsigned int num_counters, | 671 | unsigned int num_counters, |
| 682 | struct xt_table_info *newinfo, | 672 | struct xt_table_info *newinfo, |
| 683 | int *error) | 673 | int *error) |
| 684 | { | 674 | { |
| 685 | struct xt_table_info *oldinfo, *private; | 675 | struct xt_table_info *private; |
| 686 | 676 | ||
| 687 | /* Do the substitution. */ | 677 | /* Do the substitution. */ |
| 688 | mutex_lock(&table->lock); | 678 | local_bh_disable(); |
| 689 | private = table->private; | 679 | private = table->private; |
| 680 | |||
| 690 | /* Check inside lock: is the old number correct? */ | 681 | /* Check inside lock: is the old number correct? */ |
| 691 | if (num_counters != private->number) { | 682 | if (num_counters != private->number) { |
| 692 | duprintf("num_counters != table->private->number (%u/%u)\n", | 683 | duprintf("num_counters != table->private->number (%u/%u)\n", |
| 693 | num_counters, private->number); | 684 | num_counters, private->number); |
| 694 | mutex_unlock(&table->lock); | 685 | local_bh_enable(); |
| 695 | *error = -EAGAIN; | 686 | *error = -EAGAIN; |
| 696 | return NULL; | 687 | return NULL; |
| 697 | } | 688 | } |
| 698 | oldinfo = private; | ||
| 699 | rcu_assign_pointer(table->private, newinfo); | ||
| 700 | newinfo->initial_entries = oldinfo->initial_entries; | ||
| 701 | mutex_unlock(&table->lock); | ||
| 702 | 689 | ||
| 703 | synchronize_net(); | 690 | table->private = newinfo; |
| 704 | return oldinfo; | 691 | newinfo->initial_entries = private->initial_entries; |
| 692 | |||
| 693 | /* | ||
| 694 | * Even though table entries have now been swapped, other CPU's | ||
| 695 | * may still be using the old entries. This is okay, because | ||
| 696 | * resynchronization happens because of the locking done | ||
| 697 | * during the get_counters() routine. | ||
| 698 | */ | ||
| 699 | local_bh_enable(); | ||
| 700 | |||
| 701 | return private; | ||
| 705 | } | 702 | } |
| 706 | EXPORT_SYMBOL_GPL(xt_replace_table); | 703 | EXPORT_SYMBOL_GPL(xt_replace_table); |
| 707 | 704 | ||
| @@ -734,7 +731,6 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table, | |||
| 734 | 731 | ||
| 735 | /* Simplifies replace_table code. */ | 732 | /* Simplifies replace_table code. */ |
| 736 | table->private = bootstrap; | 733 | table->private = bootstrap; |
| 737 | mutex_init(&table->lock); | ||
| 738 | 734 | ||
| 739 | if (!xt_replace_table(table, 0, newinfo, &ret)) | 735 | if (!xt_replace_table(table, 0, newinfo, &ret)) |
| 740 | goto unlock; | 736 | goto unlock; |
| @@ -1147,7 +1143,14 @@ static struct pernet_operations xt_net_ops = { | |||
| 1147 | 1143 | ||
| 1148 | static int __init xt_init(void) | 1144 | static int __init xt_init(void) |
| 1149 | { | 1145 | { |
| 1150 | int i, rv; | 1146 | unsigned int i; |
| 1147 | int rv; | ||
| 1148 | |||
| 1149 | for_each_possible_cpu(i) { | ||
| 1150 | struct xt_info_lock *lock = &per_cpu(xt_info_locks, i); | ||
| 1151 | spin_lock_init(&lock->lock); | ||
| 1152 | lock->readers = 0; | ||
| 1153 | } | ||
| 1151 | 1154 | ||
| 1152 | xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); | 1155 | xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); |
| 1153 | if (!xt) | 1156 | if (!xt) |
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 791e030ea903..eb0ceb846527 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c | |||
| @@ -474,7 +474,7 @@ static ssize_t recent_old_proc_write(struct file *file, | |||
| 474 | struct recent_table *t = pde->data; | 474 | struct recent_table *t = pde->data; |
| 475 | struct recent_entry *e; | 475 | struct recent_entry *e; |
| 476 | char buf[sizeof("+255.255.255.255")], *c = buf; | 476 | char buf[sizeof("+255.255.255.255")], *c = buf; |
| 477 | __be32 addr; | 477 | union nf_inet_addr addr = {}; |
| 478 | int add; | 478 | int add; |
| 479 | 479 | ||
| 480 | if (size > sizeof(buf)) | 480 | if (size > sizeof(buf)) |
| @@ -506,14 +506,13 @@ static ssize_t recent_old_proc_write(struct file *file, | |||
| 506 | add = 1; | 506 | add = 1; |
| 507 | break; | 507 | break; |
| 508 | } | 508 | } |
| 509 | addr = in_aton(c); | 509 | addr.ip = in_aton(c); |
| 510 | 510 | ||
| 511 | spin_lock_bh(&recent_lock); | 511 | spin_lock_bh(&recent_lock); |
| 512 | e = recent_entry_lookup(t, (const void *)&addr, NFPROTO_IPV4, 0); | 512 | e = recent_entry_lookup(t, &addr, NFPROTO_IPV4, 0); |
| 513 | if (e == NULL) { | 513 | if (e == NULL) { |
| 514 | if (add) | 514 | if (add) |
| 515 | recent_entry_init(t, (const void *)&addr, | 515 | recent_entry_init(t, &addr, NFPROTO_IPV4, 0); |
| 516 | NFPROTO_IPV4, 0); | ||
| 517 | } else { | 516 | } else { |
| 518 | if (add) | 517 | if (add) |
| 519 | recent_entry_update(t, e); | 518 | recent_entry_update(t, e); |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 82271720d970..5f1f86565f16 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -794,7 +794,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 794 | { | 794 | { |
| 795 | static xfrm_address_t saddr_wildcard = { }; | 795 | static xfrm_address_t saddr_wildcard = { }; |
| 796 | struct net *net = xp_net(pol); | 796 | struct net *net = xp_net(pol); |
| 797 | unsigned int h; | 797 | unsigned int h, h_wildcard; |
| 798 | struct hlist_node *entry; | 798 | struct hlist_node *entry; |
| 799 | struct xfrm_state *x, *x0, *to_put; | 799 | struct xfrm_state *x, *x0, *to_put; |
| 800 | int acquire_in_progress = 0; | 800 | int acquire_in_progress = 0; |
| @@ -819,8 +819,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 819 | if (best) | 819 | if (best) |
| 820 | goto found; | 820 | goto found; |
| 821 | 821 | ||
| 822 | h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); | 822 | h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); |
| 823 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 823 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { |
| 824 | if (x->props.family == family && | 824 | if (x->props.family == family && |
| 825 | x->props.reqid == tmpl->reqid && | 825 | x->props.reqid == tmpl->reqid && |
| 826 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 826 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
