aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/dev.c23
-rw-r--r--net/ipv4/netfilter/ip_queue.c6
-rw-r--r--net/ipv6/netfilter/ip6_queue.c5
3 files changed, 31 insertions, 3 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 962e3de25a35..c7ef6c5d3782 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1441,15 +1441,38 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
1441EXPORT_SYMBOL(call_netdevice_notifiers); 1441EXPORT_SYMBOL(call_netdevice_notifiers);
1442 1442
1443static struct jump_label_key netstamp_needed __read_mostly; 1443static struct jump_label_key netstamp_needed __read_mostly;
1444#ifdef HAVE_JUMP_LABEL
1445/* We are not allowed to call jump_label_dec() from irq context
1446 * If net_disable_timestamp() is called from irq context, defer the
1447 * jump_label_dec() calls.
1448 */
1449static atomic_t netstamp_needed_deferred;
1450#endif
1444 1451
1445void net_enable_timestamp(void) 1452void net_enable_timestamp(void)
1446{ 1453{
1454#ifdef HAVE_JUMP_LABEL
1455 int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
1456
1457 if (deferred) {
1458 while (--deferred)
1459 jump_label_dec(&netstamp_needed);
1460 return;
1461 }
1462#endif
1463 WARN_ON(in_interrupt());
1447 jump_label_inc(&netstamp_needed); 1464 jump_label_inc(&netstamp_needed);
1448} 1465}
1449EXPORT_SYMBOL(net_enable_timestamp); 1466EXPORT_SYMBOL(net_enable_timestamp);
1450 1467
1451void net_disable_timestamp(void) 1468void net_disable_timestamp(void)
1452{ 1469{
1470#ifdef HAVE_JUMP_LABEL
1471 if (in_interrupt()) {
1472 atomic_inc(&netstamp_needed_deferred);
1473 return;
1474 }
1475#endif
1453 jump_label_dec(&netstamp_needed); 1476 jump_label_dec(&netstamp_needed);
1454} 1477}
1455EXPORT_SYMBOL(net_disable_timestamp); 1478EXPORT_SYMBOL(net_disable_timestamp);
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index e59aabd0eae4..a057fe64debd 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -404,6 +404,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
404 int status, type, pid, flags; 404 int status, type, pid, flags;
405 unsigned int nlmsglen, skblen; 405 unsigned int nlmsglen, skblen;
406 struct nlmsghdr *nlh; 406 struct nlmsghdr *nlh;
407 bool enable_timestamp = false;
407 408
408 skblen = skb->len; 409 skblen = skb->len;
409 if (skblen < sizeof(*nlh)) 410 if (skblen < sizeof(*nlh))
@@ -441,12 +442,13 @@ __ipq_rcv_skb(struct sk_buff *skb)
441 RCV_SKB_FAIL(-EBUSY); 442 RCV_SKB_FAIL(-EBUSY);
442 } 443 }
443 } else { 444 } else {
444 net_enable_timestamp(); 445 enable_timestamp = true;
445 peer_pid = pid; 446 peer_pid = pid;
446 } 447 }
447 448
448 spin_unlock_bh(&queue_lock); 449 spin_unlock_bh(&queue_lock);
449 450 if (enable_timestamp)
451 net_enable_timestamp();
450 status = ipq_receive_peer(NLMSG_DATA(nlh), type, 452 status = ipq_receive_peer(NLMSG_DATA(nlh), type,
451 nlmsglen - NLMSG_LENGTH(0)); 453 nlmsglen - NLMSG_LENGTH(0));
452 if (status < 0) 454 if (status < 0)
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index e63c3972a739..fb80a23c6640 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -405,6 +405,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
405 int status, type, pid, flags; 405 int status, type, pid, flags;
406 unsigned int nlmsglen, skblen; 406 unsigned int nlmsglen, skblen;
407 struct nlmsghdr *nlh; 407 struct nlmsghdr *nlh;
408 bool enable_timestamp = false;
408 409
409 skblen = skb->len; 410 skblen = skb->len;
410 if (skblen < sizeof(*nlh)) 411 if (skblen < sizeof(*nlh))
@@ -442,11 +443,13 @@ __ipq_rcv_skb(struct sk_buff *skb)
442 RCV_SKB_FAIL(-EBUSY); 443 RCV_SKB_FAIL(-EBUSY);
443 } 444 }
444 } else { 445 } else {
445 net_enable_timestamp(); 446 enable_timestamp = true;
446 peer_pid = pid; 447 peer_pid = pid;
447 } 448 }
448 449
449 spin_unlock_bh(&queue_lock); 450 spin_unlock_bh(&queue_lock);
451 if (enable_timestamp)
452 net_enable_timestamp();
450 453
451 status = ipq_receive_peer(NLMSG_DATA(nlh), type, 454 status = ipq_receive_peer(NLMSG_DATA(nlh), type,
452 nlmsglen - NLMSG_LENGTH(0)); 455 nlmsglen - NLMSG_LENGTH(0));