From 90955d8c40bcd0eadf78c0d5834ae3e511c784bb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Dec 2005 23:16:37 -0800 Subject: [PATCH] --- yaml --- r: 15532 b: refs/heads/master c: 3305b80c214c642b89cd5c21af83bc91ec13f8bd h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/linux/skbuff.h | 2 ++ trunk/net/core/datagram.c | 36 ++++++++++++++++++++++++++++++++++++ trunk/net/ipv4/udp.c | 15 +-------------- trunk/net/ipv6/raw.c | 16 +++------------- trunk/net/ipv6/udp.c | 16 ++-------------- 6 files changed, 45 insertions(+), 42 deletions(-) diff --git a/[refs] b/[refs] index 40682b6a9901..c5783deb61e5 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 57cca05af1e20fdc65b55be52c042c234f86c866 +refs/heads/master: 3305b80c214c642b89cd5c21af83bc91ec13f8bd diff --git a/trunk/include/linux/skbuff.h b/trunk/include/linux/skbuff.h index 8c5d6001a923..97f6580ce039 100644 --- a/trunk/include/linux/skbuff.h +++ b/trunk/include/linux/skbuff.h @@ -1239,6 +1239,8 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen, struct iovec *iov); extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); +extern void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, + unsigned int flags); extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum); extern int skb_copy_bits(const struct sk_buff *skb, int offset, diff --git a/trunk/net/core/datagram.c b/trunk/net/core/datagram.c index 1bcfef51ac58..f8d322e1ea92 100644 --- a/trunk/net/core/datagram.c +++ b/trunk/net/core/datagram.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -199,6 +200,41 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) kfree_skb(skb); } +/** + * skb_kill_datagram - Free a datagram skbuff forcibly + * @sk: socket + * @skb: datagram skbuff + * @flags: MSG_ flags + * + * This function frees a datagram skbuff that was received by + * skb_recv_datagram. The flags argument must match the one + * used for skb_recv_datagram. + * + * If the MSG_PEEK flag is set, and the packet is still on the + * receive queue of the socket, it will be taken off the queue + * before it is freed. + * + * This function currently only disables BH when acquiring the + * sk_receive_queue lock. Therefore it must not be used in a + * context where that lock is acquired in an IRQ context. + */ + +void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) +{ + if (flags & MSG_PEEK) { + spin_lock_bh(&sk->sk_receive_queue.lock); + if (skb == skb_peek(&sk->sk_receive_queue)) { + __skb_unlink(skb, &sk->sk_receive_queue); + atomic_dec(&skb->users); + } + spin_unlock_bh(&sk->sk_receive_queue.lock); + } + + kfree_skb(skb); +} + +EXPORT_SYMBOL(skb_kill_datagram); + /** * skb_copy_datagram_iovec - Copy a datagram to an iovec. * @skb: buffer to copy diff --git a/trunk/net/ipv4/udp.c b/trunk/net/ipv4/udp.c index 2422a5f7195d..012c4621e40a 100644 --- a/trunk/net/ipv4/udp.c +++ b/trunk/net/ipv4/udp.c @@ -846,20 +846,7 @@ static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, csum_copy_err: UDP_INC_STATS_BH(UDP_MIB_INERRORS); - /* Clear queue. */ - if (flags&MSG_PEEK) { - int clear = 0; - spin_lock_bh(&sk->sk_receive_queue.lock); - if (skb == skb_peek(&sk->sk_receive_queue)) { - __skb_unlink(skb, &sk->sk_receive_queue); - clear = 1; - } - spin_unlock_bh(&sk->sk_receive_queue.lock); - if (clear) - kfree_skb(skb); - } - - skb_free_datagram(sk, skb); + skb_kill_datagram(sk, skb, flags); if (noblock) return -EAGAIN; diff --git a/trunk/net/ipv6/raw.c b/trunk/net/ipv6/raw.c index a66900cda2af..66f1d12ea578 100644 --- a/trunk/net/ipv6/raw.c +++ b/trunk/net/ipv6/raw.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -433,25 +434,14 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, return err; csum_copy_err: - /* Clear queue. */ - if (flags&MSG_PEEK) { - int clear = 0; - spin_lock_bh(&sk->sk_receive_queue.lock); - if (skb == skb_peek(&sk->sk_receive_queue)) { - __skb_unlink(skb, &sk->sk_receive_queue); - clear = 1; - } - spin_unlock_bh(&sk->sk_receive_queue.lock); - if (clear) - kfree_skb(skb); - } + skb_kill_datagram(sk, skb, flags); /* Error for blocking case is chosen to masquerade as some normal condition. */ err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; /* FIXME: increment a raw6 drops counter here */ - goto out_free; + goto out; } static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, diff --git a/trunk/net/ipv6/udp.c b/trunk/net/ipv6/udp.c index 5cc8731eb55b..d8538dcea813 100644 --- a/trunk/net/ipv6/udp.c +++ b/trunk/net/ipv6/udp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -300,20 +301,7 @@ static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, return err; csum_copy_err: - /* Clear queue. */ - if (flags&MSG_PEEK) { - int clear = 0; - spin_lock_bh(&sk->sk_receive_queue.lock); - if (skb == skb_peek(&sk->sk_receive_queue)) { - __skb_unlink(skb, &sk->sk_receive_queue); - clear = 1; - } - spin_unlock_bh(&sk->sk_receive_queue.lock); - if (clear) - kfree_skb(skb); - } - - skb_free_datagram(sk, skb); + skb_kill_datagram(sk, skb, flags); if (flags & MSG_DONTWAIT) { UDP6_INC_STATS_USER(UDP_MIB_INERRORS);