diff options
-rw-r--r-- | include/linux/skbuff.h | 3 | ||||
-rw-r--r-- | net/core/datagram.c | 43 | ||||
-rw-r--r-- | net/ipv4/udp.c | 7 | ||||
-rw-r--r-- | net/ipv6/udp.c | 7 |
4 files changed, 40 insertions, 20 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 17b3f70fbbc3..c618fbf7d173 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -288,6 +288,7 @@ struct sk_buff { | |||
288 | __u8 pkt_type:3, | 288 | __u8 pkt_type:3, |
289 | fclone:2, | 289 | fclone:2, |
290 | ipvs_property:1, | 290 | ipvs_property:1, |
291 | peeked:1, | ||
291 | nf_trace:1; | 292 | nf_trace:1; |
292 | __be16 protocol; | 293 | __be16 protocol; |
293 | 294 | ||
@@ -1538,6 +1539,8 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) | |||
1538 | skb = skb->prev) | 1539 | skb = skb->prev) |
1539 | 1540 | ||
1540 | 1541 | ||
1542 | extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, | ||
1543 | int *peeked, int *err); | ||
1541 | extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | 1544 | extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, |
1542 | int noblock, int *err); | 1545 | int noblock, int *err); |
1543 | extern unsigned int datagram_poll(struct file *file, struct socket *sock, | 1546 | extern unsigned int datagram_poll(struct file *file, struct socket *sock, |
diff --git a/net/core/datagram.c b/net/core/datagram.c index fbd6c76436d0..2d733131d7ce 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -115,10 +115,10 @@ out_noerr: | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /** | 117 | /** |
118 | * skb_recv_datagram - Receive a datagram skbuff | 118 | * __skb_recv_datagram - Receive a datagram skbuff |
119 | * @sk: socket | 119 | * @sk: socket |
120 | * @flags: MSG_ flags | 120 | * @flags: MSG_ flags |
121 | * @noblock: blocking operation? | 121 | * @peeked: returns non-zero if this packet has been seen before |
122 | * @err: error code returned | 122 | * @err: error code returned |
123 | * | 123 | * |
124 | * Get a datagram skbuff, understands the peeking, nonblocking wakeups | 124 | * Get a datagram skbuff, understands the peeking, nonblocking wakeups |
@@ -143,8 +143,8 @@ out_noerr: | |||
143 | * quite explicitly by POSIX 1003.1g, don't change them without having | 143 | * quite explicitly by POSIX 1003.1g, don't change them without having |
144 | * the standard around please. | 144 | * the standard around please. |
145 | */ | 145 | */ |
146 | struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | 146 | struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, |
147 | int noblock, int *err) | 147 | int *peeked, int *err) |
148 | { | 148 | { |
149 | struct sk_buff *skb; | 149 | struct sk_buff *skb; |
150 | long timeo; | 150 | long timeo; |
@@ -156,7 +156,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | |||
156 | if (error) | 156 | if (error) |
157 | goto no_packet; | 157 | goto no_packet; |
158 | 158 | ||
159 | timeo = sock_rcvtimeo(sk, noblock); | 159 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
160 | 160 | ||
161 | do { | 161 | do { |
162 | /* Again only user level code calls this function, so nothing | 162 | /* Again only user level code calls this function, so nothing |
@@ -165,18 +165,19 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | |||
165 | * Look at current nfs client by the way... | 165 | * Look at current nfs client by the way... |
166 | * However, this function was corrent in any case. 8) | 166 | * However, this function was corrent in any case. 8) |
167 | */ | 167 | */ |
168 | if (flags & MSG_PEEK) { | 168 | unsigned long cpu_flags; |
169 | unsigned long cpu_flags; | 169 | |
170 | 170 | spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); | |
171 | spin_lock_irqsave(&sk->sk_receive_queue.lock, | 171 | skb = skb_peek(&sk->sk_receive_queue); |
172 | cpu_flags); | 172 | if (skb) { |
173 | skb = skb_peek(&sk->sk_receive_queue); | 173 | *peeked = skb->peeked; |
174 | if (skb) | 174 | if (flags & MSG_PEEK) { |
175 | skb->peeked = 1; | ||
175 | atomic_inc(&skb->users); | 176 | atomic_inc(&skb->users); |
176 | spin_unlock_irqrestore(&sk->sk_receive_queue.lock, | 177 | } else |
177 | cpu_flags); | 178 | __skb_unlink(skb, &sk->sk_receive_queue); |
178 | } else | 179 | } |
179 | skb = skb_dequeue(&sk->sk_receive_queue); | 180 | spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); |
180 | 181 | ||
181 | if (skb) | 182 | if (skb) |
182 | return skb; | 183 | return skb; |
@@ -194,6 +195,16 @@ no_packet: | |||
194 | *err = error; | 195 | *err = error; |
195 | return NULL; | 196 | return NULL; |
196 | } | 197 | } |
198 | EXPORT_SYMBOL(__skb_recv_datagram); | ||
199 | |||
200 | struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | ||
201 | int noblock, int *err) | ||
202 | { | ||
203 | int peeked; | ||
204 | |||
205 | return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), | ||
206 | &peeked, err); | ||
207 | } | ||
197 | 208 | ||
198 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb) | 209 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb) |
199 | { | 210 | { |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 78cfcb4a1b3f..9ed6393c65d9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -827,6 +827,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
827 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 827 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
828 | struct sk_buff *skb; | 828 | struct sk_buff *skb; |
829 | unsigned int ulen, copied; | 829 | unsigned int ulen, copied; |
830 | int peeked; | ||
830 | int err; | 831 | int err; |
831 | int is_udplite = IS_UDPLITE(sk); | 832 | int is_udplite = IS_UDPLITE(sk); |
832 | 833 | ||
@@ -840,7 +841,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
840 | return ip_recv_error(sk, msg, len); | 841 | return ip_recv_error(sk, msg, len); |
841 | 842 | ||
842 | try_again: | 843 | try_again: |
843 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 844 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |
845 | &peeked, &err); | ||
844 | if (!skb) | 846 | if (!skb) |
845 | goto out; | 847 | goto out; |
846 | 848 | ||
@@ -875,7 +877,8 @@ try_again: | |||
875 | if (err) | 877 | if (err) |
876 | goto out_free; | 878 | goto out_free; |
877 | 879 | ||
878 | UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); | 880 | if (!peeked) |
881 | UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); | ||
879 | 882 | ||
880 | sock_recv_timestamp(msg, sk, skb); | 883 | sock_recv_timestamp(msg, sk, skb); |
881 | 884 | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 36bdcd2e1b52..fa640765385e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -123,6 +123,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
123 | struct inet_sock *inet = inet_sk(sk); | 123 | struct inet_sock *inet = inet_sk(sk); |
124 | struct sk_buff *skb; | 124 | struct sk_buff *skb; |
125 | unsigned int ulen, copied; | 125 | unsigned int ulen, copied; |
126 | int peeked; | ||
126 | int err; | 127 | int err; |
127 | int is_udplite = IS_UDPLITE(sk); | 128 | int is_udplite = IS_UDPLITE(sk); |
128 | 129 | ||
@@ -133,7 +134,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
133 | return ipv6_recv_error(sk, msg, len); | 134 | return ipv6_recv_error(sk, msg, len); |
134 | 135 | ||
135 | try_again: | 136 | try_again: |
136 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 137 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |
138 | &peeked, &err); | ||
137 | if (!skb) | 139 | if (!skb) |
138 | goto out; | 140 | goto out; |
139 | 141 | ||
@@ -166,7 +168,8 @@ try_again: | |||
166 | if (err) | 168 | if (err) |
167 | goto out_free; | 169 | goto out_free; |
168 | 170 | ||
169 | UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); | 171 | if (!peeked) |
172 | UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); | ||
170 | 173 | ||
171 | sock_recv_timestamp(msg, sk, skb); | 174 | sock_recv_timestamp(msg, sk, skb); |
172 | 175 | ||