Merge branch 'perf/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[safe/jmp/linux-2.6] / include / net / sock.h
index 580d51f..092b055 100644 (file)
@@ -253,6 +253,8 @@ struct sock {
        struct {
                struct sk_buff *head;
                struct sk_buff *tail;
+               int len;
+               int limit;
        } sk_backlog;
        wait_queue_head_t       *sk_sleep;
        struct dst_entry        *sk_dst_cache;
@@ -381,6 +383,7 @@ static __inline__ void __sk_del_node(struct sock *sk)
        __hlist_del(&sk->sk_node);
 }
 
+/* NB: equivalent to hlist_del_init_rcu */
 static __inline__ int __sk_del_node_init(struct sock *sk)
 {
        if (sk_hashed(sk)) {
@@ -421,6 +424,7 @@ static __inline__ int sk_del_node_init(struct sock *sk)
        }
        return rc;
 }
+#define sk_del_node_init_rcu(sk)       sk_del_node_init(sk)
 
 static __inline__ int __sk_nulls_del_node_init_rcu(struct sock *sk)
 {
@@ -454,6 +458,12 @@ static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list)
        __sk_add_node(sk, list);
 }
 
+static __inline__ void sk_add_node_rcu(struct sock *sk, struct hlist_head *list)
+{
+       sock_hold(sk);
+       hlist_add_head_rcu(&sk->sk_node, list);
+}
+
 static __inline__ void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
 {
        hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list);
@@ -478,6 +488,8 @@ static __inline__ void sk_add_bind_node(struct sock *sk,
 
 #define sk_for_each(__sk, node, list) \
        hlist_for_each_entry(__sk, node, list, sk_node)
+#define sk_for_each_rcu(__sk, node, list) \
+       hlist_for_each_entry_rcu(__sk, node, list, sk_node)
 #define sk_nulls_for_each(__sk, node, list) \
        hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node)
 #define sk_nulls_for_each_rcu(__sk, node, list) \
@@ -579,8 +591,8 @@ static inline int sk_stream_memory_free(struct sock *sk)
        return sk->sk_wmem_queued < sk->sk_sndbuf;
 }
 
-/* The per-socket spinlock must be held here. */
-static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
+/* 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;
@@ -591,6 +603,17 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
        skb->next = NULL;
 }
 
+/* The per-socket spinlock must be held here. */
+static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb)
+{
+       if (sk->sk_backlog.len >= max(sk->sk_backlog.limit, sk->sk_rcvbuf << 1))
+               return -ENOBUFS;
+
+       __sk_add_backlog(sk, skb);
+       sk->sk_backlog.len += skb->truesize;
+       return 0;
+}
+
 static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        return sk->sk_backlog_rcv(sk, skb);