atomic_t                sk_drops;
        int                     sk_rcvlowat;
        struct sk_buff_head     sk_error_queue;
+       struct sk_buff          *sk_rx_skb_cache;
        struct sk_buff_head     sk_receive_queue;
        /*
         * The backlog queue is special, it is always used with
 static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb)
 {
        __skb_unlink(skb, &sk->sk_receive_queue);
+       if (
+#ifdef CONFIG_RPS
+           !static_branch_unlikely(&rps_needed) &&
+#endif
+           !sk->sk_rx_skb_cache) {
+               sk->sk_rx_skb_cache = skb;
+               skb_orphan(skb);
+               return;
+       }
        __kfree_skb(skb);
 }
 
 
        struct inet_sock *inet = inet_sk(sk);
 
        __skb_queue_purge(&sk->sk_receive_queue);
+       if (sk->sk_rx_skb_cache) {
+               __kfree_skb(sk->sk_rx_skb_cache);
+               sk->sk_rx_skb_cache = NULL;
+       }
        __skb_queue_purge(&sk->sk_error_queue);
 
        sk_mem_reclaim(sk);
 
 
        tcp_clear_xmit_timers(sk);
        __skb_queue_purge(&sk->sk_receive_queue);
+       if (sk->sk_rx_skb_cache) {
+               __kfree_skb(sk->sk_rx_skb_cache);
+               sk->sk_rx_skb_cache = NULL;
+       }
        tp->copied_seq = tp->rcv_nxt;
        tp->urg_data = 0;
        tcp_write_queue_purge(sk);
 
 int tcp_v4_rcv(struct sk_buff *skb)
 {
        struct net *net = dev_net(skb->dev);
+       struct sk_buff *skb_to_free;
        int sdif = inet_sdif(skb);
        const struct iphdr *iph;
        const struct tcphdr *th;
        tcp_segs_in(tcp_sk(sk), skb);
        ret = 0;
        if (!sock_owned_by_user(sk)) {
+               skb_to_free = sk->sk_rx_skb_cache;
+               sk->sk_rx_skb_cache = NULL;
                ret = tcp_v4_do_rcv(sk, skb);
-       } else if (tcp_add_backlog(sk, skb)) {
-               goto discard_and_relse;
+       } else {
+               if (tcp_add_backlog(sk, skb))
+                       goto discard_and_relse;
+               skb_to_free = NULL;
        }
        bh_unlock_sock(sk);
+       if (skb_to_free)
+               __kfree_skb(skb_to_free);
 
 put_and_return:
        if (refcounted)
 
 
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
+       struct sk_buff *skb_to_free;
        int sdif = inet6_sdif(skb);
        const struct tcphdr *th;
        const struct ipv6hdr *hdr;
        tcp_segs_in(tcp_sk(sk), skb);
        ret = 0;
        if (!sock_owned_by_user(sk)) {
+               skb_to_free = sk->sk_rx_skb_cache;
+               sk->sk_rx_skb_cache = NULL;
                ret = tcp_v6_do_rcv(sk, skb);
-       } else if (tcp_add_backlog(sk, skb)) {
-               goto discard_and_relse;
+       } else {
+               if (tcp_add_backlog(sk, skb))
+                       goto discard_and_relse;
+               skb_to_free = NULL;
        }
        bh_unlock_sock(sk);
-
+       if (skb_to_free)
+               __kfree_skb(skb_to_free);
 put_and_return:
        if (refcounted)
                sock_put(sk);