|
@@ -161,6 +161,43 @@ done:
|
|
|
return skb;
|
|
|
}
|
|
|
|
|
|
+struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,
|
|
|
+ struct sk_buff_head *queue,
|
|
|
+ unsigned int flags,
|
|
|
+ void (*destructor)(struct sock *sk,
|
|
|
+ struct sk_buff *skb),
|
|
|
+ int *peeked, int *off, int *err,
|
|
|
+ struct sk_buff **last)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ *last = queue->prev;
|
|
|
+ skb_queue_walk(queue, skb) {
|
|
|
+ if (flags & MSG_PEEK) {
|
|
|
+ if (*off >= skb->len && (skb->len || *off ||
|
|
|
+ skb->peeked)) {
|
|
|
+ *off -= skb->len;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!skb->len) {
|
|
|
+ skb = skb_set_peeked(skb);
|
|
|
+ if (unlikely(IS_ERR(skb))) {
|
|
|
+ *err = PTR_ERR(skb);
|
|
|
+ return skb;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *peeked = 1;
|
|
|
+ atomic_inc(&skb->users);
|
|
|
+ } else {
|
|
|
+ __skb_unlink(skb, queue);
|
|
|
+ if (destructor)
|
|
|
+ destructor(sk, skb);
|
|
|
+ }
|
|
|
+ return skb;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* __skb_try_recv_datagram - Receive a datagram skbuff
|
|
|
* @sk: socket
|
|
@@ -216,46 +253,20 @@ struct sk_buff *__skb_try_recv_datagram(struct sock *sk, unsigned int flags,
|
|
|
|
|
|
*peeked = 0;
|
|
|
do {
|
|
|
+ int _off = *off;
|
|
|
+
|
|
|
/* Again only user level code calls this function, so nothing
|
|
|
* interrupt level will suddenly eat the receive_queue.
|
|
|
*
|
|
|
* Look at current nfs client by the way...
|
|
|
* However, this function was correct in any case. 8)
|
|
|
*/
|
|
|
- int _off = *off;
|
|
|
-
|
|
|
- *last = (struct sk_buff *)queue;
|
|
|
spin_lock_irqsave(&queue->lock, cpu_flags);
|
|
|
- skb_queue_walk(queue, skb) {
|
|
|
- *last = skb;
|
|
|
- if (flags & MSG_PEEK) {
|
|
|
- if (_off >= skb->len && (skb->len || _off ||
|
|
|
- skb->peeked)) {
|
|
|
- _off -= skb->len;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!skb->len) {
|
|
|
- skb = skb_set_peeked(skb);
|
|
|
- if (IS_ERR(skb)) {
|
|
|
- error = PTR_ERR(skb);
|
|
|
- spin_unlock_irqrestore(&queue->lock,
|
|
|
- cpu_flags);
|
|
|
- goto no_packet;
|
|
|
- }
|
|
|
- }
|
|
|
- *peeked = 1;
|
|
|
- atomic_inc(&skb->users);
|
|
|
- } else {
|
|
|
- __skb_unlink(skb, queue);
|
|
|
- if (destructor)
|
|
|
- destructor(sk, skb);
|
|
|
- }
|
|
|
- spin_unlock_irqrestore(&queue->lock, cpu_flags);
|
|
|
- *off = _off;
|
|
|
- return skb;
|
|
|
- }
|
|
|
-
|
|
|
+ skb = __skb_try_recv_from_queue(sk, queue, flags, destructor,
|
|
|
+ peeked, &_off, err, last);
|
|
|
spin_unlock_irqrestore(&queue->lock, cpu_flags);
|
|
|
+ if (skb)
|
|
|
+ return skb;
|
|
|
|
|
|
if (!sk_can_busy_loop(sk))
|
|
|
break;
|
|
@@ -335,8 +346,8 @@ void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len)
|
|
|
}
|
|
|
EXPORT_SYMBOL(__skb_free_datagram_locked);
|
|
|
|
|
|
-int __sk_queue_drop_skb(struct sock *sk, struct sk_buff *skb,
|
|
|
- unsigned int flags,
|
|
|
+int __sk_queue_drop_skb(struct sock *sk, struct sk_buff_head *sk_queue,
|
|
|
+ struct sk_buff *skb, unsigned int flags,
|
|
|
void (*destructor)(struct sock *sk,
|
|
|
struct sk_buff *skb))
|
|
|
{
|
|
@@ -344,15 +355,15 @@ int __sk_queue_drop_skb(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
|
if (flags & MSG_PEEK) {
|
|
|
err = -ENOENT;
|
|
|
- spin_lock_bh(&sk->sk_receive_queue.lock);
|
|
|
- if (skb == skb_peek(&sk->sk_receive_queue)) {
|
|
|
- __skb_unlink(skb, &sk->sk_receive_queue);
|
|
|
+ spin_lock_bh(&sk_queue->lock);
|
|
|
+ if (skb == skb_peek(sk_queue)) {
|
|
|
+ __skb_unlink(skb, sk_queue);
|
|
|
atomic_dec(&skb->users);
|
|
|
if (destructor)
|
|
|
destructor(sk, skb);
|
|
|
err = 0;
|
|
|
}
|
|
|
- spin_unlock_bh(&sk->sk_receive_queue.lock);
|
|
|
+ spin_unlock_bh(&sk_queue->lock);
|
|
|
}
|
|
|
|
|
|
atomic_inc(&sk->sk_drops);
|
|
@@ -383,7 +394,8 @@ EXPORT_SYMBOL(__sk_queue_drop_skb);
|
|
|
|
|
|
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
|
|
|
{
|
|
|
- int err = __sk_queue_drop_skb(sk, skb, flags, NULL);
|
|
|
+ int err = __sk_queue_drop_skb(sk, &sk->sk_receive_queue, skb, flags,
|
|
|
+ NULL);
|
|
|
|
|
|
kfree_skb(skb);
|
|
|
sk_mem_reclaim_partial(sk);
|