Swap-over-NBD without deadlocking V11
Subsystems (21)
Mel Gorman
reviewercover Swap-over-NBD without deadlocking V11
Mostly addressing feedback from David Miller.
Changeloc since V10
o Rebase to 3.4-rc5
o Coding style fixups (davem)
o API consistency (davem)
o Rename sk_allocation to sk_gfp_atomic and use only when necessary (davem)
o Use static branches for sk_memalloc_socks (davem)
o Use static branch checks in fast paths (davem)
o Document concerns about PF_MEMALLOC leaking flags (davem)
o Locking fix in slab (mel)
Changelog since V9
o Rebase to 3.4-rc5
o Clarify comment on why PF_MEMALLOC is cleared in softirq handling (akpm)
o Only set page->pfmemalloc if ALLOC_NO_WATERMARKS was required (rientjes)
Changelog since V8
o Rebase to 3.4-rc2
o Use page flag instead of slab fields to keep structures the same size
o Properly detect allocations from softirq context that use PF_MEMALLOC
o Ensure kswapd does not sleep while processes are throttled
o Do not accidentally throttle !_GFP_FS processes indefinitely
Changelog since V7
o Rebase to 3.3-rc2
o Take greater care propagating page->pfmemalloc to skb
o Propagate pfmemalloc from netdev_alloc_page to skb where possible
o Release RCU lock properly on preempt kernel
Changelog since V6
o Rebase to 3.1-rc8
o Use wake_up instead of wake_up_interruptible()
o Do not throttle kernel threads
o Avoid a potential race between kswapd going to sleep and processes being throttled
Changelog since V5
o Rebase to 3.1-rc5
Changelog since V4
o Update comment clarifying what protocols can be used (Michal)
o Rebase to 3.0-rc3
Changelog since V3
o Propogate pfmemalloc from packet fragment pages to skb (Neil)
o Rebase to 3.0-rc2
Changelog since V2
o Document that __GFP_NOMEMALLOC overrides __GFP_MEMALLOC (Neil)
o Use wait_event_interruptible (Neil)
o Use !! when casting to bool to avoid any possibilitity of type
truncation (Neil)
o Nicer logic when using skb_pfmemalloc_protocol (Neil)
Changelog since V1
o Rebase on top of mmotm
o Use atomic_t for memalloc_socks (David Miller)
o Remove use of sk_memalloc_socks in vmscan (Neil Brown)
o Check throttle within prepare_to_wait (Neil Brown)
o Add statistics on throttling instead of printk
When a user or administrator requires swap for their application, they create a swap partition and file, format it with mkswap and activate it with swapon. Swap over the network is considered as an option in diskless systems. The two likely scenarios are when blade servers are used as part of a cluster where the form factor or maintenance costs do not allow the use of disks and thin clients.
The Linux Terminal Server Project recommends the use of the Network Block Device (NBD) for swap according to the manual at
https://sourceforge.net/projects/ltsp/files/Docs-Admin-Guide/LTSPManual.pdf/download
There is also documentation and tutorials on how to setup swap over NBD at places like https://help.ubuntu.com/community/UbuntuLTSP/EnableNBDSWAP
The nbd-client also documents the use of NBD as swap. Despite this, the fact is that a machine using NBD for swap can deadlock within minutes if swap is used intensively. This patch series addresses the problem.
The core issue is that network block devices do not use mempools like normal block devices do. As the host cannot control where they receive packets from, they cannot reliably work out in advance how much memory they might need. Some years ago, Peter Zijlstra developed a series of patches that supported swap over an NFS that at least one distribution is carrying within their kernels. This patch series borrows very heavily from Peter's work to support swapping over NBD as a pre-requisite to supporting swap-over-NFS. The bulk of the complexity is concerned with preserving memory that is allocated from the PFMEMALLOC reserves for use by the network layer which is needed for both NBD and NFS.
Patch 1 serialises access to min_free_kbytes. It's not strictly needed
by this series but as the series cares about watermarks in general, it's a harmless fix. It could be merged independently and may be if CMA is merged in advance.
Patch 2 adds knowledge of the PFMEMALLOC reserves to SLAB and SLUB to
preserve access to pages allocated under low memory situations to callers that are freeing memory.
Patch 3 introduces __GFP_MEMALLOC to allow access to the PFMEMALLOC
reserves without setting PFMEMALLOC.
Patch 4 opens the possibility for softirqs to use PFMEMALLOC reserves
for later use by network packet processing.
Patch 6 ignores memory policies when ALLOC_NO_WATERMARKS is set.
Patch 7 only sets page->pfmemalloc when ALLOC_NO_WATERMARKS was required
Patches 8-14 allows network processing to use PFMEMALLOC reserves when
the socket has been marked as being used by the VM to clean pages. If packets are received and stored in pages that were allocated under low-memory situations and are unrelated to the VM, the packets are dropped.
Patch 11 reintroduces __skb_alloc_page which the networking folk may object to but is needed in some cases to propogate pfmemalloc from a newly allocated page to an skb. If there is a strong objection, this patch can be dropped with the impact being that swap-over-network will be slower in some cases but it should not fail.
Patch 14 is a micro-optimisation to avoid a function call in the
common case.
Patch 15 tags NBD sockets as being SOCK_MEMALLOC so they can use
PFMEMALLOC if necessary.
Patch 16 notes that it is still possible for the PFMEMALLOC reserve
to be depleted. To prevent this, direct reclaimers get throttled on a waitqueue if 50% of the PFMEMALLOC reserves are depleted. It is expected that kswapd and the direct reclaimers already running will clean enough pages for the low watermark to be reached and the throttled processes are woken up.
Patch 17 adds a statistic to track how often processes get throttled
Some basic performance testing was run using kernel builds, netperf on loopback for UDP and TCP, hackbench (pipes and sockets), iozone and sysbench. Each of them were expected to use the sl*b allocators reasonably heavily but there did not appear to be significant performance variances.
For testing swap-over-NBD, a machine was booted with 2G of RAM with a swapfile backed by NBD. 8*NUM_CPU processes were started that create anonymous memory mappings and read them linearly in a loop. The total size of the mappings were 4*PHYSICAL_MEMORY to use swap heavily under memory pressure.
Without the patches and using SLUB, the machine locks up within minutes and runs to completion with them applied. With SLAB, the story is different as an unpatched kernel run to completion. However, the patched kernel completed the test 40% faster.
3.4.0-rc2 3.4.0-rc2
vanilla-slab swapnbd
Sys Time Running Test (seconds) 87.90 73.45
User+Sys Time Running Test (seconds) 91.93 76.91Total Elapsed Time (seconds) 4174.37 2953.96
drivers/block/nbd.c | 6 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2 +- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 3 +- drivers/net/usb/cdc-phonet.c | 2 +- drivers/usb/gadget/f_phonet.c | 2 +- include/linux/gfp.h | 13 +- include/linux/mm_types.h | 9 + include/linux/mmzone.h | 1 + include/linux/page-flags.h | 28 +++ include/linux/sched.h | 7 + include/linux/skbuff.h | 83 +++++++- include/linux/vm_event_item.h | 1 + include/net/sock.h | 19 ++ include/trace/events/gfpflags.h | 1 + kernel/softirq.c | 9 + mm/page_alloc.c | 69 +++++-- mm/slab.c | 216 +++++++++++++++++++-- mm/slub.c | 28 ++- mm/vmscan.c | 131 ++++++++++++- mm/vmstat.c | 1 + net/core/dev.c | 53 ++++- net/core/filter.c | 8 + net/core/skbuff.c | 94 +++++++-- net/core/sock.c | 42 ++++ net/ipv4/tcp_output.c | 9 +- net/ipv6/tcp_ipv6.c | 8 +- 29 files changed, 764 insertions(+), 87 deletions(-)
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 1/17 mm: Serialize access to min_free_kbytes
There is a race between the min_free_kbytes sysctl, memory hotplug and transparent hugepage support enablement. Memory hotplug uses a zonelists_mutex to avoid a race when building zonelists. Reuse it to serialise watermark updates.
--- mm/page_alloc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
mm/page_alloc.c +15 -8
@@ -4976,14 +4976,7 @@ static void setup_per_zone_lowmem_reserve(void)calculate_totalreserve_pages (); } -/** -* setup_per_zone_wmarks - called when min_free_kbytes changes -* or when memory is hot-{added|removed} -* -* Ensures that the watermark[min,low,high] values for each zone are set -* correctly with respect to min_free_kbytes. -*/ -void setup_per_zone_wmarks (void ) +static void __setup_per_zone_wmarks (void ) {unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT -10 );unsigned long lowmem_pages =0 ;
@@ -5038,6 +5031,20 @@ void setup_per_zone_wmarks(void)calculate_totalreserve_pages (); } +/** +* setup_per_zone_wmarks - called when min_free_kbytes changes +* or when memory is hot-{added|removed} +* +* Ensures that the watermark[min,low,high] values for each zone are set +* correctly with respect to min_free_kbytes. +*/ +void setup_per_zone_wmarks (void ) +{ +mutex_lock (&zonelists_mutex); +__setup_per_zone_wmarks (); +mutex_unlock (&zonelists_mutex); +} +/* * The inactive anon list should be small enough that the VM never has to * do too much work, but large enough that each inactive page has a chance
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 2/17 mm: sl[au]b: Add knowledge of PFMEMALLOC reserve pages
In reply to Mel GormanAllocations of pages below the min watermark run a risk of the machine hanging due to a lack of memory. To prevent this, only callers who have PF_MEMALLOC or TIF_MEMDIE set and are not processing an interrupt are allowed to allocate with ALLOC_NO_WATERMARKS. Once they are allocated to a slab though, nothing prevents other callers consuming free objects within those slabs. This patch limits access to slab pages that were alloced from the PFMEMALLOC reserves.
When this patch is applied, pages allocated from below the low watermark are returned with page->pfmemalloc set and it is up to the caller to determine how the page should be protected. SLAB restricts access to any page with page->pfmemalloc set to callers which are known to able to access the PFMEMALLOC reserve. If one is not available, an attempt is made to allocate a new page rather than use a reserve. SLUB is a bit more relaxed in that it only records if the current per-CPU page was allocated from PFMEMALLOC reserve and uses another partial slab if the caller does not have the necessary GFP or process flags. This was found to be sufficient in tests to avoid hangs due to SLUB generally maintaining smaller lists than SLAB.
In low-memory conditions it does mean that !PFMEMALLOC allocators can fail a slab allocation even though free objects are available because they are being preserved for callers that are freeing pages.
--- include/linux/mm_types.h | 9 +++ include/linux/page-flags.h | 28 +++++++ mm/internal.h | 3 + mm/page_alloc.c | 27 +++++-- mm/slab.c | 192 +++++++++++++++++++++++++++++++++++++++----- mm/slub.c | 27 ++++++- 6 files changed, 261 insertions(+), 25 deletions(-)
include/linux/mm_types.h +9 -0
@@ -53,6 +53,15 @@ struct page {union {pgoff_t index;/* Our offset within mapping. */ void *freelist;/* slub first free object */ +bool pfmemalloc;/* If set by the page allocator, +* ALLOC_PFMEMALLOC was set +* and the low watermark was not +* met implying that the system +* is under some pressure. The +* caller should try ensure +* this page is only used to +* free other pages. +*/ };union {
include/linux/page-flags.h +28 -0
@@ -453,6 +453,34 @@ static inline int PageTransTail(struct page *page) }#endif +/* +* If network-based swap is enabled, sl*b must keep track of whether pages +* were allocated from pfmemalloc reserves. +*/ +static inline int PageSlabPfmemalloc (struct page *page) +{ +VM_BUG_ON (!PageSlab (page)); +return PageActive (page); +} + +static inline void SetPageSlabPfmemalloc (struct page *page) +{ +VM_BUG_ON (!PageSlab (page)); +SetPageActive (page); +} + +static inline void __ClearPageSlabPfmemalloc (struct page *page) +{ +VM_BUG_ON (!PageSlab (page)); +__ClearPageActive (page); +} + +static inline void ClearPageSlabPfmemalloc (struct page *page) +{ +VM_BUG_ON (!PageSlab (page)); +ClearPageActive (page); +} +#ifdef CONFIG_MMU #define __PG_MLOCKED (1 << PG_mlocked)#else
mm/internal.h +3 -0
@@ -239,6 +239,9 @@ static inline struct page *mem_map_next(struct page *iter,#define __paginginit __init#endif +/* Returns true if the gfp_mask allows use of ALLOC_NO_WATERMARK */ +bool gfp_pfmemalloc_allowed (gfp_t gfp_mask); +/* Memory initialisation debug and verification */ enum mminit_level {MMINIT_WARNING ,
mm/page_alloc.c +22 -5
@@ -1463,6 +1463,7 @@ failed:#define ALLOC_HARDER 0x10/* try to alloc harder */ #define ALLOC_HIGH 0x20/* __GFP_HIGH set */ #define ALLOC_CPUSET 0x40/* check for correct cpuset */ +#define ALLOC_PFMEMALLOC 0x80/* Caller has PF_MEMALLOC set */ #ifdef CONFIG_FAIL_PAGE_ALLOC
@@ -2208,16 +2209,22 @@ gfp_to_alloc_flags(gfp_t gfp_mask) }else if (unlikely (rt_task (current)) && !in_interrupt ()) alloc_flags |=ALLOC_HARDER ; -if (likely (!(gfp_mask & __GFP_NOMEMALLOC))) { -if (!in_interrupt () && - ((current->flags &PF_MEMALLOC ) || -unlikely (test_thread_flag (TIF_MEMDIE )))) +if ((current->flags &PF_MEMALLOC ) || +unlikely (test_thread_flag (TIF_MEMDIE ))) { + alloc_flags |=ALLOC_PFMEMALLOC ; + +if (likely (!(gfp_mask & __GFP_NOMEMALLOC)) && !in_interrupt ()) alloc_flags |=ALLOC_NO_WATERMARKS ; }return alloc_flags; } +bool gfp_pfmemalloc_allowed (gfp_t gfp_mask) +{ +return !!(gfp_to_alloc_flags (gfp_mask) &ALLOC_PFMEMALLOC ); +} +static inline struct page * __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist, enum zone_type high_zoneidx,
@@ -2405,10 +2412,18 @@ nopage:warn_alloc_failed (gfp_mask, order,NULL );return page; got_pg: +/* +* page->pfmemalloc is set when the caller had PFMEMALLOC set or is +* been OOM killed. The expectation is that the caller is taking +* steps that will free more memory. The caller should avoid the +* page being used for !PFMEMALLOC purposes. +*/ + page->pfmemalloc = !!(alloc_flags &ALLOC_PFMEMALLOC ); +if (kmemcheck_enabled)kmemcheck_pagealloc_alloc (page, order, gfp_mask); -return page; +return page; }/*
@@ -2459,6 +2474,8 @@ retry_cpuset: page =__alloc_pages_slowpath (gfp_mask, order, zonelist, high_zoneidx, nodemask, preferred_zone, migratetype); + else + page->pfmemalloc = false;trace_mm_page_alloc (page, order, gfp_mask, migratetype);
mm/slab.c +174 -18
310 lines not on this page · raw message
mm/slub.c +25 -2
@@ -33,6 +33,8 @@#include <trace/events/kmem.h> +#include "internal.h" +/* * Lock order: * 1. slub_lock (Global Semaphore)
@@ -1370,6 +1372,8 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)inc_slabs_node (s,page_to_nid (page), page->objects); page->slab = s; page->flags |=1 << PG_slab; +if (page->pfmemalloc) +SetPageSlabPfmemalloc (page); start =page_address (page);
@@ -1414,6 +1418,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page) -pages);__ClearPageSlab (page); +__ClearPageSlabPfmemalloc (page);reset_page_mapcount (page);if (current->reclaim_state) current->reclaim_state->reclaimed_slab += pages;
@@ -2153,6 +2158,14 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,return object; } +static inline bool pfmemalloc_match (struct kmem_cache_cpu *c,gfp_t gfpflags) +{ +if (unlikely (PageSlabPfmemalloc (c->page))) +return gfp_pfmemalloc_allowed (gfpflags); + +return true; +} +/* * Check the page->freelist of a page and either transfer the freelist to the per cpu freelist * or deactivate the page.
@@ -2225,6 +2238,16 @@ redo: goto new_slab; } +/* +* By rights, we should be searching for a slab page that was +* PFMEMALLOC but right now, we are losing the pfmemalloc +* information when the page leaves the per-cpu allocator +*/ +if (unlikely (!pfmemalloc_match (c, gfpflags))) { +deactivate_slab (s, c); + goto new_slab; + } +/* must check again c->freelist in case of cpu migration or IRQ */ object = c->freelist;if (object)
@@ -2329,8 +2352,8 @@ redo:barrier (); object = c->freelist; -if (unlikely (!object || !node_match (c, node))) - +if (unlikely (!object || !node_match (c, node) || + !pfmemalloc_match (c, gfpflags))) object =__slab_alloc (s, gfpflags, node, addr, c);else {
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 mm: sl[au]b: first remove PFMEMALLOC flag then SLAB flag
From: Sebastian Andrzej Siewior <[email protected]>
If we first remove the SLAB flag followed by the PFMEMALLOC flag then the removal of the latter will trigger the VM_BUG_ON() as it can be seen in
| kernel BUG at include/linux/page-flags.h:474! | invalid opcode: 0000 [#1] PREEMPT SMP | Call Trace: | [<c10e2d77>] slab_destroy+0x27/0x70 | [<c10e3285>] drain_freelist+0x55/0x90 | [<c10e344e>] __cache_shrink+0x6e/0x90 | [<c14e3211>] ? acpi_sleep_init+0xcf/0xcf | [<c10e349d>] kmem_cache_shrink+0x2d/0x40
because the SLAB flag is gone. This patch simply changes the order.
--- mm/slab.c | 2 +- mm/slub.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
mm/slab.c +1 -1
@@ -2007,8 +2007,8 @@ static void kmem_freepages(struct kmem_cache *cachep, void *addr) NR_SLAB_UNRECLAIMABLE, nr_freed);while (i--) {BUG_ON (!PageSlab (page)); -__ClearPageSlab (page);__ClearPageSlabPfmemalloc (page); +__ClearPageSlab (page); page++; }if (current->reclaim_state)
mm/slub.c +1 -1
@@ -1417,8 +1417,8 @@ static void __free_slab(struct kmem_cache *s, struct page *page) NR_SLAB_RECLAIMABLE :NR_SLAB_UNRECLAIMABLE , -pages); -__ClearPageSlab (page);__ClearPageSlabPfmemalloc (page); +__ClearPageSlab (page);reset_page_mapcount (page);if (current->reclaim_state) current->reclaim_state->reclaimed_slab += pages;
Signature · 7 lines
1.7.10 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 02.5] mm: sl[au]b: first remove PFMEMALLOC flag then SLAB flag
Quoted 13 lines · Sebastian Andrzej Siewior
From: Sebastian Andrzej Siewior <[email protected]>
If we first remove the SLAB flag followed by the PFMEMALLOC flag then the removal of the latter will trigger the
VM_BUG_ON()as it can be seen in| kernel BUG at include/linux/page-flags.h:474! | invalid opcode: 0000 [#1] PREEMPT SMP | Call Trace: | [<c10e2d77>] slab_destroy+0x27/0x70 | [<c10e3285>] drain_freelist+0x55/0x90 | [<c10e344e>] __cache_shrink+0x6e/0x90 | [<c14e3211>] ? acpi_sleep_init+0xcf/0xcf | [<c10e349d>] kmem_cache_shrink+0x2d/0x40
Quoted 2 lines
because the SLAB flag is gone. This patch simply changes the order.
It would be nicer if we add some comments in the code. ;)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerRe: [PATCH 02.5] mm: sl[au]b: first remove PFMEMALLOC flag then SLAB flag
In reply to Sebastian Andrzej SiewiorQuoted 13 lines · Sebastian Andrzej Siewior
From: Sebastian Andrzej Siewior <[email protected]>
If we first remove the SLAB flag followed by the PFMEMALLOC flag then the removal of the latter will trigger the
VM_BUG_ON()as it can be seen in| kernel BUG at include/linux/page-flags.h:474! | invalid opcode: 0000 [#1] PREEMPT SMP | Call Trace: | [<c10e2d77>] slab_destroy+0x27/0x70 | [<c10e3285>] drain_freelist+0x55/0x90 | [<c10e344e>] __cache_shrink+0x6e/0x90 | [<c14e3211>] ? acpi_sleep_init+0xcf/0xcf | [<c10e349d>] kmem_cache_shrink+0x2d/0x40
Quoted 3 lines
because the SLAB flag is gone. This patch simply changes the order.
Signed-off-by Sebastian Andrzej Siewior <[email protected]>
Grr, yes of course. Thanks very much. I've folded this into patch 2 and preserved credit.
Signature · 8 lines
Mel Gorman SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 3/17 mm: slub: Optimise the SLUB fast path to avoid pfmemalloc checks
In reply to Mel GormanFrom: Christoph Lameter <[email protected]>
This patch removes the check for pfmemalloc from the alloc hotpath and puts the logic after the election of a new per cpu slab. For a pfmemalloc page we do not use the fast path but force the use of the slow path which is also used for the debug case.
This has the side-effect of weakening pfmemalloc processing in the following way;
1. A process that is allocating for network swap calls __slab_alloc. pfmemalloc_match is true so the freelist is loaded and c->freelist is now pointing to a pfmemalloc page.
2. A process that is attempting normal allocations calls slab_alloc, finds the pfmemalloc page on the freelist and uses it because it did not check pfmemalloc_match()
The patch allows non-pfmemalloc allocations to use pfmemalloc pages with the kmalloc slabs being the most vunerable caches on the grounds they are most likely to have a mix of pfmemalloc and !pfmemalloc requests. A later patch will still protect the system as processes will get throttled if the pfmemalloc reserves get depleted but performance will not degrade as smoothly.
--- mm/slub.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
mm/slub.c +3 -4
@@ -2298,11 +2298,11 @@ new_slab: } } -if (likely (!kmem_cache_debug (s))) +if (likely (!kmem_cache_debug (s) &&pfmemalloc_match (c, gfpflags))) goto load_freelist;/* Only entered in the debug case */ -if (!alloc_debug_processing (s, c->page, object, addr)) +if (kmem_cache_debug (s) && !alloc_debug_processing (s, c->page, object, addr)) goto new_slab;/* Slab failed checks. Next slab needed */ c->freelist =get_freepointer (s, object);
@@ -2352,8 +2352,7 @@ redo:barrier (); object = c->freelist; -if (unlikely (!object || !node_match (c, node) || - !pfmemalloc_match (c, gfpflags))) +if (unlikely (!object || !node_match (c, node))) object =__slab_alloc (s, gfpflags, node, addr, c);else {
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 4/17 mm: Introduce __GFP_MEMALLOC to allow access to emergency reserves
In reply to Mel Gorman__GFP_MEMALLOC will allow the allocation to disregard the watermarks, much like PF_MEMALLOC. It allows one to pass along the memalloc state in object related allocation flags as opposed to task related flags, such as sk->sk_allocation. This removes the need for ALLOC_PFMEMALLOC as callers using __GFP_MEMALLOC can get the ALLOC_NO_WATERMARK flag which is now enough to identify allocations related to page reclaim.
--- include/linux/gfp.h | 10 ++++++++-- include/linux/mm_types.h | 2 +- include/trace/events/gfpflags.h | 1 + mm/page_alloc.c | 22 ++++++++++------------ mm/slab.c | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-)
include/linux/gfp.h +8 -2
@@ -23,6 +23,7 @@ struct vm_area_struct;#define ___GFP_REPEAT 0x400u#define ___GFP_NOFAIL 0x800u#define ___GFP_NORETRY 0x1000u +#define ___GFP_MEMALLOC 0x2000u#define ___GFP_COMP 0x4000u#define ___GFP_ZERO 0x8000u#define ___GFP_NOMEMALLOC 0x10000u
@@ -76,9 +77,14 @@ struct vm_area_struct;#define __GFP_REPEAT ((__force gfp_t)___GFP_REPEAT)/* See above */ #define __GFP_NOFAIL ((__force gfp_t)___GFP_NOFAIL)/* See above */ #define __GFP_NORETRY ((__force gfp_t)___GFP_NORETRY)/* See above */ +#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC)/* Allow access to emergency reserves */ #define __GFP_COMP ((__force gfp_t)___GFP_COMP)/* Add compound page metadata */ #define __GFP_ZERO ((__force gfp_t)___GFP_ZERO)/* Return zeroed page on success */ -#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)/* Don't use emergency reserves */ +#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)/* Don't use emergency reserves. +* This takes precedence over the +* __GFP_MEMALLOC flag if both are +* set +*/ #define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)/* Enforce hardwall cpuset memory allocs */ #define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */ #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)/* Page is reclaimable */
@@ -129,7 +135,7 @@ struct vm_area_struct;/* Control page allocator reclaim behavior */ #define GFP_RECLAIM_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS|\ __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\ - __GFP_NORETRY|__GFP_NOMEMALLOC) + __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC)/* Control slab gfp mask during early boot */ #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_WAIT|__GFP_IO|__GFP_FS))
include/linux/mm_types.h +1 -1
@@ -54,7 +54,7 @@ struct page {pgoff_t index;/* Our offset within mapping. */ void *freelist;/* slub first free object */ bool pfmemalloc;/* If set by the page allocator, -* ALLOC_PFMEMALLOC was set +* ALLOC_NO_WATERMARKS was set * and the low watermark was not * met implying that the system * is under some pressure. The
include/trace/events/gfpflags.h +1 -0
@@ -30,6 +30,7 @@ {(unsigned long)__GFP_COMP, "GFP_COMP"}, \ {(unsigned long)__GFP_ZERO, "GFP_ZERO"}, \ {(unsigned long)__GFP_NOMEMALLOC, "GFP_NOMEMALLOC"}, \ + {(unsigned long)__GFP_MEMALLOC, "GFP_MEMALLOC"}, \ {(unsigned long)__GFP_HARDWALL, "GFP_HARDWALL"}, \ {(unsigned long)__GFP_THISNODE, "GFP_THISNODE"}, \ {(unsigned long)__GFP_RECLAIMABLE, "GFP_RECLAIMABLE"}, \
mm/page_alloc.c +10 -12
@@ -1463,7 +1463,6 @@ failed:#define ALLOC_HARDER 0x10/* try to alloc harder */ #define ALLOC_HIGH 0x20/* __GFP_HIGH set */ #define ALLOC_CPUSET 0x40/* check for correct cpuset */ -#define ALLOC_PFMEMALLOC 0x80/* Caller has PF_MEMALLOC set */ #ifdef CONFIG_FAIL_PAGE_ALLOC
@@ -2209,11 +2208,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask) }else if (unlikely (rt_task (current)) && !in_interrupt ()) alloc_flags |=ALLOC_HARDER ; -if ((current->flags &PF_MEMALLOC ) || -unlikely (test_thread_flag (TIF_MEMDIE ))) { - alloc_flags |=ALLOC_PFMEMALLOC ; - -if (likely (!(gfp_mask & __GFP_NOMEMALLOC)) && !in_interrupt ()) +if (likely (!(gfp_mask & __GFP_NOMEMALLOC))) { +if (gfp_mask & __GFP_MEMALLOC) + alloc_flags |=ALLOC_NO_WATERMARKS ; +else if (likely (!(gfp_mask & __GFP_NOMEMALLOC)) && !in_interrupt ()) alloc_flags |=ALLOC_NO_WATERMARKS ; }
@@ -2222,7 +2220,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)bool gfp_pfmemalloc_allowed (gfp_t gfp_mask) { -return !!(gfp_to_alloc_flags (gfp_mask) &ALLOC_PFMEMALLOC ); +return !!(gfp_to_alloc_flags (gfp_mask) &ALLOC_NO_WATERMARKS ); } static inline struct page *
@@ -2413,12 +2411,12 @@ nopage:return page; got_pg:/* -* page->pfmemalloc is set when the caller had PFMEMALLOC set or is -* been OOM killed. The expectation is that the caller is taking -* steps that will free more memory. The caller should avoid the -* page being used for !PFMEMALLOC purposes. +* page->pfmemalloc is set when the caller had PFMEMALLOC set, is +* been OOM killed or specified __GFP_MEMALLOC. The expectation is +* that the caller is taking steps that will free more memory. The +* caller should avoid the page being used for !PFMEMALLOC purposes. */ - page->pfmemalloc = !!(alloc_flags &ALLOC_PFMEMALLOC ); + page->pfmemalloc = !!(alloc_flags &ALLOC_NO_WATERMARKS );if (kmemcheck_enabled)kmemcheck_pagealloc_alloc (page, order, gfp_mask);
mm/slab.c +1 -1
@@ -1934,7 +1934,7 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)return NULL ; } -/* Record if ALLOC_PFMEMALLOC was set when allocating the slab */ +/* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */ if (unlikely (page->pfmemalloc)) pfmemalloc_active = true;
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 5/17 mm: allow PF_MEMALLOC from softirq context
In reply to Mel GormanThis is needed to allow network softirq packet processing to make use of PF_MEMALLOC.
Currently softirq context cannot use PF_MEMALLOC due to it not being associated with a task, and therefore not having task flags to fiddle with - thus the gfp to alloc flag mapping ignores the task flags when in interrupts (hard or soft) context.
Allowing softirqs to make use of PF_MEMALLOC therefore requires some trickery. This patch borrows the task flags from whatever process happens to be preempted by the softirq. It then modifies the gfp to alloc flags mapping to not exclude task flags in softirq context, and modify the softirq code to save, clear and restore the PF_MEMALLOC flag.
The save and clear, ensures the preempted task's PF_MEMALLOC flag doesn't leak into the softirq. The restore ensures a softirq's PF_MEMALLOC flag cannot leak back into the preempted process. This should be safe due to the following reasons
Softirqs can run on multiple CPUs sure but the same task should not be
executing the same softirq code. Neither should the softirq handler be preempted by any other softirq handler so the flags should not leak to an unrelated softirq.
Softirqs re-enable hardware interrupts in __do_softirq() so can be
preempted by hardware interrupts so PF_MEMALLOC is inherited by the hard IRQ. However, this is similar to a process in reclaim being preempted by a hardirq. While PF_MEMALLOC is set, gfp_to_alloc_flags() distinguishes between hard and soft irqs and avoids giving a hardirq the ALLOC_NO_WATERMARKS flag.
If the softirq is deferred to ksoftirq then its flags may be used
instead of a normal tasks but as the softirq cannot be preempted, the PF_MEMALLOC flag does not leak to other code by accident.
--- include/linux/sched.h | 7 +++++++ kernel/softirq.c | 9 +++++++++ mm/page_alloc.c | 6 +++++- 3 files changed, 21 insertions(+), 1 deletion(-)
include/linux/sched.h +7 -0
@@ -1913,6 +1913,13 @@ static inline void rcu_copy_process(struct task_struct *p)#endif +static inline void tsk_restore_flags (struct task_struct *task, +unsigned long orig_flags,unsigned long flags) +{ + task->flags &= ~flags; + task->flags |= orig_flags & flags; +} +#ifdef CONFIG_SMP extern void do_set_cpus_allowed (struct task_struct *p,const struct cpumask *new_mask);
kernel/softirq.c +9 -0
@@ -210,6 +210,14 @@ asmlinkage void __do_softirq(void)__u32 pending;int max_restart =MAX_SOFTIRQ_RESTART ;int cpu; +unsigned long old_flags = current->flags; + +/* +* Mask out PF_MEMALLOC s current task context is borrowed for the +* softirq. A softirq handled such as network RX might set PF_MEMALLOC +* again if the socket is related to swap +*/ + current->flags &= ~PF_MEMALLOC ; pending =local_softirq_pending ();account_system_vtime (current);
@@ -265,6 +273,7 @@ restart:account_system_vtime (current);__local_bh_enable (SOFTIRQ_OFFSET ); +tsk_restore_flags (current, old_flags,PF_MEMALLOC ); }#ifndef __ARCH_HAS_DO_SOFTIRQ
mm/page_alloc.c +5 -1
@@ -2211,7 +2211,11 @@ gfp_to_alloc_flags(gfp_t gfp_mask)if (likely (!(gfp_mask & __GFP_NOMEMALLOC))) {if (gfp_mask & __GFP_MEMALLOC) alloc_flags |=ALLOC_NO_WATERMARKS ; -else if (likely (!(gfp_mask & __GFP_NOMEMALLOC)) && !in_interrupt ()) +else if (in_serving_softirq () && (current->flags &PF_MEMALLOC )) + alloc_flags |=ALLOC_NO_WATERMARKS ; +else if (!in_interrupt () && + ((current->flags &PF_MEMALLOC ) || +unlikely (test_thread_flag (TIF_MEMDIE )))) alloc_flags |=ALLOC_NO_WATERMARKS ; }
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 6/17 mm: Only set page->pfmemalloc when ALLOC_NO_WATERMARKS was used
In reply to Mel Gorman__alloc_pages_slowpath() is called when the number of free pages is below the low watermark. If the caller is entitled to use ALLOC_NO_WATERMARKS then the page will be marked page->pfmemalloc. This protects more pages than are strictly necessary as we only need to protect pages allocated below the min watermark (the pfmemalloc reserves).
This patch only sets page->pfmemalloc when ALLOC_NO_WATERMARKS was required to allocate the page.
--- mm/page_alloc.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
mm/page_alloc.c +14 -13
@@ -2043,8 +2043,8 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, page =get_page_from_freelist (gfp_mask, nodemask, order, zonelist, high_zoneidx, - alloc_flags, preferred_zone, - migratetype); + alloc_flags & ~ALLOC_NO_WATERMARKS , + preferred_zone, migratetype);if (page) { preferred_zone->compact_considered =0 ; preferred_zone->compact_defer_shift =0 ;
@@ -2124,8 +2124,8 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, retry: page =get_page_from_freelist (gfp_mask, nodemask, order, zonelist, high_zoneidx, - alloc_flags, preferred_zone, - migratetype); + alloc_flags & ~ALLOC_NO_WATERMARKS , + preferred_zone, migratetype);/* * If an allocation failed after direct reclaim, it could be because
@@ -2296,8 +2296,17 @@ rebalance: page =__alloc_pages_high_priority (gfp_mask, order, zonelist, high_zoneidx, nodemask, preferred_zone, migratetype); -if (page) +if (page) { +/* +* page->pfmemalloc is set when ALLOC_NO_WATERMARKS was +* necessary to allocate the page. The expectation is +* that the caller is taking steps that will free more +* memory. The caller should avoid the page being used +* for !PFMEMALLOC purposes. +*/ + page->pfmemalloc = true; goto got_pg; + } }/* Atomic allocations - we can't balance anything */
@@ -2414,14 +2423,6 @@ nopage:warn_alloc_failed (gfp_mask, order,NULL );return page; got_pg: -/* -* page->pfmemalloc is set when the caller had PFMEMALLOC set, is -* been OOM killed or specified __GFP_MEMALLOC. The expectation is -* that the caller is taking steps that will free more memory. The -* caller should avoid the page being used for !PFMEMALLOC purposes. -*/ - page->pfmemalloc = !!(alloc_flags &ALLOC_NO_WATERMARKS ); -if (kmemcheck_enabled)kmemcheck_pagealloc_alloc (page, order, gfp_mask);
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 7/17 mm: Ignore mempolicies when using ALLOC_NO_WATERMARK
In reply to Mel GormanThe reserve is proportionally distributed over all !highmem zones in the system. So we need to allow an emergency allocation access to all zones. In order to do that we need to break out of any mempolicy boundaries we might have.
In my opinion that does not break mempolicies as those are user oriented and not system oriented. That is, system allocations are not guaranteed to be within mempolicy boundaries. For instance IRQs do not even have a mempolicy.
So breaking out of mempolicy boundaries for 'rare' emergency allocations, which are always system allocations (as opposed to user) is ok.
--- mm/page_alloc.c | 7 +++++++ 1 file changed, 7 insertions(+)
mm/page_alloc.c +7 -0
@@ -2293,6 +2293,13 @@ rebalance:/* Allocate without watermarks if the context allows */ if (alloc_flags &ALLOC_NO_WATERMARKS ) { +/* +* Ignore mempolicies if ALLOC_NO_WATERMARKS on the grounds +* the allocation is high priority and these type of +* allocations are system rather than user orientated +*/ + zonelist =node_zonelist (numa_node_id (), gfp_mask); + page =__alloc_pages_high_priority (gfp_mask, order, zonelist, high_zoneidx, nodemask, preferred_zone, migratetype);
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 8/17 net: Introduce sk_gfp_atomic() to allow addition of GFP flags depending on the individual socket
In reply to Mel GormanIntroduce sk_gfp_atomic(), this function allows to inject sock specific flags to each sock related allocation. It is only used on allocation paths that may be required for writing pages back to network storage.
--- include/net/sock.h | 5 +++++ net/ipv4/tcp_output.c | 9 +++++---- net/ipv6/tcp_ipv6.c | 8 +++++--- 3 files changed, 15 insertions(+), 7 deletions(-)
include/net/sock.h +5 -0
@@ -644,6 +644,11 @@ static inline int sock_flag(struct sock *sk, enum sock_flags flag)return test_bit (flag, &sk->sk_flags); } +static inline gfp_t sk_gfp_atomic (struct sock *sk,gfp_t gfp_mask) +{ +return GFP_ATOMIC ; +} +static inline void sk_acceptq_removed (struct sock *sk) { sk->sk_ack_backlog--;
net/ipv4/tcp_output.c +5 -4
@@ -2445,7 +2445,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,if (cvp !=NULL && cvp->s_data_constant && cvp->s_data_desired) s_data_desired = cvp->s_data_desired; - skb =sock_wmalloc (sk,MAX_TCP_HEADER +15 + s_data_desired,1 ,GFP_ATOMIC ); + skb =sock_wmalloc (sk,MAX_TCP_HEADER +15 + s_data_desired,1 , +sk_gfp_atomic (sk,GFP_ATOMIC ));if (skb ==NULL )return NULL ;
@@ -2741,7 +2742,7 @@ void tcp_send_ack(struct sock *sk)* tcp_transmit_skb() will set the ownership to this * sock. */ - buff =alloc_skb (MAX_TCP_HEADER ,GFP_ATOMIC ); + buff =alloc_skb (MAX_TCP_HEADER ,sk_gfp_atomic (sk,GFP_ATOMIC ));if (buff ==NULL ) {inet_csk_schedule_ack (sk);inet_csk (sk)->icsk_ack.ato =TCP_ATO_MIN ;
@@ -2756,7 +2757,7 @@ void tcp_send_ack(struct sock *sk)/* Send it off, this clears delayed acks for us. */ TCP_SKB_CB (buff)->when = tcp_time_stamp; -tcp_transmit_skb (sk, buff,0 ,GFP_ATOMIC ); +tcp_transmit_skb (sk, buff,0 ,sk_gfp_atomic (sk,GFP_ATOMIC )); }/* This routine sends a packet with an out of date sequence
@@ -2776,7 +2777,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)struct sk_buff *skb;/* We don't queue it, tcp_transmit_skb() sets ownership. */ - skb =alloc_skb (MAX_TCP_HEADER ,GFP_ATOMIC ); + skb =alloc_skb (MAX_TCP_HEADER ,sk_gfp_atomic (sk,GFP_ATOMIC ));if (skb ==NULL )return -1 ;
net/ipv6/tcp_ipv6.c +5 -3
@@ -1352,7 +1352,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,/* Clone pktoptions received with SYN */ newnp->pktoptions =NULL ;if (treq->pktopts !=NULL ) { - newnp->pktoptions =skb_clone (treq->pktopts,GFP_ATOMIC ); + newnp->pktoptions =skb_clone (treq->pktopts, +sk_gfp_atomic (sk,GFP_ATOMIC ));kfree_skb (treq->pktopts); treq->pktopts =NULL ;if (newnp->pktoptions)
@@ -1405,7 +1406,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,* across. Shucks. */ tcp_md5_do_add (newsk, (union tcp_md5_addr *)&newnp->daddr, - AF_INET6, key->key, key->keylen, GFP_ATOMIC); +AF_INET6 , key->key, key->keylen, + sk_gfp_atomic(sk, GFP_ATOMIC)); }#endif
@@ -1500,7 +1502,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)--ANK (980728) */ if (np->rxopt.all) - opt_skb =skb_clone (skb,GFP_ATOMIC ); + opt_skb =skb_clone (skb,sk_gfp_atomic (sk,GFP_ATOMIC ));if (sk->sk_state ==TCP_ESTABLISHED ) {/* Fast path */ sock_rps_save_rxhash (sk, skb);
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 08/17] net: Introduce sk_gfp_atomic() to allow addition of GFP flags depending on the individual socket
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:22 +0100
Quoted 7 lines
Introduce
sk_gfp_atomic(), this function allows to inject sock specific flags to each sock related allocation. It is only used on allocation paths that may be required for writing pages back to network storage.[[email protected]: Use sk_gfp_atomic only when necessary]Signed-off-by Peter Zijlstra <[email protected]>Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 9/17 netvm: Allow the use of __GFP_MEMALLOC by specific sockets
In reply to Mel GormanAllow specific sockets to be tagged SOCK_MEMALLOC and use __GFP_MEMALLOC for their allocations. These sockets will be able to go below watermarks and allocate from the emergency reserve. 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.
There is a risk that the reserves be depleted so for now, the administrator is responsible for increasing min_free_kbytes as necessary to prevent deadlock for their workloads.
--- include/net/sock.h | 5 ++++- net/core/sock.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-)
include/net/sock.h +4 -1
@@ -607,6 +607,7 @@ enum sock_flags {SOCK_RCVTSTAMPNS ,/* %SO_TIMESTAMPNS setting */ SOCK_LOCALROUTE ,/* route locally only, %SO_DONTROUTE setting */ SOCK_QUEUE_SHRUNK ,/* write queue has been shrunk recently */ +SOCK_MEMALLOC ,/* VM depends on this socket for swapping */ SOCK_TIMESTAMPING_TX_HARDWARE ,/* %SOF_TIMESTAMPING_TX_HARDWARE */ SOCK_TIMESTAMPING_TX_SOFTWARE ,/* %SOF_TIMESTAMPING_TX_SOFTWARE */ SOCK_TIMESTAMPING_RX_HARDWARE, /* %SOF_TIMESTAMPING_RX_HARDWARE */
@@ -646,7 +647,7 @@ static inline int sock_flag(struct sock *sk, enum sock_flags flag)static inline gfp_t sk_gfp_atomic (struct sock *sk,gfp_t gfp_mask) { -return GFP_ATOMIC ; +return GFP_ATOMIC | (sk->sk_allocation & __GFP_MEMALLOC); }static inline void sk_acceptq_removed (struct sock *sk)
@@ -787,6 +788,8 @@ extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p);extern void sk_stream_wait_close (struct sock *sk,long timeo_p);extern int sk_stream_error (struct sock *sk,int flags,int err);extern void sk_stream_kill_queues (struct sock *sk); +extern void sk_set_memalloc (struct sock *sk); +extern void sk_clear_memalloc (struct sock *sk);extern int sk_wait_data (struct sock *sk,long *timeo);
net/core/sock.c +22 -0
@@ -266,6 +266,28 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;int sysctl_optmem_max__read_mostly =sizeof (unsigned long )*(2 *UIO_MAXIOV +512 );EXPORT_SYMBOL (sysctl_optmem_max); +/** +* sk_set_memalloc - sets %SOCK_MEMALLOC +* @sk: socket to set it on +* +* Set %SOCK_MEMALLOC on a socket for access to emergency reserves. +* It's the responsibility of the admin to adjust min_free_kbytes +* to meet the requirements +*/ +void sk_set_memalloc (struct sock *sk) +{ +sock_set_flag (sk,SOCK_MEMALLOC ); + sk->sk_allocation |= __GFP_MEMALLOC; +} +EXPORT_SYMBOL_GPL (sk_set_memalloc); + +void sk_clear_memalloc (struct sock *sk) +{ +sock_reset_flag (sk,SOCK_MEMALLOC ); + sk->sk_allocation &= ~__GFP_MEMALLOC; +} +EXPORT_SYMBOL_GPL (sk_clear_memalloc); +#if defined(CONFIG_CGROUPS )#if !defined(CONFIG_NET_CLS_CGROUP )int net_cls_subsys_id =-1 ;
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 09/17] netvm: Allow the use of __GFP_MEMALLOC by specific sockets
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:23 +0100
Quoted 6 lines
Allow specific sockets to be tagged
SOCK_MEMALLOCand use__GFP_MEMALLOCfor their allocations. These sockets will be able to go below watermarks and allocate from the emergency reserve. 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.
Quoted 6 lines
There is a risk that the reserves be depleted so for now, the administrator is responsible for increasing
min_free_kbytesas necessary to prevent deadlock for their workloads.[[email protected]: Original patches]Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 10/17 netvm: Allow skb allocation to use PFMEMALLOC reserves
In reply to Mel GormanChange the skb allocation API to indicate RX usage and use this to fall back to the PFMEMALLOC reserve when needed. SKBs allocated from the reserve are tagged in skb->pfmemalloc. If an SKB is allocated from the reserve and the socket is later found to be unrelated to page reclaim, the packet is dropped so that the memory remains available for page reclaim. Network protocols are expected to recover from this packet loss.
--- include/linux/gfp.h | 3 ++ include/linux/skbuff.h | 17 +++++++-- include/net/sock.h | 6 ++++ mm/internal.h | 3 -- net/core/filter.c | 8 +++++ net/core/skbuff.c | 94 ++++++++++++++++++++++++++++++++++++++++-------- net/core/sock.c | 4 +++ 7 files changed, 114 insertions(+), 21 deletions(-)
include/linux/gfp.h +3 -0
@@ -385,6 +385,9 @@ void drain_local_pages(void *dummy);*/ extern gfp_t gfp_allowed_mask; +/* Returns true if the gfp_mask allows use of ALLOC_NO_WATERMARK */ +bool gfp_pfmemalloc_allowed (gfp_t gfp_mask); +extern void pm_restrict_gfp_mask (void );extern void pm_restore_gfp_mask (void );
include/linux/skbuff.h +14 -3
@@ -465,6 +465,7 @@ struct sk_buff {#ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2;#endif + __u8 pfmemalloc:1; __u8 ooo_okay:1; __u8 l4_rxhash:1; __u8 wifi_acked_valid:1;
@@ -504,6 +505,15 @@ struct sk_buff {#include <linux/slab.h> +#define SKB_ALLOC_FCLONE 0x01 +#define SKB_ALLOC_RX 0x02 + +/* Returns true if the skb was allocated from PFMEMALLOC reserves */ +static inline bool skb_pfmemalloc (struct sk_buff *skb) +{ +return unlikely (skb->pfmemalloc); +} +/* * skb might have a dst pointer attached, refcounted or not. * _skb_refdst low order bit is set if refcount was _not_ taken
@@ -561,7 +571,7 @@ extern void kfree_skb(struct sk_buff *skb);extern void consume_skb (struct sk_buff *skb);extern void __kfree_skb (struct sk_buff *skb);extern struct sk_buff *__alloc_skb (unsigned int size, -gfp_t priority,int fclone,int node); +gfp_t priority,int flags,int node);extern struct sk_buff *build_skb (void *data);static inline struct sk_buff *alloc_skb (unsigned int size,gfp_t priority)
@@ -572,7 +582,7 @@ static inline struct sk_buff *alloc_skb(unsigned int size,static inline struct sk_buff *alloc_skb_fclone (unsigned int size,gfp_t priority) { -return __alloc_skb (size, priority,1 ,NUMA_NO_NODE ); +return __alloc_skb (size, priority,SKB_ALLOC_FCLONE ,NUMA_NO_NODE ); }extern void skb_recycle (struct sk_buff *skb);
@@ -1679,7 +1689,8 @@ static inline void __skb_queue_purge(struct sk_buff_head *list)static inline struct sk_buff *__dev_alloc_skb (unsigned int length,gfp_t gfp_mask) { -struct sk_buff *skb =alloc_skb (length +NET_SKB_PAD , gfp_mask); +struct sk_buff *skb =__alloc_skb (length +NET_SKB_PAD , gfp_mask, +SKB_ALLOC_RX ,NUMA_NO_NODE );if (likely (skb))skb_reserve (skb,NET_SKB_PAD );return skb;
include/net/sock.h +6 -0
@@ -645,6 +645,12 @@ static inline int sock_flag(struct sock *sk, enum sock_flags flag)return test_bit (flag, &sk->sk_flags); } +extern struct static_key memalloc_socks; +static inline int sk_memalloc_socks (void ) +{ +return static_key_false (&memalloc_socks); +} +static inline gfp_t sk_gfp_atomic (struct sock *sk,gfp_t gfp_mask) {return GFP_ATOMIC | (sk->sk_allocation & __GFP_MEMALLOC);
mm/internal.h +0 -3
@@ -239,9 +239,6 @@ static inline struct page *mem_map_next(struct page *iter,#define __paginginit __init#endif -/* Returns true if the gfp_mask allows use of ALLOC_NO_WATERMARK */ -bool gfp_pfmemalloc_allowed (gfp_t gfp_mask); -/* Memory initialisation debug and verification */ enum mminit_level {MMINIT_WARNING ,
net/core/filter.c +8 -0
@@ -82,6 +82,14 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)int err;struct sk_filter *filter; +/* +* If the skb was allocated from pfmemalloc reserves, only +* allow SOCK_MEMALLOC sockets to use it as this socket is +* helping free memory +*/ +if (skb_pfmemalloc (skb) && !sock_flag (sk,SOCK_MEMALLOC )) +return -ENOMEM ; + err =security_sock_rcv_skb (sk, skb);if (err)return err;
net/core/skbuff.c +79 -15
196 lines not on this page · raw message
net/core/sock.c +4 -0
@@ -266,6 +266,8 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;int sysctl_optmem_max__read_mostly =sizeof (unsigned long )*(2 *UIO_MAXIOV +512 );EXPORT_SYMBOL (sysctl_optmem_max); +struct static_key memalloc_socks =STATIC_KEY_INIT_FALSE ; +/** * sk_set_memalloc - sets %SOCK_MEMALLOC * @sk: socket to set it on
@@ -278,6 +280,7 @@ void sk_set_memalloc(struct sock *sk) {sock_set_flag (sk,SOCK_MEMALLOC ); sk->sk_allocation |= __GFP_MEMALLOC; +static_key_slow_inc (&memalloc_socks); }EXPORT_SYMBOL_GPL (sk_set_memalloc);
@@ -285,6 +288,7 @@ void sk_clear_memalloc(struct sock *sk) {sock_reset_flag (sk,SOCK_MEMALLOC ); sk->sk_allocation &= ~__GFP_MEMALLOC; +static_key_slow_dec (&memalloc_socks); }EXPORT_SYMBOL_GPL (sk_clear_memalloc);
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 10/17] netvm: Allow skb allocation to use PFMEMALLOC reserves
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:24 +0100
Quoted 11 lines
Change the skb allocation API to indicate RX usage and use this to fall back to the PFMEMALLOC reserve when needed. SKBs allocated from the reserve are tagged in
skb->pfmemalloc. If an SKB is allocated from the reserve and the socket is later found to be unrelated to page reclaim, the packet is dropped so that the memory remains available for page reclaim. Network protocols are expected to recover from this packet loss.[[email protected]: Use static branches, coding style corrections][[email protected]: Ideas taken from various patches]Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 11/17 netvm: Propagate page->pfmemalloc to skb
In reply to Mel GormanThe skb->pfmemalloc flag gets set to true iff during the slab allocation of data in __alloc_skb that the the PFMEMALLOC reserves were used. If the packet is fragmented, it is possible that pages will be allocated from the PFMEMALLOC reserve without propagating this information to the skb. This patch propagates page->pfmemalloc from pages allocated for fragments to the skb.
--- include/linux/skbuff.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
include/linux/skbuff.h +11 -0
@@ -1229,6 +1229,17 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, {skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; +/* +* Propagate page->pfmemalloc to the skb if we can. The problem is +* that not all callers have unique ownership of the page. If +* pfmemalloc is set, we check the mapping as a mapping implies +* page->index is set (index and pfmemalloc share space). +* If it's a valid mapping, we cannot use page->pfmemalloc but we +* do not lose pfmemalloc information as the pages would not be +* allocated using __GFP_MEMALLOC. +*/ +if (page->pfmemalloc && !page->mapping) + skb->pfmemalloc = true; frag->page.p = page; frag->page_offset = off;skb_frag_size_set (frag, size);
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 11/17] netvm: Propagate page->pfmemalloc to skb
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:25 +0100
Quoted 8 lines
The
skb->pfmemallocflag gets set to true iff during the slab allocation of data in__alloc_skbthat the the PFMEMALLOC reserves were used. If the packet is fragmented, it is possible that pages will be allocated from the PFMEMALLOC reserve without propagating this information to the skb. This patch propagatespage->pfmemallocfrom pages allocated for fragments to the skb.Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 12/17 netvm: Propagate page->pfmemalloc from skb_alloc_page to skb
In reply to Mel GormanThe skb->pfmemalloc flag gets set to true iff during the slab allocation of data in __alloc_skb that the the PFMEMALLOC reserves were used. If page splitting is used, it is possible that pages will be allocated from the PFMEMALLOC reserve without propagating this information to the skb. This patch propagates page->pfmemalloc from pages allocated for fragments to the skb.
It works by reintroducing and expanding the skb_alloc_page() API to take an skb. If the page was allocated from pfmemalloc reserves, it is automatically copied. If the driver allocates the page before the skb, it should call skb_propagate_pfmemalloc() after the skb is allocated to ensure the flag is copied properly.
Failure to do so is not critical. The resulting driver may perform slower if it is used for swap-over-NBD or swap-over-NFS but it should not result in failure.
--- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2 +- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 3 +- drivers/net/usb/cdc-phonet.c | 2 +- drivers/usb/gadget/f_phonet.c | 2 +- include/linux/skbuff.h | 55 +++++++++++++++++++++ 8 files changed, 63 insertions(+), 7 deletions(-)
drivers/net/ethernet/chelsio/cxgb4/sge.c +1 -1
@@ -528,7 +528,7 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,#endif while (n--) { - pg =alloc_page (gfp); + pg =__skb_alloc_page (gfp,NULL );if (unlikely (!pg)) { q->alloc_failed++;break ;
drivers/net/ethernet/chelsio/cxgb4vf/sge.c +1 -1
@@ -653,7 +653,7 @@ static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl, alloc_small_pages:while (n--) { - page =alloc_page (gfp | __GFP_NOWARN | __GFP_COLD); + page =__skb_alloc_page (gfp | __GFP_NOWARN,NULL );if (unlikely (!page)) { fl->alloc_failed++;break ;
drivers/net/ethernet/intel/igb/igb_main.c +1 -1
@@ -6232,7 +6232,7 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,return true;if (!page) { - page =alloc_page (GFP_ATOMIC | __GFP_COLD); + page =__skb_alloc_page (GFP_ATOMIC , bi->skb); bi->page = page;if (unlikely (!page)) { rx_ring->rx_stats.alloc_failed++;
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +1 -1
@@ -1126,7 +1126,7 @@ static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,/* alloc new page for storage */ if (likely (!page)) { - page =alloc_pages (GFP_ATOMIC | __GFP_COLD, + page =__skb_alloc_pages (GFP_ATOMIC , bi->skb,ixgbe_rx_pg_order (rx_ring));if (unlikely (!page)) { rx_ring->rx_stats.alloc_rx_page_failed++;
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +2 -1
@@ -369,7 +369,7 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,if (!bi->page_dma && (adapter->flags &IXGBE_FLAG_RX_PS_ENABLED )) {if (!bi->page) { - bi->page =alloc_page (GFP_ATOMIC | __GFP_COLD); + bi->page =__skb_alloc_page (GFP_ATOMIC ,NULL );if (!bi->page) { adapter->alloc_rx_page_failed++; goto no_buffers;
@@ -403,6 +403,7 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,*/ skb_reserve (skb,NET_IP_ALIGN ); +skb_propagate_pfmemalloc (bi->page_dma, skb); bi->skb = skb; }if (!bi->dma) {
drivers/net/usb/cdc-phonet.c +1 -1
@@ -130,7 +130,7 @@ static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)struct page *page;int err; - page =alloc_page (gfp_flags); + page =__skb_alloc_page (gfp_flags | __GFP_NOMEMALLOC,NULL );if (!page)return -ENOMEM ;
drivers/usb/gadget/f_phonet.c +1 -1
@@ -301,7 +301,7 @@ pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)struct page *page;int err; - page =alloc_page (gfp_flags); + page =__skb_alloc_page (gfp_flags | __GFP_NOMEMALLOC,NULL );if (!page)return -ENOMEM ;
include/linux/skbuff.h +55 -0
61 lines not on this page · raw message
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 12/17] netvm: Propagate page->pfmemalloc from skb_alloc_page to skb
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:26 +0100
Quoted 13 lines
The
skb->pfmemallocflag gets set to true iff during the slab allocation of data in__alloc_skbthat the the PFMEMALLOC reserves were used. If page splitting is used, it is possible that pages will be allocated from the PFMEMALLOC reserve without propagating this information to the skb. This patch propagatespage->pfmemallocfrom pages allocated for fragments to the skb.It works by reintroducing and expanding the
skb_alloc_page()API to take an skb. If the page was allocated from pfmemalloc reserves, it is automatically copied. If the driver allocates the page before the skb, it should callskb_propagate_pfmemalloc()after the skb is allocated to ensure the flag is copied properly.
Quoted 6 lines
Failure to do so is not critical. The resulting driver may perform slower if it is used for swap-over-NBD or swap-over-NFS but it should not result in failure.
[[email protected]: API rename and consistency]Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 13/17 netvm: Set PF_MEMALLOC as appropriate during SKB processing
In reply to Mel GormanIn order to make sure pfmemalloc packets receive all memory needed to proceed, ensure processing of pfmemalloc SKBs happens under PF_MEMALLOC. This is limited to a subset of protocols that are expected to be used for writing to swap. Taps are not allowed to use PF_MEMALLOC as these are expected to communicate with userspace processes which could be paged out.
--- include/net/sock.h | 5 +++++ net/core/dev.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------ net/core/sock.c | 16 ++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-)
include/net/sock.h +5 -0
@@ -729,8 +729,13 @@ static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *sreturn 0 ; } +extern int __sk_backlog_rcv (struct sock *sk,struct sk_buff *skb); +static inline int sk_backlog_rcv (struct sock *sk,struct sk_buff *skb) { +if (sk_memalloc_socks () &&skb_pfmemalloc (skb)) +return __sk_backlog_rcv (sk, skb); +return sk->sk_backlog_rcv (sk, skb); }
net/core/dev.c +47 -6
121 lines not on this page · raw message
net/core/sock.c +16 -0
@@ -292,6 +292,22 @@ void sk_clear_memalloc(struct sock *sk) }EXPORT_SYMBOL_GPL (sk_clear_memalloc); +int __sk_backlog_rcv (struct sock *sk,struct sk_buff *skb) +{ +int ret; +unsigned long pflags = current->flags; + +/* these should have been dropped before queueing */ +BUG_ON (!sock_flag (sk,SOCK_MEMALLOC )); + + current->flags |=PF_MEMALLOC ; + ret = sk->sk_backlog_rcv (sk, skb); +tsk_restore_flags (current, pflags,PF_MEMALLOC ); + +return ret; +} +EXPORT_SYMBOL (__sk_backlog_rcv); +#if defined(CONFIG_CGROUPS )#if !defined(CONFIG_NET_CLS_CGROUP )int net_cls_subsys_id =-1 ;
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 13/17] netvm: Set PF_MEMALLOC as appropriate during SKB processing
From: Mel Gorman <[email protected]>
Date: Thu, 17 May 2012 15:50:27 +0100
Quoted 10 lines
In order to make sure pfmemalloc packets receive all memory needed to proceed, ensure processing of pfmemalloc SKBs happens under
PF_MEMALLOC. This is limited to a subset of protocols that are expected to be used for writing to swap. Taps are not allowed to usePF_MEMALLOCas these are expected to communicate with userspace processes which could be paged out.[[email protected]: Ideas taken from various patches][[email protected]: Lock imbalance fix]Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 14/17 mm: Micro-optimise slab to avoid a function call
In reply to Mel GormanGetting and putting objects in SLAB currently requires a function call but the bulk of the work is related to PFMEMALLOC reserves which are only consumed when network-backed storage is critical. Use an inline function to determine if the function call is required.
--- mm/slab.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)
mm/slab.c +26 -2
@@ -117,6 +117,8 @@#include <linux/memory.h> #include <linux/prefetch.h> +#include <net/sock.h> +#include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <asm/page.h>
@@ -1016,7 +1018,7 @@ out:spin_unlock_irqrestore (&l3->list_lock, flags); } -static void *ac_get_obj (struct kmem_cache *cachep,struct array_cache *ac, +static void *__ac_get_obj (struct kmem_cache *cachep,struct array_cache *ac,gfp_t flags,bool force_refill) {int i;
@@ -1063,7 +1065,20 @@ static void *ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,return objp; } -static void ac_put_obj (struct kmem_cache *cachep,struct array_cache *ac, +static inline void *ac_get_obj (struct kmem_cache *cachep, +struct array_cache *ac,gfp_t flags,bool force_refill) +{ +void *objp; + +if (unlikely (sk_memalloc_socks ())) + objp =__ac_get_obj (cachep, ac, flags, force_refill); +else + objp = ac->entry[--ac->avail]; + +return objp; +} + +static void *__ac_put_obj (struct kmem_cache *cachep,struct array_cache *ac,void *objp) {if (unlikely (pfmemalloc_active)) {
@@ -1073,6 +1088,15 @@ static void ac_put_obj(struct kmem_cache *cachep, struct array_cache *ac,set_obj_pfmemalloc (&objp); } +return objp; +} + +static inline void ac_put_obj (struct kmem_cache *cachep,struct array_cache *ac, +void *objp) +{ +if (unlikely (sk_memalloc_socks ())) + objp =__ac_put_obj (cachep, ac, objp); + ac->entry[ac->avail++] = objp; }
Signature · 1 line
1.7.9.2
Mel Gorman
reviewerPATCH 15/17 nbd: Set SOCK_MEMALLOC for access to PFMEMALLOC reserves
In reply to Mel GormanSet SOCK_MEMALLOC on the NBD socket to allow access to PFMEMALLOC reserves so pages backed by NBD, particularly if swap related, can be cleaned to prevent the machine being deadlocked. It is still possible that the PFMEMALLOC reserves get depleted resulting in deadlock but this can be resolved by the administrator by increasing min_free_kbytes.
--- drivers/block/nbd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/block/nbd.c +5 -1
@@ -154,6 +154,7 @@ static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,struct msghdr msg;struct kvec iov;sigset_t blocked, oldset; +unsigned long pflags = current->flags;if (unlikely (!sock)) { dev_err(disk_to_dev(nbd->disk),
@@ -167,8 +168,9 @@ static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,siginitsetinv (&blocked,sigmask (SIGKILL ));sigprocmask (SIG_SETMASK , &blocked, &oldset); + current->flags |=PF_MEMALLOC ; do { - sock->sk->sk_allocation = GFP_NOIO; + sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC; iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL;
@@ -214,6 +216,7 @@ static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size, }while (size >0 );sigprocmask (SIG_SETMASK , &oldset,NULL ); +tsk_restore_flags (current, pflags,PF_MEMALLOC );return result; }
@@ -405,6 +408,7 @@ static int nbd_do_it(struct nbd_device *nbd)BUG_ON (nbd->magic !=NBD_MAGIC ); +sk_set_memalloc (nbd->sock->sk); nbd->pid =task_pid_nr (current); ret =device_create_file (disk_to_dev (nbd->disk), &pid_attr);if (ret) {
Signature · 1 line
1.7.9.2
Mel Gorman
reviewerPATCH 16/17 mm: Throttle direct reclaimers if PF_MEMALLOC reserves are low and swap is backed by network storage
In reply to Mel GormanIf swap is backed by network storage such as NBD, there is a risk that a large number of reclaimers can hang the system by consuming all PF_MEMALLOC reserves. To avoid these hangs, the administrator must tune min_free_kbytes in advance which is a bit fragile.
This patch throttles direct reclaimers if half the PF_MEMALLOC reserves are in use. If the system is routinely getting throttled the system administrator can increase min_free_kbytes so degradation is smoother but the system will keep running.
--- include/linux/mmzone.h | 1 + mm/page_alloc.c | 1 + mm/vmscan.c | 128 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 122 insertions(+), 8 deletions(-)
include/linux/mmzone.h +1 -0
@@ -663,6 +663,7 @@ typedef struct pglist_data {range, including holes */ int node_id;wait_queue_head_t kswapd_wait; +wait_queue_head_t pfmemalloc_wait;struct task_struct *kswapd;int kswapd_max_order;enum zone_type classzone_idx;
mm/page_alloc.c +1 -0
@@ -4326,6 +4326,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,pgdat_resize_init (pgdat); pgdat->nr_zones =0 ;init_waitqueue_head (&pgdat->kswapd_wait); +init_waitqueue_head (&pgdat->pfmemalloc_wait); pgdat->kswapd_max_order =0 ;pgdat_page_cgroup_init (pgdat);
mm/vmscan.c +120 -8
183 lines not on this page · raw message
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Mel Gorman
reviewerPATCH 17/17 mm: Account for the number of times direct reclaimers get throttled
In reply to Mel GormanUnder significant pressure when writing back to network-backed storage, direct reclaimers may get throttled. This is expected to be a short-lived event and the processes get woken up again but processes do get stalled. This patch counts how many times such stalling occurs. It's up to the administrator whether to reduce these stalls by increasing min_free_kbytes.
--- include/linux/vm_event_item.h | 1 + mm/vmscan.c | 3 +++ mm/vmstat.c | 1 + 3 files changed, 5 insertions(+)
include/linux/vm_event_item.h +1 -0
@@ -30,6 +30,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,FOR_ALL_ZONES (PGSTEAL_DIRECT ),FOR_ALL_ZONES (PGSCAN_KSWAPD ),FOR_ALL_ZONES (PGSCAN_DIRECT ), +PGSCAN_DIRECT_THROTTLE , #ifdef CONFIG_NUMA PGSCAN_ZONE_RECLAIM_FAILED, #endif
mm/vmscan.c +3 -0
@@ -2486,6 +2486,9 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,if (pfmemalloc_watermark_ok (pgdat))return ; +/* Account for the throttling */ +count_vm_event (PGSCAN_DIRECT_THROTTLE ); +/* * If the caller cannot enter the filesystem, it's possible that it * is due to the caller holding an FS lock or performing a journal
mm/vmstat.c +1 -0
@@ -742,6 +742,7 @@ const char * const vmstat_text[] = { TEXTS_FOR_ZONES("pgsteal_direct") TEXTS_FOR_ZONES("pgscan_kswapd") TEXTS_FOR_ZONES("pgscan_direct") +"pgscan_direct_throttle" , #ifdef CONFIG_NUMA "zone_reclaim_failed",
Signature · 8 lines
1.7.9.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Mel Gorman
Mostly addressing feedback from David Miller.
Changeloc since V10
o Rebase to 3.4-rc5
o Coding style fixups (davem)
o API consistency (davem)
o Renamesk_allocationtosk_gfp_atomicand use only when necessary (davem)
o Use static branches forsk_memalloc_socks(davem)
o Use static branch checks in fast paths (davem)
o Document concerns aboutPF_MEMALLOCleaking flags (davem)
o Locking fix in slab (mel)
<snip>
I am attempting to test these, but when they are applied on top of mainline head my laptop hangs about 60-90 seconds after boot. I am trying mainline without these sets now and will post results.
Eric
Quoted 11 lines · Mel Gorman
Mostly addressing feedback from David Miller.
Changeloc since V10
o Rebase to 3.4-rc5
o Coding style fixups (davem)
o API consistency (davem)
o Renamesk_allocationtosk_gfp_atomicand use only when necessary (davem)
o Use static branches forsk_memalloc_socks(davem)
o Use static branch checks in fast paths (davem)
o Document concerns aboutPF_MEMALLOCleaking flags (davem)
o Locking fix in slab (mel)
The hang happens without these sets. Unfortunately because my beagle board is busy and will be through the weekend, I won't be able to test these sets until the hang is fixed.
Eric