*    @sk_omem_alloc: "o" is "option" or "other"
   *    @sk_wmem_queued: persistent queue size
   *    @sk_forward_alloc: space allocated forward
+  *    @sk_reserved_mem: space reserved and non-reclaimable for the socket
   *    @sk_napi_id: id of the last napi context to receive data for sk
   *    @sk_ll_usec: usecs to busypoll when there is no data
   *    @sk_allocation: allocation mode
 #define sk_rmem_alloc sk_backlog.rmem_alloc
 
        int                     sk_forward_alloc;
+       u32                     sk_reserved_mem;
 #ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int            sk_ll_usec;
        /* ===== mostly read cache line ===== */
                skb_pfmemalloc(skb);
 }
 
+static inline int sk_unused_reserved_mem(const struct sock *sk)
+{
+       int unused_mem;
+
+       if (likely(!sk->sk_reserved_mem))
+               return 0;
+
+       unused_mem = sk->sk_reserved_mem - sk->sk_wmem_queued -
+                       atomic_read(&sk->sk_rmem_alloc);
+
+       return unused_mem > 0 ? unused_mem : 0;
+}
+
 static inline void sk_mem_reclaim(struct sock *sk)
 {
+       int reclaimable;
+
        if (!sk_has_account(sk))
                return;
-       if (sk->sk_forward_alloc >= SK_MEM_QUANTUM)
-               __sk_mem_reclaim(sk, sk->sk_forward_alloc);
+
+       reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
+
+       if (reclaimable >= SK_MEM_QUANTUM)
+               __sk_mem_reclaim(sk, reclaimable);
+}
+
+static inline void sk_mem_reclaim_final(struct sock *sk)
+{
+       sk->sk_reserved_mem = 0;
+       sk_mem_reclaim(sk);
 }
 
 static inline void sk_mem_reclaim_partial(struct sock *sk)
 {
+       int reclaimable;
+
        if (!sk_has_account(sk))
                return;
-       if (sk->sk_forward_alloc > SK_MEM_QUANTUM)
-               __sk_mem_reclaim(sk, sk->sk_forward_alloc - 1);
+
+       reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
+
+       if (reclaimable > SK_MEM_QUANTUM)
+               __sk_mem_reclaim(sk, reclaimable - 1);
 }
 
 static inline void sk_mem_charge(struct sock *sk, int size)
 
 static inline void sk_mem_uncharge(struct sock *sk, int size)
 {
+       int reclaimable;
+
        if (!sk_has_account(sk))
                return;
        sk->sk_forward_alloc += size;
+       reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
 
        /* Avoid a possible overflow.
         * TCP send queues can make this happen, if sk_mem_reclaim()
         * If we reach 2 MBytes, reclaim 1 MBytes right now, there is
         * no need to hold that much forward allocation anyway.
         */
-       if (unlikely(sk->sk_forward_alloc >= 1 << 21))
+       if (unlikely(reclaimable >= 1 << 21))
                __sk_mem_reclaim(sk, 1 << 20);
 }
 
 
 
 #define SO_BUF_LOCK            72
 
+#define SO_RESERVE_MEM         73
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
 
 }
 EXPORT_SYMBOL(sock_set_mark);
 
+static void sock_release_reserved_memory(struct sock *sk, int bytes)
+{
+       /* Round down bytes to multiple of pages */
+       bytes &= ~(SK_MEM_QUANTUM - 1);
+
+       WARN_ON(bytes > sk->sk_reserved_mem);
+       sk->sk_reserved_mem -= bytes;
+       sk_mem_reclaim(sk);
+}
+
+static int sock_reserve_memory(struct sock *sk, int bytes)
+{
+       long allocated;
+       bool charged;
+       int pages;
+
+       if (!mem_cgroup_sockets_enabled || !sk->sk_memcg)
+               return -EOPNOTSUPP;
+
+       if (!bytes)
+               return 0;
+
+       pages = sk_mem_pages(bytes);
+
+       /* pre-charge to memcg */
+       charged = mem_cgroup_charge_skmem(sk->sk_memcg, pages,
+                                         GFP_KERNEL | __GFP_RETRY_MAYFAIL);
+       if (!charged)
+               return -ENOMEM;
+
+       /* pre-charge to forward_alloc */
+       allocated = sk_memory_allocated_add(sk, pages);
+       /* If the system goes into memory pressure with this
+        * precharge, give up and return error.
+        */
+       if (allocated > sk_prot_mem_limits(sk, 1)) {
+               sk_memory_allocated_sub(sk, pages);
+               mem_cgroup_uncharge_skmem(sk->sk_memcg, pages);
+               return -ENOMEM;
+       }
+       sk->sk_forward_alloc += pages << SK_MEM_QUANTUM_SHIFT;
+
+       sk->sk_reserved_mem += pages << SK_MEM_QUANTUM_SHIFT;
+
+       return 0;
+}
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
                                          ~SOCK_BUF_LOCK_MASK);
                break;
 
+       case SO_RESERVE_MEM:
+       {
+               int delta;
+
+               if (val < 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               delta = val - sk->sk_reserved_mem;
+               if (delta < 0)
+                       sock_release_reserved_memory(sk, -delta);
+               else
+                       ret = sock_reserve_memory(sk, delta);
+               break;
+       }
+
        default:
                ret = -ENOPROTOOPT;
                break;
                v.val = sk->sk_userlocks & SOCK_BUF_LOCK_MASK;
                break;
 
+       case SO_RESERVE_MEM:
+               v.val = sk->sk_reserved_mem;
+               break;
+
        default:
                /* We implement the SO_SNDLOWAT etc to not be settable
                 * (1003.1g 7).
        newsk->sk_dst_pending_confirm = 0;
        newsk->sk_wmem_queued   = 0;
        newsk->sk_forward_alloc = 0;
+       newsk->sk_reserved_mem  = 0;
        atomic_set(&newsk->sk_drops, 0);
        newsk->sk_send_head     = NULL;
        newsk->sk_userlocks     = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;
 
        WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
 
        /* Account for returned memory. */
-       sk_mem_reclaim(sk);
+       sk_mem_reclaim_final(sk);
 
        WARN_ON(sk->sk_wmem_queued);
        WARN_ON(sk->sk_forward_alloc);
 
        __skb_queue_purge(&sk->sk_receive_queue);
        __skb_queue_purge(&sk->sk_error_queue);
 
-       sk_mem_reclaim(sk);
+       sk_mem_reclaim_final(sk);
 
        if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
                pr_err("Attempt to release TCP socket in state %d %p\n",