9p: VFS switches for 9p2000.L: protocol and client changes
[safe/jmp/linux-2.6] / net / core / datagram.c
index 4ade301..e009753 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/poll.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
 
 #include <net/protocol.h>
 #include <linux/skbuff.h>
@@ -85,7 +86,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
        int error;
        DEFINE_WAIT_FUNC(wait, receiver_wake_function);
 
-       prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        /* Socket errors? */
        error = sock_error(sk);
@@ -114,7 +115,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
        error = 0;
        *timeo_p = schedule_timeout(*timeo_p);
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return error;
 interrupted:
        error = sock_intr_errno(*timeo_p);
@@ -228,9 +229,18 @@ EXPORT_SYMBOL(skb_free_datagram);
 
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
 {
-       lock_sock(sk);
-       skb_free_datagram(sk, skb);
-       release_sock(sk);
+       if (likely(atomic_read(&skb->users) == 1))
+               smp_rmb();
+       else if (likely(!atomic_dec_and_test(&skb->users)))
+               return;
+
+       lock_sock_bh(sk);
+       skb_orphan(skb);
+       sk_mem_reclaim_partial(sk);
+       unlock_sock_bh(sk);
+
+       /* skb is now orphaned, can be freed outside of locked section */
+       __kfree_skb(skb);
 }
 EXPORT_SYMBOL(skb_free_datagram_locked);
 
@@ -271,6 +281,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
        }
 
        kfree_skb(skb);
+       atomic_inc(&sk->sk_drops);
        sk_mem_reclaim_partial(sk);
 
        return err;
@@ -724,7 +735,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* exceptional events? */