--- 2.6.12.3.clean/include/linux/gfp.h 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/include/linux/gfp.h 2005-08-04 00:12:48.000000000 -0400 @@ -39,6 +39,7 @@ #define __GFP_COMP 0x4000u /* Add compound page metadata */ #define __GFP_ZERO 0x8000u /* Return zeroed page on success */ #define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */ +#define __GFP_MEMALLOC 0x20000u /* Use emergency reserves */ #define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) --- 2.6.12.3.clean/include/linux/skbuff.h 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/include/linux/skbuff.h 2005-08-04 13:46:35.000000000 -0400 @@ -969,7 +969,6 @@ kfree_skb(skb); } -#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB /** * __dev_alloc_skb - allocate an skbuff for sending * @length: length to allocate @@ -982,17 +981,17 @@ * * %NULL is returned in there is no free memory. */ -static inline struct sk_buff *__dev_alloc_skb(unsigned int length, - int gfp_mask) +static inline struct sk_buff *__dev_alloc_skb(unsigned length, int gfp_mask) { - struct sk_buff *skb = alloc_skb(length + 16, gfp_mask); + int opaque = 16, size = length + opaque; + struct sk_buff *skb = alloc_skb(size, gfp_mask & ~__GFP_MEMALLOC); + + if (unlikely(!skb) && (gfp_mask & __GFP_MEMALLOC)) + skb = alloc_skb(size, gfp_mask); if (likely(skb)) - skb_reserve(skb, 16); + skb_reserve(skb, opaque); return skb; } -#else -extern struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask); -#endif /** * dev_alloc_skb - allocate an skbuff for sending @@ -1011,6 +1010,16 @@ return __dev_alloc_skb(length, GFP_ATOMIC); } +static inline struct sk_buff *dev_alloc_skb_reserve(unsigned int length) +{ + return __dev_alloc_skb(length, gfp_mask | __GFP_MEMALLOC); +} + +static inline int is_memalloc_skb(struct sk_buff *skb) +{ + return !!(skb->priority & __GFP_MEMALLOC); +} + /** * skb_cow - copy header of skb when it is required * @skb: buffer to cow --- 2.6.12.3.clean/include/net/sock.h 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/include/net/sock.h 2005-08-04 00:12:49.000000000 -0400 @@ -382,6 +382,7 @@ SOCK_NO_LARGESEND, /* whether to sent large segments or not */ SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ + SOCK_MEMALLOC, /* protocol can use memalloc reserve */ }; static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) @@ -399,6 +400,11 @@ return test_bit(flag, &sk->sk_flags); } +static inline int is_memalloc_sock(struct sock *sk) +{ + return sock_flag(sk, SOCK_MEMALLOC); +} + static inline void sk_acceptq_removed(struct sock *sk) { sk->sk_ack_backlog--; --- 2.6.12.3.clean/mm/page_alloc.c 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/mm/page_alloc.c 2005-08-04 00:12:49.000000000 -0400 @@ -802,8 +802,8 @@ /* This allocation should allow future memory freeing. */ - if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) - && !in_interrupt()) { + if ((((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) + && !in_interrupt()) || (gfp_mask & __GFP_MEMALLOC)) { if (!(gfp_mask & __GFP_NOMEMALLOC)) { /* go through the zonelist yet again, ignoring mins */ for (i = 0; (z = zones[i]) != NULL; i++) { --- 2.6.12.3.clean/net/core/dev.c 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/net/core/dev.c 2005-08-04 00:12:49.000000000 -0400 @@ -1452,6 +1452,11 @@ struct softnet_data *queue; unsigned long flags; + if (unlikely(is_memalloc_skb(skb))) { + netif_receive_skb(skb); + return NET_RX_CN_HIGH; + } + /* if netpoll wants it, pretend we never saw it */ if (netpoll_rx(skb)) return NET_RX_DROP; --- 2.6.12.3.clean/net/core/skbuff.c 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/net/core/skbuff.c 2005-08-04 00:12:49.000000000 -0400 @@ -355,7 +355,7 @@ n->nohdr = 0; C(pkt_type); C(ip_summed); - C(priority); + n->priority = skb->priority & ~__GFP_MEMALLOC; C(protocol); C(security); n->destructor = NULL; @@ -411,7 +411,7 @@ new->sk = NULL; new->dev = old->dev; new->real_dev = old->real_dev; - new->priority = old->priority; + new->priority = old->priority & ~__GFP_MEMALLOC; new->protocol = old->protocol; new->dst = dst_clone(old->dst); #ifdef CONFIG_INET --- 2.6.12.3.clean/net/ipv4/tcp_ipv4.c 2005-07-15 17:18:57.000000000 -0400 +++ 2.6.12.3/net/ipv4/tcp_ipv4.c 2005-08-04 00:12:49.000000000 -0400 @@ -1766,6 +1766,9 @@ if (!sk) goto no_tcp_socket; + if (unlikely(is_memalloc_skb(skb)) && !is_memalloc_sock(sk)) + goto discard_and_relse; + process: if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait;