net: add a noref bit on skb dst
[safe/jmp/linux-2.6] / include / net / sock.h
index d361c77..5697caf 100644 (file)
@@ -74,7 +74,7 @@
                                        printk(KERN_DEBUG msg); } while (0)
 #else
 /* Validate arguments and do nothing */
-static void inline int __attribute__ ((format (printf, 2, 3)))
+static inline void __attribute__ ((format (printf, 2, 3)))
 SOCK_DEBUG(struct sock *sk, const char *msg, ...)
 {
 }
@@ -159,7 +159,7 @@ struct sock_common {
   *    @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings
   *    @sk_lock:       synchronizer
   *    @sk_rcvbuf: size of receive buffer in bytes
-  *    @sk_sleep: sock wait queue
+  *    @sk_wq: sock wait queue and async head
   *    @sk_dst_cache: destination cache
   *    @sk_dst_lock: destination cache lock
   *    @sk_policy: flow policy
@@ -177,6 +177,7 @@ struct sock_common {
   *               %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
   *    @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *    @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
+  *    @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
   *    @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
   *    @sk_gso_max_size: Maximum GSO segment size to build
   *    @sk_lingertime: %SO_LINGER l_linger setting
@@ -257,7 +258,7 @@ struct sock {
                struct sk_buff *tail;
                int len;
        } sk_backlog;
-       wait_queue_head_t       *sk_sleep;
+       struct socket_wq        *sk_wq;
        struct dst_entry        *sk_dst_cache;
 #ifdef CONFIG_XFRM
        struct xfrm_policy      *sk_policy[2];
@@ -276,6 +277,7 @@ struct sock {
        int                     sk_forward_alloc;
        gfp_t                   sk_allocation;
        int                     sk_route_caps;
+       int                     sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
        int                     sk_rcvlowat;
@@ -598,12 +600,15 @@ static inline int sk_stream_memory_free(struct sock *sk)
 /* OOB backlog add */
 static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
-       if (!sk->sk_backlog.tail) {
-               sk->sk_backlog.head = sk->sk_backlog.tail = skb;
-       } else {
+       /* dont let skb dst not refcounted, we are going to leave rcu lock */
+       skb_dst_force(skb);
+
+       if (!sk->sk_backlog.tail)
+               sk->sk_backlog.head = skb;
+       else
                sk->sk_backlog.tail->next = skb;
-               sk->sk_backlog.tail = skb;
-       }
+
+       sk->sk_backlog.tail = skb;
        skb->next = NULL;
 }
 
@@ -1219,7 +1224,7 @@ static inline void sk_set_socket(struct sock *sk, struct socket *sock)
 
 static inline wait_queue_head_t *sk_sleep(struct sock *sk)
 {
-       return sk->sk_sleep;
+       return &sk->sk_wq->wait;
 }
 /* Detach socket from process context.
  * Announce socket dead, detach it from wait queue and inode.
@@ -1233,14 +1238,14 @@ static inline void sock_orphan(struct sock *sk)
        write_lock_bh(&sk->sk_callback_lock);
        sock_set_flag(sk, SOCK_DEAD);
        sk_set_socket(sk, NULL);
-       sk->sk_sleep  = NULL;
+       sk->sk_wq  = NULL;
        write_unlock_bh(&sk->sk_callback_lock);
 }
 
 static inline void sock_graft(struct sock *sk, struct socket *parent)
 {
        write_lock_bh(&sk->sk_callback_lock);
-       sk->sk_sleep = &parent->wait;
+       rcu_assign_pointer(sk->sk_wq, parent->wq);
        parent->sk = sk;
        sk_set_socket(sk, parent);
        security_sock_graft(sk, parent);
@@ -1335,6 +1340,12 @@ static inline int sk_can_gso(const struct sock *sk)
 
 extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
 
+static inline void sk_nocaps_add(struct sock *sk, int flags)
+{
+       sk->sk_route_nocaps |= flags;
+       sk->sk_route_caps &= ~flags;
+}
+
 static inline int skb_copy_to_page(struct sock *sk, char __user *from,
                                   struct sk_buff *skb, struct page *page,
                                   int off, int copy)
@@ -1392,12 +1403,12 @@ static inline int sk_has_allocations(const struct sock *sk)
 }
 
 /**
- * sk_has_sleeper - check if there are any waiting processes
- * @sk: socket
+ * wq_has_sleeper - check if there are any waiting processes
+ * @sk: struct socket_wq
  *
- * Returns true if socket has waiting processes
+ * Returns true if socket_wq has waiting processes
  *
- * The purpose of the sk_has_sleeper and sock_poll_wait is to wrap the memory
+ * The purpose of the wq_has_sleeper and sock_poll_wait is to wrap the memory
  * barrier call. They were added due to the race found within the tcp code.
  *
  * Consider following tcp code paths:
@@ -1410,9 +1421,10 @@ static inline int sk_has_allocations(const struct sock *sk)
  *   ...                 ...
  *   tp->rcv_nxt check   sock_def_readable
  *   ...                 {
- *   schedule               ...
- *                          if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
- *                              wake_up_interruptible(sk_sleep(sk))
+ *   schedule               rcu_read_lock();
+ *                          wq = rcu_dereference(sk->sk_wq);
+ *                          if (wq && waitqueue_active(&wq->wait))
+ *                              wake_up_interruptible(&wq->wait)
  *                          ...
  *                       }
  *
@@ -1421,19 +1433,18 @@ static inline int sk_has_allocations(const struct sock *sk)
  * could then endup calling schedule and sleep forever if there are no more
  * data on the socket.
  *
- * The sk_has_sleeper is always called right after a call to read_lock, so we
- * can use smp_mb__after_lock barrier.
  */
-static inline int sk_has_sleeper(struct sock *sk)
+static inline bool wq_has_sleeper(struct socket_wq *wq)
 {
+
        /*
         * We need to be sure we are in sync with the
         * add_wait_queue modifications to the wait queue.
         *
         * This memory barrier is paired in the sock_poll_wait.
         */
-       smp_mb__after_lock();
-       return sk_sleep(sk) && waitqueue_active(sk_sleep(sk));
+       smp_mb();
+       return wq && waitqueue_active(&wq->wait);
 }
 
 /**
@@ -1442,7 +1453,7 @@ static inline int sk_has_sleeper(struct sock *sk)
  * @wait_address:   socket wait queue
  * @p:              poll_table
  *
- * See the comments in the sk_has_sleeper function.
+ * See the comments in the wq_has_sleeper function.
  */
 static inline void sock_poll_wait(struct file *filp,
                wait_queue_head_t *wait_address, poll_table *p)
@@ -1453,7 +1464,7 @@ static inline void sock_poll_wait(struct file *filp,
                 * We need to be sure we are in sync with the
                 * socket flags modification.
                 *
-                * This memory barrier is paired in the sk_has_sleeper.
+                * This memory barrier is paired in the wq_has_sleeper.
                */
                smp_mb();
        }
@@ -1635,7 +1646,24 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
                sk->sk_stamp = kt;
 }
 
-extern void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb);
+extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+                                    struct sk_buff *skb);
+
+static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+                                         struct sk_buff *skb)
+{
+#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)                      | \
+                          (1UL << SOCK_RCVTSTAMP)                      | \
+                          (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)       | \
+                          (1UL << SOCK_TIMESTAMPING_SOFTWARE)          | \
+                          (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)      | \
+                          (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
+
+       if (sk->sk_flags & FLAGS_TS_OR_DROPS)
+               __sock_recv_ts_and_drops(msg, sk, skb);
+       else
+               sk->sk_stamp = skb->tstamp;
+}
 
 /**
  * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped