From: Peter Zijlstra <hidden> Date: 2007-02-21 15:34:07
(patches against 2.6.20-mm1)
There is a fundamental deadlock associated with paging; when writing out a page
to free memory requires free memory to complete. The usually solution is to
keep a small amount of memory available at all times so we can overcome this
problem. This however assumes the amount of memory needed for writeout is
(constant and) smaller than the provided reserve.
It is this latter assumption that breaks when doing writeout over network.
Network can take up an unspecified amount of memory while waiting for a reply
to our write request. This re-introduces the deadlock; we might never complete
the writeout, for we might not have enough memory to receive the completion
message.
The proposed solution is simple, only allow traffic servicing the VM to make
use of the reserves. Since the VM is always present to service, this limited
amount of memory can sustain a full connection; after a packet has been
processed its memory can be re-used for the next packet.
This however implies you know what packets are for whom, which generally
speaking you don't. Hence we need to receive all packets but discard them as
soon as we encounter a non VM bound packet allocated from the reserves.
Also knowing it is headed towards the VM needs a little help, hence we
introduce the socket flag SOCK_VMIO to mark sockets with.
Of course, since we are paging all this has to happen in kernel-space, since
user-space might just not be there.
Since packet processing might also require memory, this all also implies that
those auxiliary allocations may use the reserves when an emergency packet is
processed. This is accomplished by using PF_MEMALLOC.
How much memory is to be reserved is also an issue, enough memory to saturate
both the route cache and IP fragment reassembly, along with various constants.
This patch-set comes in 5 parts:
1) introduce the memory reserve and make the SLAB allocator play nice with it.
patches 01-09
2) add some needed infrastructure to the network code
patches 10-12
3) implement the idea outlined above
patches 13-19
4) teach the swap machinery to use generic address_spaces
patches 20-23
5) implement swap over NFS using all the new stuff
patches 24-29
--
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:05:47
If we have a lot of dirty memory and hit the throttle in balance_dirty_pages()
we (potentially) generate a lot of writeback and unstable pages, if however
during this writeback we need to reclaim a bit, we might hit
throttle_vm_writeout(), which might delay us until the combined total of
NR_UNSTABLE_NFS + NR_WRITEBACK falls below the dirty limit.
However unstable pages don't go away automagickally, they need a push. While
balance_dirty_pages() does this push, throttle_vm_writeout() doesn't. So we can
sit here ad infintum.
Hence I propose to remove the NR_UNSTABLE_NFS count from throttle_vm_writeout().
Signed-off-by: Peter Zijlstra <redacted>
---
mm/page-writeback.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
Index: linux-2.6-git/mm/page-writeback.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:06:08
The slab allocator has some unfairness wrt gfp flags; when the slab cache is
grown the gfp flags are used to allocate more memory, however when there is
slab cache available (in partial or free slabs, per cpu caches or otherwise)
gfp flags are ignored.
Thus it is possible for less critical slab allocations to succeed and gobble
up precious memory when under memory pressure.
This patch solves that by using the newly introduced page allocation rank.
Page allocation rank is a scalar quantity connecting ALLOC_ and gfp flags which
represents how deep we had to reach into our reserves when allocating a page.
Rank 0 is the deepest we can reach (ALLOC_NO_WATERMARK) and 16 is the most
shallow allocation possible (ALLOC_WMARK_HIGH).
When the slab space is grown the rank of the page allocation is stored. For
each slab allocation we test the given gfp flags against this rank. Thereby
asking the question: would these flags have allowed the slab to grow.
If not so, we need to test the current situation. This is done by forcing the
growth of the slab space. (Just testing the free page limits will not work due
to direct reclaim) Failing this we need to fail the slab allocation.
Thus if we grew the slab under great duress while PF_MEMALLOC was set and we
really did access the memalloc reserve the rank would be set to 0. If the next
allocation to that slab would be GFP_NOFS|__GFP_NOMEMALLOC (which ordinarily
maps to rank 4 and always > 0) we'd want to make sure that memory pressure has
decreased enough to allow an allocation with the given gfp flags.
So in this case we try to force grow the slab cache and on failure we fail the
slab allocation. Thus preserving the available slab cache for more pressing
allocations.
If this newly allocated slab will be trimmed on the next kmem_cache_free
(not unlikely) this is no problem, since 1) it will free memory and 2) the
sole purpose of the allocation was to probe the allocation rank, we didn't
need the space itself.
[AIM9 results go here]
Signed-off-by: Peter Zijlstra <redacted>
---
mm/Kconfig | 3 ++
mm/slab.c | 81 ++++++++++++++++++++++++++++++++++++++++---------------------
2 files changed, 57 insertions(+), 27 deletions(-)
Index: linux-2.6/mm/slab.c
===================================================================
@@ -3020,14 +3026,16 @@ must_grow:l3->free_objects-=ac->avail;alloc_done:spin_unlock(&l3->list_lock);-if(unlikely(!ac->avail)){intx;+force_grow:x=cache_grow(cachep,flags|GFP_THISNODE,node,NULL);/* cache_grow can reenable interrupts, then ac could change. */ac=cpu_cache_get(cachep);-if(!x&&ac->avail==0)/* no objects in sight? abort */++/* no objects in sight? abort */+if(!x&&(ac->avail==0||rank>cachep->rank))returnNULL;if(!ac->avail)/* objects refilled by interrupt? */
@@ -3404,12 +3430,12 @@ __cache_alloc_node(struct kmem_cache *ca*toothernodes.Itmayfailwhilewestillhave*objectsonothernodesavailable.*/-ptr=____cache_alloc(cachep,flags);+ptr=____cache_alloc(cachep,flags,rank);if(ptr)gotoout;}/* ___cache_alloc_node can fall back to other nodes */-ptr=____cache_alloc_node(cachep,flags,nodeid);+ptr=____cache_alloc_node(cachep,flags,nodeid,rank);out:local_irq_restore(save_flags);ptr=cache_alloc_debugcheck_after(cachep,flags,ptr,caller);
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:06:24
Move around the swap entry methods in preparation for use from
page methods.
Also provide a function to obtain the swap_info_struct backing
a swap cache page.
Signed-off-by: Peter Zijlstra <redacted>
CC: Trond Myklebust <redacted>
---
include/linux/mm.h | 8 ++++++++
include/linux/swap.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/swapops.h | 44 --------------------------------------------
mm/swapfile.c | 1 +
4 files changed, 57 insertions(+), 44 deletions(-)
Index: linux-2.6-git/include/linux/mm.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:06:57
Provide means to reserve a specific amount pages.
The emergency pool is separated from the min watermark because ALLOC_HARDER
and ALLOC_HIGH modify the watermark in a relative way and thus do not ensure
a strict minimum.
Signed-off-by: Peter Zijlstra <redacted>
---
include/linux/mmzone.h | 3 +-
mm/page_alloc.c | 52 ++++++++++++++++++++++++++++++++++++++++---------
mm/vmstat.c | 6 ++---
3 files changed, 48 insertions(+), 13 deletions(-)
Index: linux-2.6-git/include/linux/mmzone.h
===================================================================
@@ -178,7 +178,7 @@ enum zone_type {structzone{/* Fields commonly accessed by the page allocator */-unsignedlongpages_min,pages_low,pages_high;+unsignedlongpages_emerg,pages_min,pages_low,pages_high;/**Wedon'tknowifthememorythatwe'regoingtoallocatewillbefreeable*or/anditwillbereleasedeventually,sotoavoidtotallywastingseveral
@@ -562,6 +562,7 @@ int sysctl_min_unmapped_ratio_sysctl_hanstructfile*,void__user*,size_t*,loff_t*);intsysctl_min_slab_ratio_sysctl_handler(structctl_table*,int,structfile*,void__user*,size_t*,loff_t*);+voidadjust_memalloc_reserve(intpages);#include<linux/topology.h>/* Returns the number of the current Node. */
@@ -995,7 +996,8 @@ int zone_watermark_ok(struct zone *z, inif(alloc_flags&ALLOC_HARDER)min-=min/4;-if(free_pages<=min+z->lowmem_reserve[classzone_idx])+if(free_pages<=min+z->lowmem_reserve[classzone_idx]++z->pages_emerg)return0;for(o=0;o<order;o++){/* At the next order, this order's pages become unavailable */
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:07:47
With the introduction of the shared dirty page accounting in .19, NFS should
not be able to surpise the VM with all dirty pages. Thus it should always be
able to free some memory. Hence no more need for mempools.
Signed-off-by: Peter Zijlstra <redacted>
Cc: Trond Myklebust <redacted>
---
fs/nfs/read.c | 15 +++------------
fs/nfs/write.c | 27 +++++----------------------
2 files changed, 8 insertions(+), 34 deletions(-)
Index: linux-2.6-git/fs/nfs/read.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:08:24
In order to make sure emergency packets receive all memory needed to proceed
ensure processing of emergency skbs happens under PF_MEMALLOC.
Use the (new) sk_backlog_rcv() wrapper to ensure this for backlog processing.
Skip taps, since those are user-space again.
Signed-off-by: Peter Zijlstra <redacted>
---
include/net/sock.h | 4 ++++
net/core/dev.c | 42 +++++++++++++++++++++++++++++++++++++-----
net/core/sock.c | 19 +++++++++++++++++++
3 files changed, 60 insertions(+), 5 deletions(-)
Index: linux-2.6-git/net/core/dev.c
===================================================================
@@ -1767,10 +1767,23 @@ int netif_receive_skb(struct sk_buff *skstructnet_device*orig_dev;intret=NET_RX_DROP;__be16type;+unsignedlongpflags=current->flags;++/* Emergency skb are special, they should+*-bedeliveredtoSOCK_VMIOsocketsonly+*-stayawayfromuserspace+*-haveboundedmemoryusage+*+*UsePF_MEMALLOCasapoormansmemorypool-thegroupingkind.+*Thissavesusfrompropagatingtheallocationcontextdowntoall+*allocationsites.+*/+if(skb_emergency(skb))+current->flags|=PF_MEMALLOC;/* if we've gotten here through NAPI, check netpoll */if(skb->dev->poll&&netpoll_rx(skb))-returnNET_RX_DROP;+gotoout;if(!skb->tstamp.off_sec)net_timestamp(skb);
@@ -1781,7 +1794,7 @@ int netif_receive_skb(struct sk_buff *skorig_dev=skb_bond(skb);if(!orig_dev)-returnNET_RX_DROP;+gotoout;__get_cpu_var(netdev_rx_stat).total++;
@@ -1799,6 +1812,9 @@ int netif_receive_skb(struct sk_buff *sk}#endif+if(skb_emergency(skb))+gotoskip_taps;+list_for_each_entry_rcu(ptype,&ptype_all,list){if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)
@@ -1807,6 +1823,7 @@ int netif_receive_skb(struct sk_buff *sk}}+skip_taps:#ifdef CONFIG_NET_CLS_ACTif(pt_prev){ret=deliver_skb(skb,pt_prev,orig_dev);
@@ -1819,15 +1836,27 @@ int netif_receive_skb(struct sk_buff *skif(ret==TC_ACT_SHOT||(ret==TC_ACT_STOLEN)){kfree_skb(skb);-gotoout;+gotounlock;}skb->tc_verd=0;ncls:#endif+if(skb_emergency(skb))+switch(skb->protocol){+case__constant_htons(ETH_P_ARP):+case__constant_htons(ETH_P_IP):+case__constant_htons(ETH_P_IPV6):+case__constant_htons(ETH_P_8021Q):+break;++default:+gotodrop;+}+if(handle_bridge(&skb,&pt_prev,&ret,orig_dev))-gotoout;+gotounlock;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&15],list){
@@ -1842,6 +1871,7 @@ ncls:if(pt_prev){ret=pt_prev->func(skb,skb->dev,pt_prev,orig_dev);}else{+drop:kfree_skb(skb);/* Jamal, now you will not able to escape explaining*mehowyouweregoingtousethis.:-)
@@ -332,6 +332,25 @@ int sk_clear_vmio(struct sock *sk)}EXPORT_SYMBOL_GPL(sk_clear_vmio);+#ifdef CONFIG_NETVM+intsk_backlog_rcv(structsock*sk,structsk_buff*skb)+{+if(skb_emergency(skb)){+intret;+unsignedlongpflags=current->flags;+/* these should have been dropped before queueing */+BUG_ON(!sk_has_vmio(sk));+current->flags|=PF_MEMALLOC;+ret=sk->sk_backlog_rcv(sk,skb);+current->flags=pflags;+returnret;+}++returnsk->sk_backlog_rcv(sk,skb);+}+EXPORT_SYMBOL(sk_backlog_rcv);+#endif+staticintsock_set_timeout(long*timeo_p,char__user*optval,intoptlen){structtimevaltv;
@@ -133,13 +133,13 @@ static struct nfs_page *nfs_page_find_re/* Adjust the file length if we're writing beyond the end */staticvoidnfs_grow_file(structpage*page,unsignedintoffset,unsignedintcount){-structinode*inode=page->mapping->host;+structinode*inode=page_file_mapping(page)->host;loff_tend,i_size=i_size_read(inode);unsignedlongend_index=(i_size-1)>>PAGE_CACHE_SHIFT;-if(i_size>0&&page->index<end_index)+if(i_size>0&&page_file_index(page)<end_index)return;-end=((loff_t)page->index<<PAGE_CACHE_SHIFT)+((loff_t)offset+count);+end=page_offset(page)+((loff_t)offset+count);if(i_size>=end)return;nfs_inc_stats(inode,NFSIOS_EXTENDWRITE);
@@ -150,7 +150,7 @@ static void nfs_grow_file(struct page *pstaticvoidnfs_set_pageerror(structpage*page){SetPageError(page);-nfs_zap_mapping(page->mapping->host,page->mapping);+nfs_zap_mapping(page_file_mapping(page)->host,page_file_mapping(page));}/* We can set the PG_uptodate flag if we see that a write request
@@ -182,7 +182,7 @@ static int nfs_writepage_setup(struct nfret=PTR_ERR(req);if(ret!=-EBUSY)returnret;-ret=nfs_wb_page(page->mapping->host,page);+ret=nfs_wb_page(page_file_mapping(page)->host,page);if(ret!=0)returnret;}
@@ -216,7 +216,7 @@ int nfs_congestion_kb;staticvoidnfs_set_page_writeback(structpage*page){if(!test_set_page_writeback(page)){-structinode*inode=page->mapping->host;+structinode*inode=page_file_mapping(page)->host;structnfs_server*nfss=NFS_SERVER(inode);if(atomic_inc_return(&nfss->writeback)>
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:31:28
Toss all emergency packets not for a SOCK_VMIO socket. This ensures our
precious memory reserve doesn't get stuck waiting for user-space.
Signed-off-by: Peter Zijlstra <redacted>
---
include/net/sock.h | 3 +++
1 file changed, 3 insertions(+)
Index: linux-2.6-git/include/net/sock.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:32:04
Emergency skbs should never touch user-space, however NF_QUEUE is fully user
configurable. Notify the user of his mistake and try to continue.
Signed-off-by: Peter Zijlstra <redacted>
---
net/netfilter/core.c | 5 +++++
1 file changed, 5 insertions(+)
Index: linux-2.6-git/net/netfilter/core.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:32:27
Allow the mempool to use the memalloc reserves when all else fails and
the allocation context would otherwise allow it.
Signed-off-by: Peter Zijlstra <redacted>
---
mm/mempool.c | 10 ++++++++++
1 file changed, 10 insertions(+)
Index: linux-2.6-git/mm/mempool.c
===================================================================
@@ -229,6 +230,15 @@ repeat_alloc:}spin_unlock_irqrestore(&pool->lock,flags);+/* if we really had right to the emergency reserves try those */+if(gfp_to_alloc_flags(gfp_mask)&ALLOC_NO_WATERMARKS){+if(gfp_temp&__GFP_NOMEMALLOC){+gfp_temp&=~(__GFP_NOMEMALLOC|__GFP_NOWARN);+gotorepeat_alloc;+}else+gfp_temp|=__GFP_NOMEMALLOC|__GFP_NOWARN;+}+/* We must not sleep in the GFP_ATOMIC case */if(!(gfp_mask&__GFP_WAIT))returnNULL;
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:32:56
When 'include/linux/mm.h' includes 'include/linux/swap.h', the global
remove_mapping() definition clashes with the arch/um one.
Rename the arch/um one.
Signed-off-by: Peter Zijlstra <redacted>
Acked-by: Jeff Dike <redacted>
---
arch/um/kernel/physmem.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
Index: linux-2.6-git/arch/um/kernel/physmem.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:33:18
Provide a method to calculate the number of pages needed to store a given
number of slab objects (upper bound when considering possible partial and
free slabs).
Signed-off-by: Peter Zijlstra <redacted>
---
include/linux/slab.h | 1 +
mm/slab.c | 6 ++++++
2 files changed, 7 insertions(+)
Index: linux-2.6-git/include/linux/slab.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:33:33
There is a small race between the procfs caller and the memory hotplug caller
of setup_per_zone_pages_min(). Not a big deal, but the next patch will add yet
another caller. Time to close the gap.
Signed-off-by: Peter Zijlstra <redacted>
---
mm/page_alloc.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
Index: linux-2.6-git/mm/page_alloc.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:34:30
Allow PF_MEMALLOC to be set in softirq context. When running softirqs from
a borrowed context save current->flags, ksoftirqd will have its own
task_struct.
Signed-off-by: Peter Zijlstra <redacted>
---
kernel/softirq.c | 3 +++
mm/internal.h | 14 ++++++++------
2 files changed, 11 insertions(+), 6 deletions(-)
Index: linux-2.6-git/mm/internal.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:34:41
It could happen that all !SOCK_VMIO sockets have buffered so much data
that we're over the global rmem limit. This will prevent SOCK_VMIO buffers
from receiving data, which will prevent userspace from running, which is needed
to reduce the buffered data.
Signed-off-by: Peter Zijlstra <redacted>
---
include/net/sock.h | 7 ++++---
net/core/stream.c | 5 +++--
net/ipv4/tcp_ipv4.c | 8 ++++++++
net/ipv6/tcp_ipv6.c | 8 ++++++++
4 files changed, 23 insertions(+), 5 deletions(-)
Index: linux-2.6-git/include/net/sock.h
===================================================================
@@ -757,13 +758,13 @@ static inline void sk_stream_writequeue_staticinlineintsk_stream_rmem_schedule(structsock*sk,structsk_buff*skb){return(int)skb->truesize<=sk->sk_forward_alloc||-sk_stream_mem_schedule(sk,skb->truesize,1);+sk_stream_mem_schedule(sk,skb,skb->truesize,1);}staticinlineintsk_stream_wmem_schedule(structsock*sk,intsize){returnsize<=sk->sk_forward_alloc||-sk_stream_mem_schedule(sk,size,0);+sk_stream_mem_schedule(sk,NULL,size,0);}/* Used by processes to "lock" a socket state, so that
@@ -224,7 +224,8 @@ int sk_stream_mem_schedule(struct sock */* Over hard limit. */if(atomic_read(sk->sk_prot->memory_allocated)>sk->sk_prot->sysctl_mem[2]){sk->sk_prot->enter_memory_pressure();-gotosuppress_allocation;+if(!skb||(skb&&!skb_emergency(skb)))+gotosuppress_allocation;}/* Under pressure. */
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:34:49
In order to teach filesystems to handle swap cache pages, two new page
functions are introduced:
pgoff_t page_file_index(struct page *);
struct address_space *page_file_mapping(struct page *);
page_file_index - gives the offset of this page in the file in PAGE_CACHE_SIZE
blocks. Like page->index is for mapped pages, this function also gives the
correct index for PG_swapcache pages.
page_file_mapping - gives the mapping backing the actual page; that is for
swap cache pages it will give swap_file->f_mapping.
page_offset() is modified to use page_file_index(), so that it will give the
expected result, even for PG_swapcache pages.
Signed-off-by: Peter Zijlstra <redacted>
CC: Trond Myklebust <redacted>
---
include/linux/mm.h | 25 +++++++++++++++++++++++++
include/linux/pagemap.h | 2 +-
2 files changed, 26 insertions(+), 1 deletion(-)
Index: linux-2.6-git/include/linux/mm.h
===================================================================
@@ -198,61 +198,6 @@ nodata:}/**-*alloc_skb_from_cache-allocateanetworkbuffer-*@cp:kmem_cachefromwhichtoallocatethedataarea-*(objectsizemustbebigenoughfor@sizebytes+skboverheads)-*@size:sizetoallocate-*@gfp_mask:allocationmask-*-*Allocateanew&sk_buff.Thereturnedbufferhasnoheadroomand-*tailroomofsizebytes.Theobjecthasareferencecountofone.-*Thereturnisthebuffer.Onafailurethereturnis%NULL.-*-*Buffersmayonlybeallocatedfrominterruptsusinga@gfp_maskof-*%GFP_ATOMIC.-*/-structsk_buff*alloc_skb_from_cache(structkmem_cache*cp,-unsignedintsize,-gfp_tgfp_mask)-{-structsk_buff*skb;-u8*data;--/* Get the HEAD */-skb=kmem_cache_alloc(skbuff_head_cache,-gfp_mask&~__GFP_DMA);-if(!skb)-gotoout;--/* Get the DATA. */-size=SKB_DATA_ALIGN(size);-data=kmem_cache_alloc(cp,gfp_mask);-if(!data)-gotonodata;--memset(skb,0,offsetof(structsk_buff,truesize));-skb->truesize=size+sizeof(structsk_buff);-atomic_set(&skb->users,1);-skb->head=data;-skb->data=data;-skb->tail=data;-skb->end=data+size;--atomic_set(&(skb_shinfo(skb)->dataref),1);-skb_shinfo(skb)->nr_frags=0;-skb_shinfo(skb)->gso_size=0;-skb_shinfo(skb)->gso_segs=0;-skb_shinfo(skb)->gso_type=0;-skb_shinfo(skb)->frag_list=NULL;-out:-returnskb;-nodata:-kmem_cache_free(skbuff_head_cache,skb);-skb=NULL;-gotoout;-}--/***__netdev_alloc_skb-allocateanskbuffforrxonaspecificdevice*@dev:networkdevicetoreceiveon*@length:lengthtoallocate
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:35:40
__GFP_EMERGENCY will allow the allocation to disregard the watermarks,
much like PF_MEMALLOC.
Signed-off-by: Peter Zijlstra <redacted>
---
include/linux/gfp.h | 7 ++++++-
mm/internal.h | 10 +++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
Index: linux-2.6-git/include/linux/gfp.h
===================================================================
@@ -54,7 +58,8 @@ struct vm_area_struct;#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT|\__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP|\-__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)+__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE|\+__GFP_EMERGENCY)/* This equals 0, but use constants in case they ever change */#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:36:09
Do as Trond suggested:
http://lkml.org/lkml/2006/8/25/348
Disable NFS data cache revalidation on swap files since it doesn't really
make sense to have other clients change the file while you are using it.
Thereby we can stop setting PG_private on swap pages, since there ought to
be no further races with invalidate_inode_pages2() to deal with.
And since we cannot set PG_private we cannot use page->private (which is
already used by PG_swapcache pages anyway) to store the nfs_page. Thus
augment the new nfs_page_find_request logic.
Signed-off-by: Peter Zijlstra <redacted>
Cc: Trond Myklebust <redacted>
---
fs/nfs/inode.c | 6 ++++++
fs/nfs/write.c | 35 +++++++++++++++++++++++------------
2 files changed, 29 insertions(+), 12 deletions(-)
Index: linux-2.6-git/fs/nfs/inode.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:36:23
Add some packet-split receive hooks.
For one this allows to do NUMA node affine page allocs. Later on these hooks
will be extended to do emergency reserve allocations for fragments.
Signed-off-by: Peter Zijlstra <redacted>
---
drivers/net/e1000/e1000_main.c | 8 ++------
drivers/net/sky2.c | 16 ++++++----------
include/linux/skbuff.h | 23 +++++++++++++++++++++++
net/core/skbuff.c | 20 ++++++++++++++++++++
4 files changed, 51 insertions(+), 16 deletions(-)
Index: linux-2.6-git/drivers/net/e1000/e1000_main.c
===================================================================
@@ -4412,12 +4412,8 @@ e1000_clean_rx_irq_ps(struct e1000_adaptpci_unmap_page(pdev,ps_page_dma->ps_page_dma[j],PAGE_SIZE,PCI_DMA_FROMDEVICE);ps_page_dma->ps_page_dma[j]=0;-skb_fill_page_desc(skb,j,ps_page->ps_page[j],0,-length);+skb_add_rx_frag(skb,j,ps_page->ps_page[j],0,length);ps_page->ps_page[j]=NULL;-skb->len+=length;-skb->data_len+=length;-skb->truesize+=length;}/* strip the ethernet crc, problem is we're using pages now so
@@ -1972,8 +1972,8 @@ static struct sk_buff *receive_copy(stru}/* Adjust length of skb with fragments to match received data */-staticvoidskb_put_frags(structsk_buff*skb,unsignedinthdr_space,-unsignedintlength)+staticvoidskb_put_frags(structsky2_port*sky2,structsk_buff*skb,+unsignedinthdr_space,unsignedintlength){inti,num_frags;unsignedintsize;
@@ -1990,15 +1990,11 @@ static void skb_put_frags(struct sk_buffif(length==0){/* don't need this page */-__free_page(frag->page);+netdev_free_page(sky2->netdev,frag->page);--skb_shinfo(skb)->nr_frags;}else{size=min(length,(unsigned)PAGE_SIZE);--frag->size=size;-skb->data_len+=size;-skb->truesize+=size;-skb->len+=size;+skb_add_rx_frag(skb,i,frag->page,0,size);length-=size;}}
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:36:53
Hook up networking to the memory reserve.
There are two kinds of reserves: skb and aux.
- skb reserves are used for incomming packets,
- aux reserves are used for processing these packets.
The consumers for these reserves are sockets marked with:
SOCK_VMIO
Such sockets are to be used to service the VM (iow. to swap over). They
must be handled kernel side, exposing such a socket to user-space is a BUG.
Signed-off-by: Peter Zijlstra <redacted>
---
include/net/sock.h | 31 ++++++++++++
net/Kconfig | 3 +
net/core/sock.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 168 insertions(+)
Index: linux-2.6-git/include/net/sock.h
===================================================================
@@ -392,6 +392,7 @@ enum sock_flags {SOCK_RCVTSTAMP,/* %SO_TIMESTAMP setting */SOCK_LOCALROUTE,/* route locally only, %SO_DONTROUTE setting */SOCK_QUEUE_SHRUNK,/* write queue has been shrunk recently */+SOCK_VMIO,/* the VM depends on us - make sure we're serviced */};staticinlinevoidsock_copy_flags(structsock*nsk,structsock*osk)
@@ -196,6 +197,138 @@ __u32 sysctl_rmem_default __read_mostly /* Maximal space eaten by iovec or ancilliary data plus some space */intsysctl_optmem_max__read_mostly=sizeof(unsignedlong)*(2*UIO_MAXIOV+512);+staticatomic_trx_emergency_bytes;++staticintskb_reserve_bytes;+staticintaux_reserve_pages;++staticDEFINE_SPINLOCK(memalloc_lock);+staticintrx_net_reserve;+atomic_tvmio_socks;+EXPORT_SYMBOL_GPL(vmio_socks);++/*+*isthereroomforanotheremergencypacket?+*weaccountinpoweroftwounitstoapproxtheslaballocator.+*/+staticint__rx_emergency_get(intbytes,boolovercommit)+{+intsize=roundup_pow_of_two(bytes);+intnr=atomic_add_return(size,&rx_emergency_bytes);+intthresh=(3*skb_reserve_bytes)/2;+if(nr<thresh||overcommit)+return1;++atomic_dec(&rx_emergency_bytes);+return0;+}++intrx_emergency_get(intbytes)+{+return__rx_emergency_get(bytes,false);+}++intrx_emergency_get_overcommit(intbytes)+{+return__rx_emergency_get(bytes,true);+}++voidrx_emergency_put(intbytes)+{+intsize=roundup_pow_of_two(bytes);+returnatomic_sub(size,&rx_emergency_bytes);+}++/**+*sk_adjust_memalloc-adjusttheglobalmemallocreserveforcriticalRX+*@socks:numberofnew%SOCK_VMIOsockets+*@tx_resserve_pages:numberofpagesto(un)reserveforTX+*+*Thisfunctionadjuststhememallocreservebasedonsystemdemand.+*TheRXreserveisalimit,andonlyaddedonce,notforeachsocket.+*+*NOTE:+*@tx_reserve_pagesisanupper-boundofmemoryusedforTXhence+*weneednotaccountthepageslikewedoforRXpages.+*/+voidsk_adjust_memalloc(intsocks,inttx_reserve_pages)+{+unsignedlongflags;+intreserve=tx_reserve_pages;+intnr_socks;++spin_lock_irqsave(&memalloc_lock,flags);+nr_socks=atomic_add_return(socks,&vmio_socks);+BUG_ON(nr_socks<0);++if(nr_socks){+intskb_reserve_pages=skb_reserve_bytes/PAGE_SIZE;+intrx_pages=2*skb_reserve_pages+aux_reserve_pages;+reserve+=rx_pages-rx_net_reserve;+rx_net_reserve=rx_pages;+}else{+reserve-=rx_net_reserve;+rx_net_reserve=0;+}++if(reserve)+adjust_memalloc_reserve(reserve);+spin_unlock_irqrestore(&memalloc_lock,flags);+}+EXPORT_SYMBOL_GPL(sk_adjust_memalloc);++/*+*tinyhelperfunctionstotrackthememoryreserves+*neededbecauseofmodularipv6+*/+voidskb_reserve_memory(intbytes)+{+skb_reserve_bytes+=bytes;+sk_adjust_memalloc(0,0);+}+EXPORT_SYMBOL_GPL(skb_reserve_memory);++voidaux_reserve_memory(intpages)+{+aux_reserve_pages+=pages;+sk_adjust_memalloc(0,0);+}+EXPORT_SYMBOL_GPL(aux_reserve_memory);++/**+*sk_set_vmio-sets%SOCK_VMIO+*@sk:sockettosetiton+*+*Set%SOCK_VMIOonasocketandincreasethememallocreserve+*accordingly.+*/+intsk_set_vmio(structsock*sk)+{+intset=sock_flag(sk,SOCK_VMIO);+#ifndef CONFIG_NETVM+BUG();+#endif+if(!set){+sk_adjust_memalloc(1,0);+sock_set_flag(sk,SOCK_VMIO);+sk->sk_allocation|=__GFP_EMERGENCY;+}+return!set;+}+EXPORT_SYMBOL_GPL(sk_set_vmio);++intsk_clear_vmio(structsock*sk)+{+intset=sock_flag(sk,SOCK_VMIO);+if(set){+sk_adjust_memalloc(-1,0);+sock_reset_flag(sk,SOCK_VMIO);+sk->sk_allocation&=~__GFP_EMERGENCY;+}+returnset;+}+EXPORT_SYMBOL_GPL(sk_clear_vmio);+staticintsock_set_timeout(long*timeo_p,char__user*optval,intoptlen){structtimevaltv;
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:37:07
Provide an ops->swapfile() implementation for NFS. This will set the
NFS socket to SOCK_VMIO and run socket reconnect under PF_MEMALLOC as well
as reset SOCK_VMIO before engaging the protocol ->connect() method.
PF_MEMALLOC should allow the allocation of struct socket and related objects
and the early (re)setting of SOCK_VMIO should allow us to receive the packets
required for the TCP connection buildup.
(swapping continues over a server reset during heavy network traffic)
Signed-off-by: Peter Zijlstra <redacted>
Cc: Trond Myklebust <redacted>
---
fs/Kconfig | 14 ++++++++++++
fs/nfs/file.c | 6 +++++
include/linux/sunrpc/xprt.h | 5 +++-
net/sunrpc/sched.c | 13 +++++++----
net/sunrpc/xprtsock.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 81 insertions(+), 6 deletions(-)
Index: linux-2.6-git/fs/nfs/file.c
===================================================================
@@ -149,7 +149,9 @@ struct rpc_xprt {unsignedintmax_reqs;/* total slots */unsignedlongstate;/* transport state */unsignedcharshutdown:1,/* being shut down */-resvport:1;/* use a reserved port */+resvport:1,/* use a reserved port */+swapper:1;/* we're swapping over this+transport*//**Connectionoftransports
@@ -1215,11 +1215,15 @@ static void xs_udp_connect_worker(structcontainer_of(work,structsock_xprt,connect_worker.work);structrpc_xprt*xprt=&transport->xprt;structsocket*sock=transport->sock;+unsignedlongpflags=current->flags;interr,status=-EIO;if(xprt->shutdown||!xprt_bound(xprt))gotoout;+if(xprt->swapper)+current->flags|=PF_MEMALLOC;+/* Start by resetting any existing state */xs_close(xprt);
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:37:10
A new addres_space_operations method is added:
int swapfile(struct address_space *, int)
When during sys_swapon() this method is found and returns no error the
swapper_space.a_ops will proxy to sis->swap_file->f_mapping->a_ops.
The swapfile method will be used to communicate to the address_space that the
VM relies on it, and the address_space should take adequate measures (like
reserving memory for mempools or the like).
Signed-off-by: Peter Zijlstra <redacted>
CC: Trond Myklebust <redacted>
---
Documentation/filesystems/Locking | 9 ++++++++
include/linux/fs.h | 1
include/linux/swap.h | 3 ++
mm/Kconfig | 4 +++
mm/page_io.c | 42 ++++++++++++++++++++++++++++++++++++++
mm/swap_state.c | 4 +++
mm/swapfile.c | 22 +++++++++++++++++++
7 files changed, 84 insertions(+), 1 deletion(-)
Index: linux-2.6/include/linux/swap.h
===================================================================
@@ -163,6 +163,7 @@ enum {SWP_USED=(1<<0),/* is slot in swap_info[] used? */SWP_WRITEOK=(1<<1),/* ok to write to this swap? */SWP_ACTIVE=(SWP_USED|SWP_WRITEOK),+SWP_FILE=(1<<2),/* file swap area *//* add others here before... */SWP_SCANNING=(1<<8),/* refcount in scan_swap_map */};
@@ -172,6 +172,7 @@ prototypes: int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); int (*launder_page) (struct page *);+ int (*swapfile) (struct address_space *, int); locking rules: All except set_page_dirty may block
@@ -190,6 +191,7 @@ invalidatepage: no yes releasepage: no yes direct_IO: no launder_page: no yes+swapfile no ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop).
@@ -289,6 +291,13 @@ cleaned, or an error value if not. Note getting mapped back in and redirtied, it needs to be kept locked across the entire operation.+ ->swapfile() will be called with a non zero argument on address spaces+backing non block device backed swapfiles. A return value of zero indicates+success. In which case this address space can be used for backing swapspace.+The swapspace operations will be proxied to the address space operations.+Swapoff will call this method with a zero argument to release the address+space.+ Note: currently almost all instances of address_space methods are using BKL for internal serialization and that's one of the worst sources of contention. Normally they are calling library functions (in fs/buffer.c)
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:38:15
Introduce page allocation rank.
This allocation rank is an measure of the 'hardness' of the page allocation.
Where hardness refers to how deep we have to reach (and thereby if reclaim
was activated) to obtain the page.
It basically is a mapping from the ALLOC_/gfp flags into a scalar quantity,
which allows for comparisons of the kind:
'would this allocation have succeeded using these gfp flags'.
For the gfp -> alloc_flags mapping we use the 'hardest' possible, those
used by __alloc_pages() right before going into direct reclaim.
The alloc_flags -> rank mapping is given by: 2*2^wmark - harder - 2*high
where wmark = { min = 1, low, high } and harder, high are booleans.
This gives:
0 is the hardest possible allocation - ALLOC_NO_WATERMARK,
1 is ALLOC_WMARK_MIN|ALLOC_HARDER|ALLOC_HIGH,
...
15 is ALLOC_WMARK_HIGH|ALLOC_HARDER,
16 is the softest allocation - ALLOC_WMARK_HIGH.
Rank <= 4 will have woke up kswapd and when also > 0 might have ran into
direct reclaim.
Rank > 8 rarely happens and means lots of memory free (due to parallel oom kill).
The allocation rank is stored in page->index for successful allocations.
'offline' testing of the rank is made impossible by direct reclaim and
fragmentation issues. That is, it is impossible to tell if a given allocation
will succeed without actually doing it.
The purpose of this measure is to introduce some fairness into the slab
allocator.
Signed-off-by: Peter Zijlstra <redacted>
---
mm/internal.h | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mm/page_alloc.c | 58 ++++++++++--------------------------
2 files changed, 106 insertions(+), 41 deletions(-)
Index: linux-2.6-git/mm/internal.h
===================================================================
@@ -1259,48 +1252,27 @@ restart:*OK,we'rebelowthekswapdwatermarkandhavekickedbackground*reclaim.Nowthingsgetmorecomplex,sosetupalloc_flagsaccording*tohowwewanttoproceed.-*-*Thecallermaydipintopagereservesabitmoreifthecaller-*cannotrundirectreclaim,orifthecallerhasrealtimescheduling-*policyorisaskingfor__GFP_HIGHmemory.GFP_ATOMICrequestswill-*setbothALLOC_HARDER(!wait)andALLOC_HIGH(__GFP_HIGH).*/-alloc_flags=ALLOC_WMARK_MIN;-if((unlikely(rt_task(p))&&!in_interrupt())||!wait)-alloc_flags|=ALLOC_HARDER;-if(gfp_mask&__GFP_HIGH)-alloc_flags|=ALLOC_HIGH;-if(wait)-alloc_flags|=ALLOC_CPUSET;+alloc_flags=gfp_to_alloc_flags(gfp_mask);-/*-*Gothroughthezonelistagain.Let__GFP_HIGHandallocations-*comingfromrealtimetasksgodeeperintoreserves.-*-*Thisisthelastchance,ingeneral,beforethegotonopage.-*IgnorecpusetifGFP_ATOMIC(!wait)ratherthanfailalloc.-*Seealsocpuset_zone_allowed()commentinkernel/cpuset.c.-*/-page=get_page_from_freelist(gfp_mask,order,zonelist,alloc_flags);+/* This is the last chance, in general, before the goto nopage. */+page=get_page_from_freelist(gfp_mask,order,zonelist,+alloc_flags&~ALLOC_NO_WATERMARKS);if(page)gotogot_pg;/* This allocation should allow future memory freeing. */-rebalance:-if(((p->flags&PF_MEMALLOC)||unlikely(test_thread_flag(TIF_MEMDIE)))-&&!in_interrupt()){-if(!(gfp_mask&__GFP_NOMEMALLOC)){+if(alloc_flags&ALLOC_NO_WATERMARKS){nofail_alloc:-/* go through the zonelist yet again, ignoring mins */-page=get_page_from_freelist(gfp_mask,order,+/* go through the zonelist yet again, ignoring mins */+page=get_page_from_freelist(gfp_mask,order,zonelist,ALLOC_NO_WATERMARKS);-if(page)-gotogot_pg;-if(gfp_mask&__GFP_NOFAIL){-congestion_wait(WRITE,HZ/50);-gotonofail_alloc;-}+if(page)+gotogot_pg;+if(wait&&(gfp_mask&__GFP_NOFAIL)){+congestion_wait(WRITE,HZ/50);+gotonofail_alloc;}gotonopage;}
@@ -1309,6 +1281,10 @@ nofail_alloc:if(!wait)gotonopage;+/* Avoid recursion of direct reclaim */+if(p->flags&PF_MEMALLOC)+gotonopage;+cond_resched();/* We now go into synchronous reclaim */
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:38:21
Change the skb allocation api to indicate RX usage and use this to fall back to
the reserve when needed. Skbs allocated from the reserve are tagged in
skb->emergency.
Teach all other skb ops about emergency skbs and the reserve accounting.
Use the (new) packet split API to allocate and track fragment pages from the
emergency reserve. Do this using an atomic counter in page->index. This is
needed because the fragments have a different sharing semantic than that
indicated by skb_shinfo()->dataref.
(NOTE the extra atomic overhead is only for those pages allocated from the
reserves - it does not affect the normal fast path.)
Signed-off-by: Peter Zijlstra <redacted>
---
include/linux/skbuff.h | 22 ++++--
net/core/skbuff.c | 170 ++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 165 insertions(+), 27 deletions(-)
Index: linux-2.6-git/include/linux/skbuff.h
===================================================================
@@ -142,28 +142,36 @@ EXPORT_SYMBOL(skb_truesize_bug);*%GFP_ATOMIC.*/structsk_buff*__alloc_skb(unsignedintsize,gfp_tgfp_mask,-intfclone,intnode)+intflags,intnode){structkmem_cache*cache;structskb_shared_info*shinfo;structsk_buff*skb;u8*data;+intemergency=0;-cache=fclone?skbuff_fclone_cache:skbuff_head_cache;+size=SKB_DATA_ALIGN(size);+cache=(flags&SKB_ALLOC_FCLONE)+?skbuff_fclone_cache:skbuff_head_cache;+#ifdef CONFIG_NETVM+if(flags&SKB_ALLOC_RX)+gfp_mask|=__GFP_NOMEMALLOC|__GFP_NOWARN;+#endif+retry_alloc:/* Get the HEAD */skb=kmem_cache_alloc_node(cache,gfp_mask&~__GFP_DMA,node);if(!skb)-gotoout;+gotonoskb;/* Get the DATA. Size must match skb_add_mtu(). */-size=SKB_DATA_ALIGN(size);data=kmalloc_node_track_caller(size+sizeof(structskb_shared_info),gfp_mask,node);if(!data)gotonodata;memset(skb,0,offsetof(structsk_buff,truesize));+skb->emergency=emergency;skb->truesize=size+sizeof(structsk_buff);atomic_set(&skb->users,1);skb->head=data;
From: Peter Zijlstra <hidden> Date: 2007-02-21 15:39:04
Add reserves for INET.
The two big users seem to be the route cache and ip-fragment cache.
Account the route cache to the auxillary reserve.
Account the fragments to the skb reserve so that one can at least
overflow the fragment cache (avoids fragment deadlocks).
Signed-off-by: Peter Zijlstra <redacted>
---
net/ipv4/ip_fragment.c | 1 +
net/ipv4/route.c | 18 +++++++++++++++++-
net/ipv4/sysctl_net_ipv4.c | 13 ++++++++++++-
net/ipv6/reassembly.c | 1 +
net/ipv6/route.c | 18 +++++++++++++++++-
net/ipv6/sysctl_net_ipv6.c | 12 +++++++++++-
6 files changed, 59 insertions(+), 4 deletions(-)
Index: linux-2.6-git/net/ipv4/sysctl_net_ipv4.c
===================================================================
From: Pekka Enberg <hidden> Date: 2007-02-21 15:48:05
Hi Peter,
On 2/21/07, Peter Zijlstra [off-list ref] wrote:
Provide a method to calculate the number of pages needed to store a given
number of slab objects (upper bound when considering possible partial and
free slabs).
So how does this work? You ask the slab allocator how many pages you
need for a given number of objects and then those pages are available
to it via the page allocator? Can other users also dip into those
reserves?
I would prefer we simply have an API for telling the slab allocator to
keep certain number of pages in a reserve for a cache rather than
exposing internals such as object size to rest of the world.
Pekka
this wipes out all the flags in one go.... evil.
What if something just selected this process for OOM killing? you nuke
that flag here again. Would be nicer if only the PF_MEMALLOC bit got
inherited in the restore path..
this wipes out all the flags in one go.... evil.
What if something just selected this process for OOM killing? you nuke
that flag here again. Would be nicer if only the PF_MEMALLOC bit got
inherited in the restore path..
would something like this:
#define PF_PUSH(tsk, pflags, mask) \
do { \
(pflags) = ((tsk)->flags) & (mask); \
} while (0)
#define PF_POP(tsk, pflags, mask) \
do { \
((tsk)->flags &= ~(mask); \
((tsk)->flags |= (pflags); \
} while (0)
be useful, or shall I just open code it in various places?
(I made this same mistake; ignorant of the problem; all over this patch series)
From: Peter Zijlstra <hidden> Date: 2007-02-22 09:33:54
On Wed, 2007-02-21 at 17:47 +0200, Pekka Enberg wrote:
Hi Peter,
On 2/21/07, Peter Zijlstra [off-list ref] wrote:
quoted
Provide a method to calculate the number of pages needed to store a given
number of slab objects (upper bound when considering possible partial and
free slabs).
So how does this work? You ask the slab allocator how many pages you
need for a given number of objects and then those pages are available
to it via the page allocator? Can other users also dip into those
reserves?
Everybody (ab)using PF_MEMALLOC or the new __GFP_EMERGENCY.
I would prefer we simply have an API for telling the slab allocator to
keep certain number of pages in a reserve for a cache rather than
exposing internals such as object size to rest of the world.
Keeping the free pages in the page allocator is good for the buddy
system. Although you could probably implement a reserve interface
without actually claiming the pages.
However, doing it like so separates the making of the reserve from the
actual kmem_cache object, I can just carry a sum of pages around instead
of a list of kmem_cache pointers.
I calculate a potential reserve, I might never actually commit to making
(and using) the reserve.
Also, I don't see what internals are exposed, kmem_cache is still
private to slab.c.
From: Pekka Enberg <hidden> Date: 2007-02-22 09:45:58
Hi Peter,
On Wed, 2007-02-21 at 17:47 +0200, Pekka Enberg wrote:
quoted
So how does this work? You ask the slab allocator how many pages you
need for a given number of objects and then those pages are available
to it via the page allocator? Can other users also dip into those
reserves?
On 2/22/07, Peter Zijlstra [off-list ref] wrote:
Everybody (ab)using PF_MEMALLOC or the new __GFP_EMERGENCY.
So you are only interested in rough estimation of how much many pages
you need for a given amount of objects? Why not use ksize() for that
then?
Pekka
this wipes out all the flags in one go.... evil.
What if something just selected this process for OOM killing? you nuke
that flag here again. Would be nicer if only the PF_MEMALLOC bit got
inherited in the restore path..
would something like this:
#define PF_PUSH(tsk, pflags, mask) \
do { \
(pflags) = ((tsk)->flags) & (mask); \
} while (0)
#define PF_POP(tsk, pflags, mask) \
do { \
((tsk)->flags &= ~(mask); \
((tsk)->flags |= (pflags); \
} while (0)
be useful, or shall I just open code it in various places?
technically all you need is __get_bit and __set_bit() right?
(well a set_bit which sets to a value, not to always-1)
more generic name at least ;)
--
if you want to mail me at work (you don't), use arjan (at) linux.intel.com
Test the interaction between Linux and your BIOS via http://www.linuxfirmwarekit.org
If I'm not mistaken any skb on the receive side might get
allocated from the reserve. I don't see how the user could
avoid this except by not using queueing at all.
I also didn't see a patch dropping packets allocated from
the reserve that are forwarded or processed directly without
getting queued to a socket, so this would allow them to
bypass userspace queueing and still go through.
I think the user should just exclude packets necessary for
swapping from queueing manually, based on IP addresses,
port numbers or something like that.
If I'm not mistaken any skb on the receive side might get
allocated from the reserve. I don't see how the user could
avoid this except by not using queueing at all.
Well, the rules could be setup so that the storage path will never hit
the queue.
I also didn't see a patch dropping packets allocated from
the reserve that are forwarded or processed directly without
getting queued to a socket, so this would allow them to
bypass userspace queueing and still go through.
I think the user should just exclude packets necessary for
swapping from queueing manually, based on IP addresses,
port numbers or something like that.
Indeed, this patch will just warn the user that he did something very
wrong and should avoid this situation.
Perhaps skipping is not the proper action, but dropping them will most
certainly freeze the box. Either way seems unlucky. Might as well stick
BUG() in there :-(.
Any ideas on how to resolve this are most welcome, detecting the
situation on either rule insert or swapon and failing the respective
action would be most ideal, but I have no idea if that is feasible.
If I'm not mistaken any skb on the receive side might get
allocated from the reserve. I don't see how the user could
avoid this except by not using queueing at all.
Well, the rules could be setup so that the storage path will never hit
the queue.
Sure, but other packets might still get allocated from the
reserve and trigger this.
quoted
I think the user should just exclude packets necessary for
swapping from queueing manually, based on IP addresses,
port numbers or something like that.
Indeed, this patch will just warn the user that he did something very
wrong and should avoid this situation.
Perhaps skipping is not the proper action, but dropping them will most
certainly freeze the box. Either way seems unlucky. Might as well stick
BUG() in there :-(.
At this point we don't know whether the packet is destined for
a SOCK_VMIO socket or not. The only thing we know is that is
was allocated from the reserve, but it could be anything.
There is really nothing you can do at this point.
Any ideas on how to resolve this are most welcome, detecting the
situation on either rule insert or swapon and failing the respective
action would be most ideal, but I have no idea if that is feasible.
Unfortunately this is not possible either. I don't really see why
queueing is special though, dropping the packets in the ruleset
will break things just as well, as will routing them to a blackhole.
I guess the user just needs to be smart enough not to do this.
From: Peter Zijlstra <hidden> Date: 2007-02-24 16:25:06
On Sat, 2007-02-24 at 17:17 +0100, Patrick McHardy wrote:
I don't really see why
queueing is special though, dropping the packets in the ruleset
will break things just as well, as will routing them to a blackhole.
I guess the user just needs to be smart enough not to do this.
Its user-space and no emergency packet may rely on user-space because it
most likely is needed to maintain user-space.
From: Patrick McHardy <hidden> Date: 2007-02-24 16:40:44
Peter Zijlstra wrote:
On Sat, 2007-02-24 at 17:17 +0100, Patrick McHardy wrote:
quoted
I don't really see why
queueing is special though, dropping the packets in the ruleset
will break things just as well, as will routing them to a blackhole.
I guess the user just needs to be smart enough not to do this.
Its user-space and no emergency packet may rely on user-space because it
most likely is needed to maintain user-space.
I believe I might have misunderstood the intention of this patch.
Assuming the user is smart enough not to queue packets destined
to a SOCK_VMIO socket, are you worried about unrelated packets
allocated from the emergency reserve not getting freed fast
enough because they're sitting in a queue? In that case simply
dropping the packets would be fine I guess.
From: Peter Zijlstra <hidden> Date: 2007-02-24 16:56:00
On Sat, 2007-02-24 at 17:40 +0100, Patrick McHardy wrote:
Peter Zijlstra wrote:
quoted
On Sat, 2007-02-24 at 17:17 +0100, Patrick McHardy wrote:
quoted
I don't really see why
queueing is special though, dropping the packets in the ruleset
will break things just as well, as will routing them to a blackhole.
I guess the user just needs to be smart enough not to do this.
Its user-space and no emergency packet may rely on user-space because it
most likely is needed to maintain user-space.
I believe I might have misunderstood the intention of this patch.
Assuming the user is smart enough not to queue packets destined
to a SOCK_VMIO socket, are you worried about unrelated packets
allocated from the emergency reserve not getting freed fast
enough because they're sitting in a queue? In that case simply
dropping the packets would be fine I guess.
OK, that sounds good. I shall make NF_QUEUE a black hole for emergency
packets.
Alas, that leaves no way to warn a user about a SOCK_VMIO bound packet
treated this way, since, as you said, that is unknown at this point in
the chain.
Thanks,
Peter