diff options
-rw-r--r-- | net/packet/af_packet.c | 66 | ||||
-rw-r--r-- | net/packet/diag.c | 1 | ||||
-rw-r--r-- | net/packet/internal.h | 2 |
3 files changed, 62 insertions, 7 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d5495d87f399..12f2f725a945 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -89,6 +89,7 @@ | |||
89 | #include <linux/errqueue.h> | 89 | #include <linux/errqueue.h> |
90 | #include <linux/net_tstamp.h> | 90 | #include <linux/net_tstamp.h> |
91 | #include <linux/reciprocal_div.h> | 91 | #include <linux/reciprocal_div.h> |
92 | #include <linux/percpu.h> | ||
92 | #ifdef CONFIG_INET | 93 | #ifdef CONFIG_INET |
93 | #include <net/inet_common.h> | 94 | #include <net/inet_common.h> |
94 | #endif | 95 | #endif |
@@ -1168,6 +1169,47 @@ static void packet_increment_head(struct packet_ring_buffer *buff) | |||
1168 | buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; | 1169 | buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; |
1169 | } | 1170 | } |
1170 | 1171 | ||
1172 | static void packet_inc_pending(struct packet_ring_buffer *rb) | ||
1173 | { | ||
1174 | this_cpu_inc(*rb->pending_refcnt); | ||
1175 | } | ||
1176 | |||
1177 | static void packet_dec_pending(struct packet_ring_buffer *rb) | ||
1178 | { | ||
1179 | this_cpu_dec(*rb->pending_refcnt); | ||
1180 | } | ||
1181 | |||
1182 | static unsigned int packet_read_pending(const struct packet_ring_buffer *rb) | ||
1183 | { | ||
1184 | unsigned int refcnt = 0; | ||
1185 | int cpu; | ||
1186 | |||
1187 | /* We don't use pending refcount in rx_ring. */ | ||
1188 | if (rb->pending_refcnt == NULL) | ||
1189 | return 0; | ||
1190 | |||
1191 | for_each_possible_cpu(cpu) | ||
1192 | refcnt += *per_cpu_ptr(rb->pending_refcnt, cpu); | ||
1193 | |||
1194 | return refcnt; | ||
1195 | } | ||
1196 | |||
1197 | static int packet_alloc_pending(struct packet_sock *po) | ||
1198 | { | ||
1199 | po->rx_ring.pending_refcnt = NULL; | ||
1200 | |||
1201 | po->tx_ring.pending_refcnt = alloc_percpu(unsigned int); | ||
1202 | if (unlikely(po->tx_ring.pending_refcnt == NULL)) | ||
1203 | return -ENOBUFS; | ||
1204 | |||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static void packet_free_pending(struct packet_sock *po) | ||
1209 | { | ||
1210 | free_percpu(po->tx_ring.pending_refcnt); | ||
1211 | } | ||
1212 | |||
1171 | static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb) | 1213 | static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb) |
1172 | { | 1214 | { |
1173 | struct sock *sk = &po->sk; | 1215 | struct sock *sk = &po->sk; |
@@ -2014,8 +2056,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb) | |||
2014 | __u32 ts; | 2056 | __u32 ts; |
2015 | 2057 | ||
2016 | ph = skb_shinfo(skb)->destructor_arg; | 2058 | ph = skb_shinfo(skb)->destructor_arg; |
2017 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); | 2059 | packet_dec_pending(&po->tx_ring); |
2018 | atomic_dec(&po->tx_ring.pending); | ||
2019 | 2060 | ||
2020 | ts = __packet_set_timestamp(po, ph, skb); | 2061 | ts = __packet_set_timestamp(po, ph, skb); |
2021 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); | 2062 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); |
@@ -2236,7 +2277,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2236 | skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); | 2277 | skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); |
2237 | skb->destructor = tpacket_destruct_skb; | 2278 | skb->destructor = tpacket_destruct_skb; |
2238 | __packet_set_status(po, ph, TP_STATUS_SENDING); | 2279 | __packet_set_status(po, ph, TP_STATUS_SENDING); |
2239 | atomic_inc(&po->tx_ring.pending); | 2280 | packet_inc_pending(&po->tx_ring); |
2240 | 2281 | ||
2241 | status = TP_STATUS_SEND_REQUEST; | 2282 | status = TP_STATUS_SEND_REQUEST; |
2242 | err = po->xmit(skb); | 2283 | err = po->xmit(skb); |
@@ -2256,8 +2297,14 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2256 | } | 2297 | } |
2257 | packet_increment_head(&po->tx_ring); | 2298 | packet_increment_head(&po->tx_ring); |
2258 | len_sum += tp_len; | 2299 | len_sum += tp_len; |
2259 | } while (likely((ph != NULL) || (need_wait && | 2300 | } while (likely((ph != NULL) || |
2260 | atomic_read(&po->tx_ring.pending)))); | 2301 | /* Note: packet_read_pending() might be slow if we have |
2302 | * to call it as it's per_cpu variable, but in fast-path | ||
2303 | * we already short-circuit the loop with the first | ||
2304 | * condition, and luckily don't have to go that path | ||
2305 | * anyway. | ||
2306 | */ | ||
2307 | (need_wait && packet_read_pending(&po->tx_ring)))); | ||
2261 | 2308 | ||
2262 | err = len_sum; | 2309 | err = len_sum; |
2263 | goto out_put; | 2310 | goto out_put; |
@@ -2556,6 +2603,7 @@ static int packet_release(struct socket *sock) | |||
2556 | /* Purge queues */ | 2603 | /* Purge queues */ |
2557 | 2604 | ||
2558 | skb_queue_purge(&sk->sk_receive_queue); | 2605 | skb_queue_purge(&sk->sk_receive_queue); |
2606 | packet_free_pending(po); | ||
2559 | sk_refcnt_debug_release(sk); | 2607 | sk_refcnt_debug_release(sk); |
2560 | 2608 | ||
2561 | sock_put(sk); | 2609 | sock_put(sk); |
@@ -2717,6 +2765,10 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
2717 | po->num = proto; | 2765 | po->num = proto; |
2718 | po->xmit = dev_queue_xmit; | 2766 | po->xmit = dev_queue_xmit; |
2719 | 2767 | ||
2768 | err = packet_alloc_pending(po); | ||
2769 | if (err) | ||
2770 | goto out2; | ||
2771 | |||
2720 | packet_cached_dev_reset(po); | 2772 | packet_cached_dev_reset(po); |
2721 | 2773 | ||
2722 | sk->sk_destruct = packet_sock_destruct; | 2774 | sk->sk_destruct = packet_sock_destruct; |
@@ -2749,6 +2801,8 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
2749 | preempt_enable(); | 2801 | preempt_enable(); |
2750 | 2802 | ||
2751 | return 0; | 2803 | return 0; |
2804 | out2: | ||
2805 | sk_free(sk); | ||
2752 | out: | 2806 | out: |
2753 | return err; | 2807 | return err; |
2754 | } | 2808 | } |
@@ -3676,7 +3730,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
3676 | if (!closing) { | 3730 | if (!closing) { |
3677 | if (atomic_read(&po->mapped)) | 3731 | if (atomic_read(&po->mapped)) |
3678 | goto out; | 3732 | goto out; |
3679 | if (atomic_read(&rb->pending)) | 3733 | if (packet_read_pending(rb)) |
3680 | goto out; | 3734 | goto out; |
3681 | } | 3735 | } |
3682 | 3736 | ||
diff --git a/net/packet/diag.c b/net/packet/diag.c index a9584a2f6d69..533ce4ff108a 100644 --- a/net/packet/diag.c +++ b/net/packet/diag.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/net.h> | 3 | #include <linux/net.h> |
4 | #include <linux/netdevice.h> | 4 | #include <linux/netdevice.h> |
5 | #include <linux/packet_diag.h> | 5 | #include <linux/packet_diag.h> |
6 | #include <linux/percpu.h> | ||
6 | #include <net/net_namespace.h> | 7 | #include <net/net_namespace.h> |
7 | #include <net/sock.h> | 8 | #include <net/sock.h> |
8 | 9 | ||
diff --git a/net/packet/internal.h b/net/packet/internal.h index 0a87d7b36c9e..eb9580a6b25f 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h | |||
@@ -64,7 +64,7 @@ struct packet_ring_buffer { | |||
64 | unsigned int pg_vec_pages; | 64 | unsigned int pg_vec_pages; |
65 | unsigned int pg_vec_len; | 65 | unsigned int pg_vec_len; |
66 | 66 | ||
67 | atomic_t pending; | 67 | unsigned int __percpu *pending_refcnt; |
68 | 68 | ||
69 | struct tpacket_kbdq_core prb_bdqc; | 69 | struct tpacket_kbdq_core prb_bdqc; |
70 | }; | 70 | }; |