Skip to content

Commit a59322b

Browse files
herbertxdavem330
authored andcommitted
[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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1781f7f commit a59322b

File tree

4 files changed

+40
-20
lines changed

4 files changed

+40
-20
lines changed

include/linux/skbuff.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ struct sk_buff {
288288
__u8 pkt_type:3,
289289
fclone:2,
290290
ipvs_property:1,
291+
peeked:1,
291292
nf_trace:1;
292293
__be16 protocol;
293294

@@ -1538,6 +1539,8 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
15381539
skb = skb->prev)
15391540

15401541

1542+
extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
1543+
int *peeked, int *err);
15411544
extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
15421545
int noblock, int *err);
15431546
extern unsigned int datagram_poll(struct file *file, struct socket *sock,

net/core/datagram.c

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
115115
}
116116

117117
/**
118-
* skb_recv_datagram - Receive a datagram skbuff
118+
* __skb_recv_datagram - Receive a datagram skbuff
119119
* @sk: socket
120120
* @flags: MSG_ flags
121-
* @noblock: blocking operation?
121+
* @peeked: returns non-zero if this packet has been seen before
122122
* @err: error code returned
123123
*
124124
* Get a datagram skbuff, understands the peeking, nonblocking wakeups
@@ -143,8 +143,8 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
143143
* quite explicitly by POSIX 1003.1g, don't change them without having
144144
* the standard around please.
145145
*/
146-
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
147-
int noblock, int *err)
146+
struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
147+
int *peeked, int *err)
148148
{
149149
struct sk_buff *skb;
150150
long timeo;
@@ -156,7 +156,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
156156
if (error)
157157
goto no_packet;
158158

159-
timeo = sock_rcvtimeo(sk, noblock);
159+
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
160160

161161
do {
162162
/* 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,
165165
* Look at current nfs client by the way...
166166
* However, this function was corrent in any case. 8)
167167
*/
168-
if (flags & MSG_PEEK) {
169-
unsigned long cpu_flags;
170-
171-
spin_lock_irqsave(&sk->sk_receive_queue.lock,
172-
cpu_flags);
173-
skb = skb_peek(&sk->sk_receive_queue);
174-
if (skb)
168+
unsigned long cpu_flags;
169+
170+
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
171+
skb = skb_peek(&sk->sk_receive_queue);
172+
if (skb) {
173+
*peeked = skb->peeked;
174+
if (flags & MSG_PEEK) {
175+
skb->peeked = 1;
175176
atomic_inc(&skb->users);
176-
spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
177-
cpu_flags);
178-
} else
179-
skb = skb_dequeue(&sk->sk_receive_queue);
177+
} else
178+
__skb_unlink(skb, &sk->sk_receive_queue);
179+
}
180+
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
180181

181182
if (skb)
182183
return skb;
@@ -194,6 +195,16 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
194195
*err = error;
195196
return NULL;
196197
}
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+
}
197208

198209
void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
199210
{

net/ipv4/udp.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
827827
struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
828828
struct sk_buff *skb;
829829
unsigned int ulen, copied;
830+
int peeked;
830831
int err;
831832
int is_udplite = IS_UDPLITE(sk);
832833

@@ -840,7 +841,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
840841
return ip_recv_error(sk, msg, len);
841842

842843
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);
844846
if (!skb)
845847
goto out;
846848

@@ -875,7 +877,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
875877
if (err)
876878
goto out_free;
877879

878-
UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
880+
if (!peeked)
881+
UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
879882

880883
sock_recv_timestamp(msg, sk, skb);
881884

net/ipv6/udp.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
123123
struct inet_sock *inet = inet_sk(sk);
124124
struct sk_buff *skb;
125125
unsigned int ulen, copied;
126+
int peeked;
126127
int err;
127128
int is_udplite = IS_UDPLITE(sk);
128129

@@ -133,7 +134,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
133134
return ipv6_recv_error(sk, msg, len);
134135

135136
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);
137139
if (!skb)
138140
goto out;
139141

@@ -166,7 +168,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
166168
if (err)
167169
goto out_free;
168170

169-
UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
171+
if (!peeked)
172+
UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
170173

171174
sock_recv_timestamp(msg, sk, skb);
172175

0 commit comments

Comments
 (0)