aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-12-05 04:53:40 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:56:34 -0500
commita59322be07c964e916d15be3df473fb7ba20c41e (patch)
tree16d4caa41c1fd6c3fb907ce792202b157e6c9a1e
parent1781f7f5804e52ee2d35328b129602146a8d8254 (diff)
[UDP]: Only increment counter on first peek/recv
The previous move of the the UDP inDatagrams counter caused each peek of the same packet to be counted separately. This may be undesirable. This patch fixes this by adding a bit to sk_buff to record whether this packet has already been seen through skb_recv_datagram. We then only increment the counter when the packet is seen for the first time. The only dodgy part is the fact that skb_recv_datagram doesn't have a good way of returning this new bit of information. So I've added a new function __skb_recv_datagram that does return this and made skb_recv_datagram a wrapper around it. The plan is to eventually replace all uses of skb_recv_datagram with this new function at which time it can be renamed its proper name. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h3
-rw-r--r--net/core/datagram.c43
-rw-r--r--net/ipv4/udp.c7
-rw-r--r--net/ipv6/udp.c7
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
1542extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
1543 int *peeked, int *err);
1541extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, 1544extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
1542 int noblock, int *err); 1545 int noblock, int *err);
1543extern unsigned int datagram_poll(struct file *file, struct socket *sock, 1546extern 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 */
146struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, 146struct 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}
198EXPORT_SYMBOL(__skb_recv_datagram);
199
200struct 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
198void skb_free_datagram(struct sock *sk, struct sk_buff *skb) 209void 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
842try_again: 843try_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
135try_again: 136try_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