Discard __GFP_ATOMIC
Subsystems (11)
cover Discard __GFP_ATOMIC
Neil's patch has been residing in mm-unstable as commit 2fafb4fe8f7a ("mm: discard __GFP_ATOMIC") for a long time and recently brought up again. Most recently, I was worried that __GFP_HIGH allocations could use high-order atomic reserves which is unintentional but there was no response so lets revisit -- this series reworks how min reserves are used, protects highorder reserves and then finishes with Neil's patch with very minor modifications so it fits on top.
There was a review discussion on renaming __GFP_DIRECT_RECLAIM to __GFP_ALLOW_BLOCKING but I didn't think it was that big an issue and is ortogonal to the removal of __GFP_ATOMIC.
There were some concerns about how the gfp flags affect the min reserves but it never reached a solid conclusion so I made my own attempt.
The series tries to iron out some of the details on how reserves are used. ALLOC_HIGH becomes ALLOC_MIN_RESERVE and ALLOC_HARDER becomes ALLOC_NON_BLOCK and documents how the reserves are affected. For example, ALLOC_NON_BLOCK (no direct reclaim) on its own allows 25% of the min reserve. ALLOC_MIN_RESERVE (__GFP_HIGH) allows 50% and both combined allows deeper access again. ALLOC_OOM allows access to 75%.
High-order atomic allocations are explicitly handled with the caveat that no __GFP_ATOMIC flag means that any high-order allocation that specifies GFP_HIGH and cannot enter direct reclaim will be treated as if it was GFP_ATOMIC.
Signature · 1 line
2.35.3
PATCH 1/6 mm/page_alloc: Rename ALLOC_HIGH to ALLOC_MIN_RESERVE
__GFP_HIGH aliases to ALLOC_HIGH but the name does not really hint what it means. As ALLOC_HIGH is internal to the allocator, rename it to ALLOC_MIN_RESERVE to document that the min reserves can be depleted.
--- mm/internal.h | 4 +++- mm/page_alloc.c | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-)
mm/internal.h +3 -1
@@ -744,7 +744,9 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#endif #define ALLOC_HARDER 0x10/* try to alloc harder */ -#define ALLOC_HIGH 0x20/* __GFP_HIGH set */ +#define ALLOC_MIN_RESERVE 0x20/* __GFP_HIGH set. Allow access to 50% +* of the min watermark. +*/ #define ALLOC_CPUSET 0x40/* check for correct cpuset */ #define ALLOC_CMA 0x80/* allow allocations from CMA areas */ #ifdef CONFIG_ZONE_DMA32
mm/page_alloc.c +4 -4
@@ -3981,7 +3981,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,/* free_pages may go negative - that's OK */ free_pages -=__zone_watermark_unusable_free (z, order, alloc_flags); -if (alloc_flags &ALLOC_HIGH ) +if (alloc_flags &ALLOC_MIN_RESERVE ) min -= min /2 ;if (unlikely (alloc_harder)) {
@@ -4823,18 +4823,18 @@ gfp_to_alloc_flags(gfp_t gfp_mask)unsigned int alloc_flags =ALLOC_WMARK_MIN |ALLOC_CPUSET ;/* -* __GFP_HIGH is assumed to be the same as ALLOC_HIGH +* __GFP_HIGH is assumed to be the same as ALLOC_MIN_RESERVE * and __GFP_KSWAPD_RECLAIM is assumed to be the same as ALLOC_KSWAPD * to save two branches. */ -BUILD_BUG_ON (__GFP_HIGH != (__force gfp_t )ALLOC_HIGH ); +BUILD_BUG_ON (__GFP_HIGH != (__force gfp_t )ALLOC_MIN_RESERVE );BUILD_BUG_ON (__GFP_KSWAPD_RECLAIM != (__force gfp_t )ALLOC_KSWAPD );/* * The caller may dip into page reserves a bit more if the caller * cannot run direct reclaim, or if the caller has realtime scheduling * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will -* set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_HIGH (__GFP_HIGH). +* set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_MIN_RESERVE(__GFP_HIGH). */ alloc_flags |= (__force int ) (gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM));
Signature · 1 line
2.35.3
Re: [PATCH 1/6] mm/page_alloc: Rename ALLOC_HIGH to ALLOC_MIN_RESERVE
Quoted 6 lines · Mel Gorman
__GFP_HIGHaliases toALLOC_HIGHbut the name does not really hint what it means. AsALLOC_HIGHis internal to the allocator, rename it toALLOC_MIN_RESERVEto document that the min reserves can be depleted.Signed-off-by Mel Gorman <[email protected]>
PATCH 2/6 mm/page_alloc: Treat RT tasks similar to GFP_HIGH
In reply to Mel GormanRT tasks are allowed to dip below the min reserve but ALLOC_HARDER is typically combined with ALLOC_MIN_RESERVE so RT tasks are a little unusual. While there is some justification for allowing RT tasks access to memory reserves, there is a strong chance that a RT task that is also under memory pressure is at risk of missing deadlines anyway. Relax how much reserves an RT task can access by treating it the same as __GFP_HIGH allocations.
--- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/page_alloc.c +1 -1
@@ -4852,7 +4852,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)*/ alloc_flags &= ~ALLOC_CPUSET ; }else if (unlikely (rt_task (current)) &&in_task ()) - alloc_flags |=ALLOC_HARDER ; + alloc_flags |=ALLOC_MIN_RESERVE ; alloc_flags =gfp_to_alloc_flags_cma (gfp_mask, alloc_flags);
Signature · 1 line
2.35.3
Re: [PATCH 2/6] mm/page_alloc: Treat RT tasks similar to GFP_HIGH
Subject should say __GFP_HIGH as there's no GFP_HIGH?
Quoted 9 lines · Mel Gorman
RT tasks are allowed to dip below the min reserve but
ALLOC_HARDERis typically combined withALLOC_MIN_RESERVEso RT tasks are a little unusual. While there is some justification for allowing RT tasks access to memory reserves, there is a strong chance that a RT task that is also under memory pressure is at risk of missing deadlines anyway. Relax how much reserves an RT task can access by treating it the same as__GFP_HIGHallocations.Signed-off-by Mel Gorman <[email protected]>
Quoted 17 lines
--- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)mm/page_alloc.c +1
-1@@ -4852,7 +4852,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)*/ alloc_flags &= ~ALLOC_CPUSET ; }else if (unlikely (rt_task (current)) &&in_task ()) - alloc_flags |=ALLOC_HARDER ; + alloc_flags |=ALLOC_MIN_RESERVE ; alloc_flags =gfp_to_alloc_flags_cma (gfp_mask, alloc_flags);
PATCH 3/6 mm/page_alloc: Explicitly record high-order atomic allocations in alloc_flags
In reply to Mel GormanA high-order ALLOC_HARDER allocation is assumed to be atomic. While that is accurate, it changes later in the series. In preparation, explicitly record high-order atomic allocations in gfp_to_alloc_flags().
--- mm/internal.h | 1 + mm/page_alloc.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-)
mm/internal.h +1 -0
@@ -754,6 +754,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#else #define ALLOC_NOFRAGMENT 0x0#endif +#define ALLOC_HIGHATOMIC 0x200/* Allows access to MIGRATE_HIGHATOMIC */ #define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ enum ttu_flags ;
mm/page_alloc.c +13 -6
@@ -3710,7 +3710,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,* reserved for high-order atomic allocation, so order-0 * request should skip it. */ -if (order >0 && alloc_flags &ALLOC_HARDER ) +if (alloc_flags &ALLOC_HIGHATOMIC ) page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC );if (!page) { page =__rmqueue (zone, order, migratetype, alloc_flags);
@@ -4028,8 +4028,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; }#endif -if (alloc_harder && !free_area_empty (area,MIGRATE_HIGHATOMIC )) +if ((alloc_flags &ALLOC_HIGHATOMIC ) && + !free_area_empty (area,MIGRATE_HIGHATOMIC )) {return true; + } }return false; }
@@ -4291,7 +4293,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,* If this is a high-order atomic allocation then check * if the pageblock should be reserved for the future */ -if (unlikely (order && (alloc_flags &ALLOC_HARDER ))) +if (unlikely (alloc_flags &ALLOC_HIGHATOMIC ))reserve_highatomic_pageblock (page, zone, order);return page;
@@ -4818,7 +4820,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, }static inline unsigned int -gfp_to_alloc_flags (gfp_t gfp_mask) +gfp_to_alloc_flags (gfp_t gfp_mask,unsigned int order) {unsigned int alloc_flags =ALLOC_WMARK_MIN |ALLOC_CPUSET ;
@@ -4844,8 +4846,13 @@ gfp_to_alloc_flags(gfp_t gfp_mask)* Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ -if (!(gfp_mask & __GFP_NOMEMALLOC)) +if (!(gfp_mask & __GFP_NOMEMALLOC)) { alloc_flags |=ALLOC_HARDER ; + +if (order >0 ) + alloc_flags |=ALLOC_HIGHATOMIC ; + } +/* * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the * comment for __cpuset_node_allowed().
@@ -5053,7 +5060,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* kswapd needs to be woken up, and to avoid the cost of setting up * alloc_flags precisely. So we do that now. */ - alloc_flags =gfp_to_alloc_flags (gfp_mask); + alloc_flags =gfp_to_alloc_flags (gfp_mask, order);/* * We need to recalculate the starting point for the zonelist iterator
Signature · 1 line
2.35.3
Re: [PATCH 3/6] mm/page_alloc: Explicitly record high-order atomic allocations in alloc_flags
Hi Mel,
thanks a lot for doing this!
I tried reviewing it but "HIGHATOMIC" is new to me and I quickly got lost :-(
Maybe one day I'll work it out - now that several names are more meaningful, it will likely be easier.
Thanks,
NeilBrown
Quoted 93 lines · Mel Gorman
A high-order
ALLOC_HARDERallocation is assumed to be atomic. While that is accurate, it changes later in the series. In preparation, explicitly record high-order atomic allocations ingfp_to_alloc_flags().Signed-off-by Mel Gorman <[email protected]>--- mm/internal.h | 1 + mm/page_alloc.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-)mm/internal.h +1
-0@@ -754,6 +754,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#else #define ALLOC_NOFRAGMENT 0x0#endif +#define ALLOC_HIGHATOMIC 0x200/* Allows access to MIGRATE_HIGHATOMIC */ #define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ enum ttu_flags ;mm/page_alloc.c +13
-6@@ -3710,7 +3710,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,* reserved for high-order atomic allocation, so order-0 * request should skip it. */ -if (order >0 && alloc_flags &ALLOC_HARDER ) +if (alloc_flags &ALLOC_HIGHATOMIC ) page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC );if (!page) { page =__rmqueue (zone, order, migratetype, alloc_flags);@@ -4028,8 +4028,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; }#endif -if (alloc_harder && !free_area_empty (area,MIGRATE_HIGHATOMIC )) +if ((alloc_flags &ALLOC_HIGHATOMIC ) && + !free_area_empty (area,MIGRATE_HIGHATOMIC )) {return true; + } }return false; }@@ -4291,7 +4293,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,* If this is a high-order atomic allocation then check * if the pageblock should be reserved for the future */ -if (unlikely (order && (alloc_flags &ALLOC_HARDER ))) +if (unlikely (alloc_flags &ALLOC_HIGHATOMIC ))reserve_highatomic_pageblock (page, zone, order);return page;@@ -4818,7 +4820,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, }static inline unsigned int -gfp_to_alloc_flags (gfp_t gfp_mask) +gfp_to_alloc_flags (gfp_t gfp_mask,unsigned int order) {unsigned int alloc_flags =ALLOC_WMARK_MIN |ALLOC_CPUSET ;@@ -4844,8 +4846,13 @@ gfp_to_alloc_flags(gfp_t gfp_mask)* Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ -if (!(gfp_mask & __GFP_NOMEMALLOC)) +if (!(gfp_mask & __GFP_NOMEMALLOC)) { alloc_flags |=ALLOC_HARDER ; + +if (order >0 ) + alloc_flags |=ALLOC_HIGHATOMIC ; + } +/* * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the * comment for __cpuset_node_allowed(). @@ -5053,7 +5060,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* kswapd needs to be woken up, and to avoid the cost of setting up * alloc_flags precisely. So we do that now. */ - alloc_flags =gfp_to_alloc_flags (gfp_mask); + alloc_flags =gfp_to_alloc_flags (gfp_mask, order);/* * We need to recalculate the starting point for the zonelist iterator Signature · 1 line
2.35.3
Re: [PATCH 3/6] mm/page_alloc: Explicitly record high-order atomic allocations in alloc_flags
Quoted 3 lines · NeilBrown
Hi Mel,
thanks a lot for doing this!
My pleasure.
Quoted 2 lines
I tried reviewing it but "HIGHATOMIC" is new to me and I quickly got lost :-(
That's ok, HIGHATOMIC reserves are obscure and internal to the allocator. It's almost as obscure as granting access to reserves for RT tasks with the only difference being a lack of data on what sort of RT tasks needed extra privileges back in the early 2000's but I happened to remember why highatomic reserves were introduced. It was introduced when fragmentation avoidance triggered high-order atomic allocations failures that "happened to work" by accident before fragmentation avoidance (details in 0aaa29a56e4f). IIRC, there were a storm of bugs, mostly on small embedded platforms where devices without an IOMMU relied on high-order atomics to work so a small reserve was created. I was concerned your patch would trigger this class of bug again even though it might take a few years to show up as embedded platforms tend to stay on old kernels for ages.
The main point of this patch is identifying these high-order atomic allocations without relying on __GFP_ATOMIC but it should not be necessary to understand how high-order atomic reserves work. They still work the same way, access is just granted differently.
Quoted 12 lines
Maybe one day I'll work it out - now that several names are more meaningful, it will likely be easier.
Quoted 9 lines
mm/page_alloc.c +1
-1@@ -4818,7 +4820,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, }static inline unsigned int -gfp_to_alloc_flags (gfp_t gfp_mask) +gfp_to_alloc_flags (gfp_t gfp_mask,unsigned int order) {unsigned int alloc_flags =ALLOC_WMARK_MIN |ALLOC_CPUSET ;
Quoted 15 lines
Quoted 5 lines
mm/page_alloc.c +0
-1@@ -4844,8 +4846,13 @@ gfp_to_alloc_flags(gfp_t gfp_mask)* Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ -if (!(gfp_mask & __GFP_NOMEMALLOC))mm/page_alloc.c gfp_to_alloc_flags(gfp_t gfp_mask) · line 4858
Quoted 10 lines
mm/page_alloc.c +6
-0+if (!(gfp_mask & __GFP_NOMEMALLOC)) { alloc_flags |=ALLOC_HARDER ; + +if (order >0 ) + alloc_flags |=ALLOC_HIGHATOMIC ; + } +/* * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the * comment for __cpuset_node_allowed().
This is the most crucial hunk two hunks of the patch. If the series is merged and we start seeing high-order atomic allocations failure, the key will be to look at the gfp_flags and determine if this hunk is enough to accurately detect high-order atomic allocations. If the GFP flags look ok, then a tracing debugging patch will be created to dump gfp_flags every time access is granted to high-atomic reserves to determine if access is given incorrectly and under what circumstances.
The main concern I had with your original patch was that it was too easy to grant access to high-atomic reserves for requests that were not high-order atomics requests which might exhaust the reserves. The rest of the series tries to improve the naming of the ALLOC flags and what they mean. The actual changes to your patch are minimal. I could have started with your patch and fixed it up but I preferred this ordering to reduce use of __GFP_ATOMIC and then delete it. It should be bisection safe.
Signature · 2 lines
Mel Gorman SUSE Labs
Re: [PATCH 3/6] mm/page_alloc: Explicitly record high-order atomic allocations in alloc_flags
In reply to Mel GormanQuoted 36 lines · Mel Gorman
A high-order
ALLOC_HARDERallocation is assumed to be atomic. While that is accurate, it changes later in the series. In preparation, explicitly record high-order atomic allocations ingfp_to_alloc_flags().Signed-off-by Mel Gorman <[email protected]>--- mm/internal.h | 1 + mm/page_alloc.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-)mm/internal.h +1
-0@@ -754,6 +754,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#else #define ALLOC_NOFRAGMENT 0x0#endif +#define ALLOC_HIGHATOMIC 0x200/* Allows access to MIGRATE_HIGHATOMIC */ #define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ enum ttu_flags ;mm/page_alloc.c +1
-1@@ -3710,7 +3710,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,* reserved for high-order atomic allocation, so order-0 * request should skip it. */ -if (order >0 && alloc_flags &ALLOC_HARDER ) +if (alloc_flags &ALLOC_HIGHATOMIC ) page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC );if (!page) { page =__rmqueue (zone, order, migratetype, alloc_flags);
mm/page_alloc.c bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 4033
Quoted 7 lines
mm/page_alloc.c +2
-1@@ -4028,8 +4028,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; }#endif -if (alloc_harder && !free_area_empty (area,MIGRATE_HIGHATOMIC )) +if ((alloc_flags &ALLOC_HIGHATOMIC ) && + !free_area_empty (area,MIGRATE_HIGHATOMIC )) {return true;
alloc_harder is defined as
(alloc_flags & (ALLOC_HARDER|ALLOC_OOM));
AFAICS this means we no longer allow ALLOC_OOM to use the highatomic reserve. Isn't that a risk?
Quoted 46 lines
mm/page_alloc.c +10
-4+ } }return false; }@@ -4291,7 +4293,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,* If this is a high-order atomic allocation then check * if the pageblock should be reserved for the future */ -if (unlikely (order && (alloc_flags &ALLOC_HARDER ))) +if (unlikely (alloc_flags &ALLOC_HIGHATOMIC ))reserve_highatomic_pageblock (page, zone, order);return page;@@ -4818,7 +4820,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, }static inline unsigned int -gfp_to_alloc_flags (gfp_t gfp_mask) +gfp_to_alloc_flags (gfp_t gfp_mask,unsigned int order) {unsigned int alloc_flags =ALLOC_WMARK_MIN |ALLOC_CPUSET ;@@ -4844,8 +4846,13 @@ gfp_to_alloc_flags(gfp_t gfp_mask)* Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ -if (!(gfp_mask & __GFP_NOMEMALLOC)) +if (!(gfp_mask & __GFP_NOMEMALLOC)) { alloc_flags |=ALLOC_HARDER ; + +if (order >0 ) + alloc_flags |=ALLOC_HIGHATOMIC ; + } +/* * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the * comment for __cpuset_node_allowed(). @@ -5053,7 +5060,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* kswapd needs to be woken up, and to avoid the cost of setting up * alloc_flags precisely. So we do that now. */ - alloc_flags =gfp_to_alloc_flags (gfp_mask); + alloc_flags =gfp_to_alloc_flags (gfp_mask, order);/* * We need to recalculate the starting point for the zonelist iterator
Re: [PATCH 3/6] mm/page_alloc: Explicitly record high-order atomic allocations in alloc_flags
First off, sorry for the long delay getting back to you. I was sick for a few weeks and still catching up. I'm still not 100%.
Quoted 24 lines · Vlastimil Babka
Quoted 14 lines · Mel Gorman
mm/page_alloc.c +1
-1@@ -3710,7 +3710,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,* reserved for high-order atomic allocation, so order-0 * request should skip it. */ -if (order >0 && alloc_flags &ALLOC_HARDER ) +if (alloc_flags &ALLOC_HIGHATOMIC ) page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC );if (!page) { page =__rmqueue (zone, order, migratetype, alloc_flags);mm/page_alloc.c bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 4033
Quoted 7 lines
mm/page_alloc.c +2
-1@@ -4028,8 +4028,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; }#endif -if (alloc_harder && !free_area_empty (area,MIGRATE_HIGHATOMIC )) +if ((alloc_flags &ALLOC_HIGHATOMIC ) && + !free_area_empty (area,MIGRATE_HIGHATOMIC )) {return true;
alloc_harderis defined as
Quoted 4 lines
(alloc_flags & (ALLOC_HARDER|ALLOC_OOM));AFAICS this means we no longer allow
ALLOC_OOMto use the highatomic reserve. Isn't that a risk?
Yes, it is. I intend to apply the patch below on top. I didn't alter the first check for ALLOC_HIGHATOMIC as I wanted OOM handling to only use the high-order reserves if there was no other option. While this is a change in behaviour, it should be a harmless one. I'll add a note in the changelog.
mm/page_alloc.c +11 -1
@@ -3710,6 +3710,16 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone, page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC );if (!page) { page =__rmqueue (zone, order, migratetype, alloc_flags); + +/* +* If the allocation fails, allow OOM handling access +* to HIGHATOMIC reserves as failing now is worse than +* failing a high-order atomic allocation in the +* future. +*/ +if (!page && (alloc_flags &ALLOC_OOM )) + page =__rmqueue_smallest (zone, order,MIGRATE_HIGHATOMIC ); +if (!page) {spin_unlock_irqrestore (&zone->lock, flags);return NULL ;
@@ -4023,7 +4033,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; }#endif -if ((alloc_flags &ALLOC_HIGHATOMIC ) && +if ((alloc_flags & (ALLOC_HIGHATOMIC |ALLOC_OOM )) && !free_area_empty (area,MIGRATE_HIGHATOMIC )) {return true; }
Signature · 2 lines
Mel Gorman SUSE Labs
PATCH 4/6 mm/page_alloc: Explicitly define what alloc flags deplete min reserves
In reply to Mel GormanAs there are more ALLOC_ flags that affect reserves, define what flags affect reserves and clarify the effect of each flag.
--- mm/internal.h | 3 +++ mm/page_alloc.c | 36 +++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-)
mm/internal.h +3 -0
@@ -757,6 +757,9 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_HIGHATOMIC 0x200/* Allows access to MIGRATE_HIGHATOMIC */ #define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ +/* Flags that allow allocations below the min watermark. */ +#define ALLOC_RESERVES (ALLOC_HARDER|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM) +enum ttu_flags ;struct tlbflush_unmap_batch ;
mm/page_alloc.c +23 -13
@@ -3944,15 +3944,14 @@ ALLOW_ERROR_INJECTION(should_fail_alloc_page, TRUE);static inline long __zone_watermark_unusable_free (struct zone *z,unsigned int order,unsigned int alloc_flags) { -const bool alloc_harder = (alloc_flags & (ALLOC_HARDER |ALLOC_OOM ));long unusable_free = (1 << order) -1 ;/* -* If the caller does not have rights to ALLOC_HARDER then subtract -* the high-atomic reserves. This will over-estimate the size of the -* atomic reserve but it avoids a search. +* If the caller does not have rights to reserves below the min +* watermark then subtract the high-atomic reserves. This will +* over-estimate the size of the atomic reserve but it avoids a search. */ -if (likely (!alloc_harder)) +if (likely (!(alloc_flags &ALLOC_RESERVES ))) unusable_free += z->nr_reserved_highatomic;#ifdef CONFIG_CMA
@@ -3976,25 +3975,36 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, {long min = mark;int o; -const bool alloc_harder = (alloc_flags & (ALLOC_HARDER |ALLOC_OOM ));/* free_pages may go negative - that's OK */ free_pages -=__zone_watermark_unusable_free (z, order, alloc_flags); -if (alloc_flags &ALLOC_MIN_RESERVE ) - min -= min /2 ; +if (alloc_flags &ALLOC_RESERVES ) { +/* +* __GFP_HIGH allows access to 50% of the min reserve as well +* as OOM. +*/ +if (alloc_flags &ALLOC_MIN_RESERVE ) + min -= min /2 ; -if (unlikely (alloc_harder)) {/* -* OOM victims can try even harder than normal ALLOC_HARDER +* Non-blocking allocations can access some of the reserve +* with more access if also __GFP_HIGH. The reasoning is that +* a non-blocking caller may incur a more severe penalty +* if it cannot get memory quickly, particularly if it's +* also __GFP_HIGH. +*/ +if (alloc_flags & (ALLOC_HARDER |ALLOC_HIGHATOMIC )) + min -= min /4 ; + +/* +* OOM victims can try even harder than the normal reserve * users on the grounds that it's definitely going to be in * the exit path shortly and free memory. Any allocation it * makes during the free path will be small and short-lived. */ if (alloc_flags &ALLOC_OOM ) min -= min /2 ; -else - min -= min /4 ; }/*
@@ -5293,7 +5303,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* could deplete whole memory reserves which would just make * the situation worse */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac);if (page) goto got_pg;
Signature · 1 line
2.35.3
Re: [PATCH 4/6] mm/page_alloc: Explicitly define what alloc flags deplete min reserves
Quoted 2 lines · Mel Gorman
As there are more
ALLOC_flags that affect reserves, define what flags affect reserves and clarify the effect of each flag.
Seems to me this does more than a clarification, but also some functional tweaks, so it could be helpful if those were spelled out in the changelog.
Quoted 46 lines
Signed-off-by Mel Gorman <[email protected]>--- mm/internal.h | 3 +++ mm/page_alloc.c | 36 +++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-)mm/internal.h +3
-0@@ -757,6 +757,9 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_HIGHATOMIC 0x200/* Allows access to MIGRATE_HIGHATOMIC */ #define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ +/* Flags that allow allocations below the min watermark. */ +#define ALLOC_RESERVES (ALLOC_HARDER|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM) +enum ttu_flags ;struct tlbflush_unmap_batch ;mm/page_alloc.c +4
-5@@ -3944,15 +3944,14 @@ ALLOW_ERROR_INJECTION(should_fail_alloc_page, TRUE);static inline long __zone_watermark_unusable_free (struct zone *z,unsigned int order,unsigned int alloc_flags) { -const bool alloc_harder = (alloc_flags & (ALLOC_HARDER |ALLOC_OOM ));long unusable_free = (1 << order) -1 ;/* -* If the caller does not have rights to ALLOC_HARDER then subtract -* the high-atomic reserves. This will over-estimate the size of the -* atomic reserve but it avoids a search. +* If the caller does not have rights to reserves below the min +* watermark then subtract the high-atomic reserves. This will +* over-estimate the size of the atomic reserve but it avoids a search. */ -if (likely (!alloc_harder)) +if (likely (!(alloc_flags &ALLOC_RESERVES ))) unusable_free += z->nr_reserved_highatomic;#ifdef CONFIG_CMA @@ -3976,25 +3975,36 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, {
mm/page_alloc.c bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 3982
Quoted 10 lines
mm/page_alloc.c +1
-3long min = mark;int o; -const bool alloc_harder = (alloc_flags & (ALLOC_HARDER |ALLOC_OOM ));/* free_pages may go negative - that's OK */ free_pages -=__zone_watermark_unusable_free (z, order, alloc_flags); -if (alloc_flags &ALLOC_MIN_RESERVE ) - min -= min /2 ; +if (alloc_flags &ALLOC_RESERVES ) {
Do we want to keep this unlikely() as alloc_harder did before?
Quoted 8 lines
mm/page_alloc.c +6
-1+/* +* __GFP_HIGH allows access to 50% of the min reserve as well +* as OOM. +*/ +if (alloc_flags &ALLOC_MIN_RESERVE ) + min -= min /2 ; -if (unlikely (alloc_harder)) {
mm/page_alloc.c bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 3998
Quoted 10 lines
mm/page_alloc.c +8
-1/* -* OOM victims can try even harder than normal ALLOC_HARDER +* Non-blocking allocations can access some of the reserve +* with more access if also __GFP_HIGH. The reasoning is that +* a non-blocking caller may incur a more severe penalty +* if it cannot get memory quickly, particularly if it's +* also __GFP_HIGH. +*/ +if (alloc_flags & (ALLOC_HARDER |ALLOC_HIGHATOMIC )) + min -= min /4 ;
For example this seems to change the allowed dip to reserves for ALLOC_HIGHATOMIC.
mm/page_alloc.c bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 4008
Quoted 12 lines
mm/page_alloc.c +3
-2+ +/* +* OOM victims can try even harder than the normal reserve * users on the grounds that it's definitely going to be in * the exit path shortly and free memory. Any allocation it * makes during the free path will be small and short-lived. */ if (alloc_flags &ALLOC_OOM ) min -= min /2 ; -else - min -= min /4 ; }
(noted that this patch doesn't seem to change the concern I raised in previous patch)
mm/page_alloc.c __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, · line 5306
Quoted 7 lines
mm/page_alloc.c +1
-1/* @@ -5293,7 +5303,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* could deplete whole memory reserves which would just make * the situation worse */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac);
And this AFAICS seems to give __GFP_NOFAIL 3/4 of min reserves instead of 1/4, which seems like a significant change (but hopefully ok) so worth noting at least.
Quoted 3 lines
mm/page_alloc.c +0
-0if (page) goto got_pg;
Re: [PATCH 4/6] mm/page_alloc: Explicitly define what alloc flags deplete min reserves
Quoted 7 lines · Vlastimil Babka
Quoted 2 lines · Mel Gorman
As there are more
ALLOC_flags that affect reserves, define what flags affect reserves and clarify the effect of each flag.Seems to me this does more than a clarification, but also some functional tweaks, so it could be helpful if those were spelled out in the changelog.
I will to take out the problematic parts that need clarification. There are two, one I'll drop and the other will be split. More details below.
Quoted 6 lines
Quoted 6 lines
(quoted diff) +0
-1@@ -3976,25 +3975,36 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, { long min = mark; int o; - const bool alloc_harder = (alloc_flags & (ALLOC_HARDER|ALLOC_OOM));
Quoted 9 lines
Review bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 3982
Quoted 6 lines
(quoted diff) +1
-2/* free_pages may go negative - that's OK */ free_pages -= __zone_watermark_unusable_free(z, order, alloc_flags); - if (alloc_flags & ALLOC_MIN_RESERVE) - min -= min / 2; + if (alloc_flags & ALLOC_RESERVES) {Do we want to keep this
unlikely()asalloc_harderdid before?
Added back in.
Quoted 7 lines
Quoted 7 lines
(quoted diff) +6
-0+ /* + * __GFP_HIGH allows access to 50% of the min reserve as well + * as OOM. + */ + if (alloc_flags & ALLOC_MIN_RESERVE) + min -= min / 2;
Quoted 15 lines
Review bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 3998
Quoted 11 lines
(quoted diff) +8
-2- if (unlikely(alloc_harder)) { /* - * OOM victims can try even harder than normal ALLOC_HARDER + * Non-blocking allocations can access some of the reserve + * with more access if also __GFP_HIGH. The reasoning is that + * a non-blocking caller may incur a more severe penalty + * if it cannot get memory quickly, particularly if it's + * also __GFP_HIGH. + */ + if (alloc_flags & (ALLOC_HARDER|ALLOC_HIGHATOMIC)) + min -= min / 4;For example this seems to change the allowed dip to reserves for
ALLOC_HIGHATOMIC.
You're right and this could cause problems. If high-order atomic allocation failures start appearing again, this change would help but it should be a standalone patch in response to a bug. I'll drop it for now.
Quoted 7 lines
Quoted 7 lines
(quoted diff) +3
-0+ + /* + * OOM victims can try even harder than the normal reserve * users on the grounds that it's definitely going to be in * the exit path shortly and free memory. Any allocation it * makes during the free path will be small and short-lived. */
Quoted 9 lines
Review bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, · line 4008
Quoted 5 lines
(quoted diff) +0
-2if (alloc_flags & ALLOC_OOM) min -= min / 2; - else - min -= min / 4; }(noted that this patch doesn't seem to change the concern I raised in previous patch)
This might be addressed now with the chjanges to the patch that caused you concerns about OOM handling.
Quoted 12 lines
Review __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, · line 5306
Quoted 7 lines
(quoted diff) +1
-1/*@@ -5293,7 +5303,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, * could deplete whole memory reserves which would just make * the situation worse */ - page = __alloc_pages_cpuset_fallback(gfp_mask, order, ALLOC_HARDER, ac); + page = __alloc_pages_cpuset_fallback(gfp_mask, order, ALLOC_MIN_RESERVE|ALLOC_HARDER, ac);And this AFAICS seems to give
__GFP_NOFAIL3/4 of min reserves instead of 1/4, which seems like a significant change (but hopefully ok) so worth noting at least.
It deserves a standalone patch. Below is the diff I intend to apply to this patch and the standalone patch.
mm/page_alloc.c +3 -3
@@ -3984,7 +3984,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,/* free_pages may go negative - that's OK */ free_pages -=__zone_watermark_unusable_free (z, order, alloc_flags); -if (alloc_flags &ALLOC_RESERVES ) { +if (unlikely (alloc_flags &ALLOC_RESERVES )) {/* * __GFP_HIGH allows access to 50% of the min reserve as well * as OOM.
@@ -3999,7 +3999,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,* if it cannot get memory quickly, particularly if it's * also __GFP_HIGH. */ -if (alloc_flags & (ALLOC_HARDER |ALLOC_HIGHATOMIC )) +if (alloc_flags &ALLOC_HARDER ) min -= min /4 ;/*
@@ -5308,7 +5308,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* could deplete whole memory reserves which would just make * the situation worse */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_HARDER , ac);if (page) goto got_pg;
The patch to allow __GFP_NOFAIL deeper access is this
--8<--mm/page_alloc.c: Allow __GFP_NOFAIL requests deeper access to reserves
Currently __GFP_NOFAIL allocations without any other flags can access 25% of the reserves but these requests imply that the system cannot make forward progress until the allocation succeeds. Allow __GFP_NOFAIL access to 75% of the min reserve.
--- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/page_alloc.c +1 -1
@@ -5308,7 +5308,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,* could deplete whole memory reserves which would just make * the situation worse */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac);if (page) goto got_pg;
PATCH 5/6 mm/page_alloc: Give GFP_ATOMIC and non-blocking allocations access to reserves
In reply to Mel GormanExplicit GFP_ATOMIC allocations get flagged ALLOC_HARDER which is a bit vague. In preparation for removing __GFP_ATOMIC, give GFP_ATOMIC and other non-blocking allocation requests equal access to reserve. Rename ALLOC_HARDER to ALLOC_NON_BLOCK to make it more clear what the flag means.
--- mm/internal.h | 7 +++++-- mm/page_alloc.c | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-)
mm/internal.h +5 -2
@@ -743,7 +743,10 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_OOM ALLOC_NO_WATERMARKS#endif -#define ALLOC_HARDER 0x10/* try to alloc harder */ +#define ALLOC_NON_BLOCK 0x10/* Caller cannot block. Allow access +* to 25% of the min watermark or +* 62.5% if __GFP_HIGH is set. +*/ #define ALLOC_MIN_RESERVE 0x20/* __GFP_HIGH set. Allow access to 50% * of the min watermark. */
@@ -758,7 +761,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ /* Flags that allow allocations below the min watermark. */ -#define ALLOC_RESERVES (ALLOC_HARDER|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM) +#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)enum ttu_flags ;struct tlbflush_unmap_batch ;
mm/page_alloc.c +13 -10
@@ -3994,7 +3994,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,* if it cannot get memory quickly, particularly if it's * also __GFP_HIGH. */ -if (alloc_flags & (ALLOC_HARDER |ALLOC_HIGHATOMIC )) +if (alloc_flags & (ALLOC_NON_BLOCK |ALLOC_HIGHATOMIC )) min -= min /4 ;/*
@@ -4846,28 +4846,30 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)* The caller may dip into page reserves a bit more if the caller * cannot run direct reclaim, or if the caller has realtime scheduling * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will -* set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_MIN_RESERVE(__GFP_HIGH). +* set both ALLOC_NON_BLOCK and ALLOC_MIN_RESERVE(__GFP_HIGH). */ alloc_flags |= (__force int ) (gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM)); -if (gfp_mask & __GFP_ATOMIC) { +if (!(gfp_mask & __GFP_RECLAIM)) {/* * Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ if (!(gfp_mask & __GFP_NOMEMALLOC)) { - alloc_flags |=ALLOC_HARDER ; + alloc_flags |=ALLOC_NON_BLOCK ;if (order >0 ) alloc_flags |=ALLOC_HIGHATOMIC ; }/* -* Ignore cpuset mems for GFP_ATOMIC rather than fail, see the -* comment for __cpuset_node_allowed(). +* Ignore cpuset mems for non-blocking __GFP_HIGH (probably +* GFP_ATOMIC) rather than fail, see the comment for +* __cpuset_node_allowed(). */ - alloc_flags &= ~ALLOC_CPUSET ; +if (alloc_flags &ALLOC_MIN_RESERVE ) + alloc_flags &= ~ALLOC_CPUSET ; }else if (unlikely (rt_task (current)) &&in_task ()) alloc_flags |=ALLOC_MIN_RESERVE ;
@@ -5299,11 +5301,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,/* * Help non-failing allocations by giving them access to memory -* reserves but do not use ALLOC_NO_WATERMARKS because this +* reserves normally used for high priority non-blocking +* allocations but do not use ALLOC_NO_WATERMARKS because this * could deplete whole memory reserves which would just make -* the situation worse +* the situation worse. */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_NON_BLOCK , ac);if (page) goto got_pg;
Signature · 1 line
2.35.3
Re: [PATCH 5/6] mm/page_alloc: Give GFP_ATOMIC and non-blocking allocations access to reserves
Quoted 52 lines · Mel Gorman
Explicit
GFP_ATOMICallocations get flaggedALLOC_HARDERwhich is a bit vague. In preparation for removing__GFP_ATOMIC, giveGFP_ATOMICand other non-blocking allocation requests equal access to reserve. RenameALLOC_HARDERtoALLOC_NON_BLOCKto make it more clear what the flag means.Signed-off-by Mel Gorman <[email protected]>--- mm/internal.h | 7 +++++-- mm/page_alloc.c | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-)mm/internal.h +5
-2@@ -743,7 +743,10 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_OOM ALLOC_NO_WATERMARKS#endif -#define ALLOC_HARDER 0x10/* try to alloc harder */ +#define ALLOC_NON_BLOCK 0x10/* Caller cannot block. Allow access +* to 25% of the min watermark or +* 62.5% if __GFP_HIGH is set. +*/ #define ALLOC_MIN_RESERVE 0x20/* __GFP_HIGH set. Allow access to 50% * of the min watermark. */ @@ -758,7 +761,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_KSWAPD 0x800/* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */ /* Flags that allow allocations below the min watermark. */ -#define ALLOC_RESERVES (ALLOC_HARDER|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM) +#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)enum ttu_flags ;struct tlbflush_unmap_batch ;mm/page_alloc.c +1
-1@@ -3994,7 +3994,7 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,* if it cannot get memory quickly, particularly if it's * also __GFP_HIGH. */ -if (alloc_flags & (ALLOC_HARDER |ALLOC_HIGHATOMIC )) +if (alloc_flags & (ALLOC_NON_BLOCK |ALLOC_HIGHATOMIC )) min -= min /4 ;/* @@ -4846,28 +4846,30 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)* The caller may dip into page reserves a bit more if the caller
mm/page_alloc.c gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order) · line 4854
Quoted 10 lines
mm/page_alloc.c +2
-2* cannot run direct reclaim, or if the caller has realtime scheduling * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will -* set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_MIN_RESERVE(__GFP_HIGH). +* set both ALLOC_NON_BLOCK and ALLOC_MIN_RESERVE(__GFP_HIGH). */ alloc_flags |= (__force int ) (gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM)); -if (gfp_mask & __GFP_ATOMIC) { +if (!(gfp_mask & __GFP_RECLAIM)) {
This is supposed to be __GFP_DIRECT_RECLAIM right? Otherwise that includes also __GFP_KSWAPD_RECLAIM and GFP_ATOMIC sets that one...
Quoted 41 lines
mm/page_alloc.c +10
-7/* * Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule. */ if (!(gfp_mask & __GFP_NOMEMALLOC)) { - alloc_flags |=ALLOC_HARDER ; + alloc_flags |=ALLOC_NON_BLOCK ;if (order >0 ) alloc_flags |=ALLOC_HIGHATOMIC ; }/* -* Ignore cpuset mems for GFP_ATOMIC rather than fail, see the -* comment for __cpuset_node_allowed(). +* Ignore cpuset mems for non-blocking __GFP_HIGH (probably +* GFP_ATOMIC) rather than fail, see the comment for +* __cpuset_node_allowed(). */ - alloc_flags &= ~ALLOC_CPUSET ; +if (alloc_flags &ALLOC_MIN_RESERVE ) + alloc_flags &= ~ALLOC_CPUSET ; }else if (unlikely (rt_task (current)) &&in_task ()) alloc_flags |=ALLOC_MIN_RESERVE ;@@ -5299,11 +5301,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,/* * Help non-failing allocations by giving them access to memory -* reserves but do not use ALLOC_NO_WATERMARKS because this +* reserves normally used for high priority non-blocking +* allocations but do not use ALLOC_NO_WATERMARKS because this * could deplete whole memory reserves which would just make -* the situation worse +* the situation worse. */ - page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_HARDER , ac); + page =__alloc_pages_cpuset_fallback (gfp_mask, order,ALLOC_MIN_RESERVE |ALLOC_NON_BLOCK , ac);if (page) goto got_pg;
Re: [PATCH 5/6] mm/page_alloc: Give GFP_ATOMIC and non-blocking allocations access to reserves
Quoted 11 lines · Vlastimil Babka
Quoted 10 lines · Mel Gorman
(quoted diff) +1
-1@@ -4846,28 +4846,30 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order) * The caller may dip into page reserves a bit more if the caller * cannot run direct reclaim, or if the caller has realtime scheduling * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will - * set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_MIN_RESERVE(__GFP_HIGH). + * set both ALLOC_NON_BLOCK and ALLOC_MIN_RESERVE(__GFP_HIGH). */ alloc_flags |= (__force int) (gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM));
Quoted 6 lines
Review gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order) · line 4854
Quoted 2 lines
(quoted diff) +1
-1- if (gfp_mask & __GFP_ATOMIC) { + if (!(gfp_mask & __GFP_RECLAIM)) {This is supposed to be
__GFP_DIRECT_RECLAIMright? Otherwise that includes also__GFP_KSWAPD_RECLAIMandGFP_ATOMICsets that one...
Yes
mm/page_alloc.c +1 -1
@@ -4856,7 +4856,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order) alloc_flags |= (__force int ) (gfp_mask & (__GFP_HIGH | __GFP_KSWAPD_RECLAIM)); -if (!(gfp_mask & __GFP_RECLAIM)) { +if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {/* * Not worth trying to allocate harder for __GFP_NOMEMALLOC even * if it can't schedule.
Signature · 2 lines
Mel Gorman SUSE Labs
PATCH 6/6 mm: discard __GFP_ATOMIC
In reply to Mel GormanFrom: NeilBrown <[email protected]>
__GFP_ATOMIC serves little purpose. Its main effect is to set ALLOC_HARDER which adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.
It is *always* paired with __GFP_HIGH which sets ALLOC_HIGH which also adjusts this watermark. It is probable that other users of __GFP_HIGH should benefit from the other little bonuses that __GFP_ATOMIC gets.
__GFP_ATOMIC also gives a warning if used with __GFP_DIRECT_RECLAIM. There is little point to this. We already get a might_sleep() warning if __GFP_DIRECT_RECLAIM is set.
__GFP_ATOMIC allows the "watermark_boost" to be side-stepped. It is probable that testing ALLOC_HARDER is a better fit here.
__GFP_ATOMIC is used by tegra-smmu.c to check if the allocation might sleep. This should test __GFP_DIRECT_RECLAIM instead.
This patch:
- removes __GFP_ATOMIC
- allows __GFP_HIGH allocations to ignore watermark boosting as well as GFP_ATOMIC requests.
- makes other adjustments as suggested by the above.
The net result is not change to GFP_ATOMIC allocations. Other allocations that use __GFP_HIGH will benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.
--- Documentation/mm/balance.rst | 2 +- drivers/iommu/tegra-smmu.c | 4 ++-- include/linux/gfp_types.h | 12 ++++-------- include/trace/events/mmflags.h | 1 - lib/test_printf.c | 8 ++++---- mm/internal.h | 2 +- mm/page_alloc.c | 13 +++---------- tools/perf/builtin-kmem.c | 1 - 8 files changed, 15 insertions(+), 28 deletions(-)
Documentation/mm/balance.rst +1 -1
@@ -6,7 +6,7 @@ Memory Balancing Started Jan 2000 by Kanoj Sarcar <[email protected]> -Memory balancing is needed for !__GFP_ATOMIC and !__GFP_KSWAPD_RECLAIM as +Memory balancing is needed for !__GFP_HIGH and !__GFP_KSWAPD_RECLAIM as well as for non __GFP_IO allocations. The first reason why a caller may avoid reclaim is that the caller can not
drivers/iommu/tegra-smmu.c +2 -2
@@ -671,12 +671,12 @@ static struct page *as_get_pde_page(struct tegra_smmu_as *as,* allocate page in a sleeping context if GFP flags permit. Hence * spinlock needs to be unlocked and re-locked after allocation. */ -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_unlock_irqrestore (&as->lock, *flags); page =alloc_page (gfp | __GFP_DMA | __GFP_ZERO); -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_lock_irqsave (&as->lock, *flags);/*
include/linux/gfp_types.h +4 -8
@@ -31,7 +31,7 @@ typedef unsigned int __bitwise gfp_t;#define ___GFP_IO 0x40u#define ___GFP_FS 0x80u#define ___GFP_ZERO 0x100u -#define ___GFP_ATOMIC 0x200u +/* 0x200u unused */ #define ___GFP_DIRECT_RECLAIM 0x400u#define ___GFP_KSWAPD_RECLAIM 0x800u#define ___GFP_WRITE 0x1000u
@@ -116,11 +116,8 @@ typedef unsigned int __bitwise gfp_t;* * %__GFP_HIGH indicates that the caller is high-priority and that granting * the request is necessary before the system can make forward progress. -* For example, creating an IO context to clean pages. -* -* %__GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is -* high priority. Users are typically interrupt handlers. This may be -* used in conjunction with %__GFP_HIGH +* For example creating an IO context to clean pages and requests +* from atomic context. * * %__GFP_MEMALLOC allows access to all memory. This should only be used when * the caller guarantees the allocation will allow more memory to be freed
@@ -135,7 +132,6 @@ typedef unsigned int __bitwise gfp_t;* %__GFP_NOMEMALLOC is used to explicitly forbid access to emergency reserves. * This takes precedence over the %__GFP_MEMALLOC flag if both are set. */ -#define __GFP_ATOMIC ((__force gfp_t)___GFP_ATOMIC)#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH)#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC)#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)
@@ -329,7 +325,7 @@ typedef unsigned int __bitwise gfp_t;* version does not attempt reclaim/compaction at all and is by default used * in page fault path, while the non-light is used by khugepaged. */ -#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) +#define GFP_ATOMIC (__GFP_HIGH|__GFP_KSWAPD_RECLAIM)#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)
include/trace/events/mmflags.h +0 -1
@@ -31,7 +31,6 @@gfpflag_string (__GFP_HIGHMEM), \gfpflag_string (GFP_DMA32 ), \gfpflag_string (__GFP_HIGH), \ -gfpflag_string (__GFP_ATOMIC), \gfpflag_string (__GFP_IO), \gfpflag_string (__GFP_FS), \ gfpflag_string(__GFP_NOWARN), \
lib/test_printf.c +4 -4
@@ -686,17 +686,17 @@ flags(void) gfp =GFP_ATOMIC |__GFP_DMA;test ("GFP_ATOMIC|GFP_DMA" ,"%pGg" , &gfp); - gfp = __GFP_ATOMIC; -test ("__GFP_ATOMIC" ,"%pGg" , &gfp); + gfp = __GFP_HIGH; +test ("__GFP_HIGH" ,"%pGg" , &gfp);/* Any flags not translated by the table should remain numeric */ gfp = ~__GFP_BITS_MASK;snprintf (cmp_buffer,BUF_SIZE ,"%#lx" , (unsigned long ) gfp);test (cmp_buffer,"%pGg" , &gfp); -snprintf (cmp_buffer,BUF_SIZE ,"__GFP_ATOMIC|%#lx" , +snprintf (cmp_buffer,BUF_SIZE ,"__GFP_HIGH|%#lx" , (unsigned long ) gfp); - gfp |= __GFP_ATOMIC; + gfp |= __GFP_HIGH;test (cmp_buffer,"%pGg" , &gfp);kfree (cmp_buffer);
mm/internal.h +1 -1
@@ -24,7 +24,7 @@ struct folio_batch;#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\ __GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\ __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\ - __GFP_ATOMIC|__GFP_NOLOCKDEP) + __GFP_NOLOCKDEP)/* The GFP flags allowed during early boot */ #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))
mm/page_alloc.c +3 -10
@@ -4081,13 +4081,14 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,if (__zone_watermark_ok (z, order, mark, highest_zoneidx, alloc_flags, free_pages))return true; +/* -* Ignore watermark boosting for GFP_ATOMIC order-0 allocations +* Ignore watermark boosting for GFP_HIGH order-0 allocations * when checking the min watermark. The min watermark is the * point where boosting is ignored so that kswapd is woken up * when below the low watermark. */ -if (unlikely (!order && (gfp_mask & __GFP_ATOMIC) && z->watermark_boost +if (unlikely (!order && (alloc_flags &ALLOC_MIN_RESERVE ) && z->watermark_boost && ((alloc_flags &ALLOC_WMARK_MASK ) ==WMARK_MIN ))) { mark = z->_watermark[WMARK_MIN ]; return __zone_watermark_ok(z, order, mark, highest_zoneidx,
@@ -5052,14 +5053,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,unsigned int zonelist_iter_cookie;int reserve_flags; -/* -* We also sanity check to catch abuse of atomic reserves being used by -* callers that are not in atomic context. -*/ -if (WARN_ON_ONCE ((gfp_mask & (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) == - (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM))) - gfp_mask &= ~__GFP_ATOMIC; - restart: compaction_retries =0 ; no_progress_loops =0 ;
tools/perf/builtin-kmem.c +0 -1
@@ -640,7 +640,6 @@ static const struct { { "__GFP_HIGHMEM", "HM" }, { "GFP_DMA32", "D32" }, { "__GFP_HIGH", "H" }, - { "__GFP_ATOMIC", "_A" }, { "__GFP_IO", "I" }, { "__GFP_FS", "F" }, { "__GFP_NOWARN", "NWR" },
Signature · 1 line
2.35.3
Re: [PATCH 6/6] mm: discard __GFP_ATOMIC
Quoted 38 lines · Mel Gorman
From: NeilBrown <[email protected]>
__GFP_ATOMICserves little purpose. Its main effect is to setALLOC_HARDERwhich adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.It is *always* paired with
__GFP_HIGHwhich setsALLOC_HIGHwhich also adjusts this watermark. It is probable that other users of__GFP_HIGHshould benefit from the other little bonuses that__GFP_ATOMICgets.
__GFP_ATOMICalso gives a warning if used with__GFP_DIRECT_RECLAIM. There is little point to this. We already get amight_sleep()warning if__GFP_DIRECT_RECLAIMis set.
__GFP_ATOMICallows the "watermark_boost" to be side-stepped. It is probable that testingALLOC_HARDERis a better fit here.
__GFP_ATOMICis used bytegra-smmu.cto check if the allocation might sleep. This should test__GFP_DIRECT_RECLAIMinstead.This patch:
- removes__GFP_ATOMIC
- allows__GFP_HIGHallocations to ignore watermark boosting as well asGFP_ATOMICrequests.
- makes other adjustments as suggested by the above.The net result is not change to
GFP_ATOMICallocations. Other allocations that use__GFP_HIGHwill benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.
Quoted 4 lines
[mgorman: Minor adjustments to rework on top of a series]Signed-off-by NeilBrown <[email protected]>Signed-off-by Mel Gorman <[email protected]>
Just a nit below.
mm/page_alloc.c static inline bool zone_watermark_fast(struct zone *z, unsigned int order, · line 4086
Quoted 10 lines
mm/page_alloc.c +2
-1@@ -4081,13 +4081,14 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,if (__zone_watermark_ok (z, order, mark, highest_zoneidx, alloc_flags, free_pages))return true; +/* -* Ignore watermark boosting for GFP_ATOMIC order-0 allocations +* Ignore watermark boosting for GFP_HIGH order-0 allocations
There's no GFP_HIGH. We could either keep GFP_ATOMIC here if we want to talk about the high-level flag combo, or __GFP_HIGH if about the low-level detail. We're deep in the page allocator implementation so the latter would be OK.
Quoted 6 lines
mm/page_alloc.c +1
-1* when checking the min watermark. The min watermark is the * point where boosting is ignored so that kswapd is woken up * when below the low watermark. */ - if (unlikely(!order && (gfp_mask & __GFP_ATOMIC) && z->watermark_boost + if (unlikely(!order && (alloc_flags & ALLOC_MIN_RESERVE) && z->watermark_boost
Re: [PATCH 6/6] mm: discard __GFP_ATOMIC
Quoted 5 lines · Vlastimil Babka
Quoted 5 lines
mm/page_alloc.c +1
-0@@ -4081,13 +4081,14 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,if (__zone_watermark_ok (z, order, mark, highest_zoneidx, alloc_flags, free_pages))return true; +
Quoted 9 lines
mm/page_alloc.c static inline bool zone_watermark_fast(struct zone *z, unsigned int order, · line 4086
Quoted 3 lines
mm/page_alloc.c +1
-1/* -* Ignore watermark boosting for GFP_ATOMIC order-0 allocations +* Ignore watermark boosting for GFP_HIGH order-0 allocations There's no
GFP_HIGH. We could either keepGFP_ATOMIChere if we want to talk about the high-level flag combo, or__GFP_HIGHif about the low-level detail. We're deep in the page allocator implementation so the latter would be OK.
Fixed
Signature · 2 lines
Mel Gorman SUSE Labs
Mike Rapoport
reviewerRe: [PATCH 6/6] mm: discard __GFP_ATOMIC
In reply to Mel GormanHi Mel,
Quoted 38 lines · Mel Gorman
From: NeilBrown <[email protected]>
__GFP_ATOMICserves little purpose. Its main effect is to setALLOC_HARDERwhich adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.It is *always* paired with
__GFP_HIGHwhich setsALLOC_HIGHwhich also adjusts this watermark. It is probable that other users of__GFP_HIGHshould benefit from the other little bonuses that__GFP_ATOMICgets.
__GFP_ATOMICalso gives a warning if used with__GFP_DIRECT_RECLAIM. There is little point to this. We already get amight_sleep()warning if__GFP_DIRECT_RECLAIMis set.
__GFP_ATOMICallows the "watermark_boost" to be side-stepped. It is probable that testingALLOC_HARDERis a better fit here.
__GFP_ATOMICis used bytegra-smmu.cto check if the allocation might sleep. This should test__GFP_DIRECT_RECLAIMinstead.This patch:
- removes__GFP_ATOMIC
- allows__GFP_HIGHallocations to ignore watermark boosting as well asGFP_ATOMICrequests.
- makes other adjustments as suggested by the above.The net result is not change to
GFP_ATOMICallocations. Other allocations that use__GFP_HIGHwill benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.
Quoted 6 lines
[mgorman: Minor adjustments to rework on top of a series]Signed-off-by NeilBrown <[email protected]>Signed-off-by Mel Gorman <[email protected]>--- Documentation/mm/balance.rst | 2 +-
Documentation/core-api/memory-allocation.rst needs an update as well, and there are other mentions of GFP_ATOMIC in Documentation/
Quoted 188 lines
drivers/iommu/tegra-smmu.c | 4 ++-- include/linux/gfp_types.h | 12 ++++-------- include/trace/events/mmflags.h | 1 - lib/test_printf.c | 8 ++++---- mm/internal.h | 2 +- mm/page_alloc.c | 13 +++---------- tools/perf/builtin-kmem.c | 1 - 8 files changed, 15 insertions(+), 28 deletions(-)Documentation/mm/balance.rst +1
-1@@ -6,7 +6,7 @@ Memory Balancing Started Jan 2000 by Kanoj Sarcar <[email protected]> -Memory balancing is needed for !__GFP_ATOMIC and !__GFP_KSWAPD_RECLAIM as +Memory balancing is needed for !__GFP_HIGH and !__GFP_KSWAPD_RECLAIM as well as for non __GFP_IO allocations. The first reason why a caller may avoid reclaim is that the caller can notdrivers/iommu/tegra-smmu.c +2
-2@@ -671,12 +671,12 @@ static struct page *as_get_pde_page(struct tegra_smmu_as *as,* allocate page in a sleeping context if GFP flags permit. Hence * spinlock needs to be unlocked and re-locked after allocation. */ -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_unlock_irqrestore (&as->lock, *flags); page =alloc_page (gfp | __GFP_DMA | __GFP_ZERO); -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_lock_irqsave (&as->lock, *flags);/* include/linux/gfp_types.h +4
-8@@ -31,7 +31,7 @@ typedef unsigned int __bitwise gfp_t;#define ___GFP_IO 0x40u#define ___GFP_FS 0x80u#define ___GFP_ZERO 0x100u -#define ___GFP_ATOMIC 0x200u +/* 0x200u unused */ #define ___GFP_DIRECT_RECLAIM 0x400u#define ___GFP_KSWAPD_RECLAIM 0x800u#define ___GFP_WRITE 0x1000u@@ -116,11 +116,8 @@ typedef unsigned int __bitwise gfp_t;* * %__GFP_HIGH indicates that the caller is high-priority and that granting * the request is necessary before the system can make forward progress. -* For example, creating an IO context to clean pages. -* -* %__GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is -* high priority. Users are typically interrupt handlers. This may be -* used in conjunction with %__GFP_HIGH +* For example creating an IO context to clean pages and requests +* from atomic context. * * %__GFP_MEMALLOC allows access to all memory. This should only be used when * the caller guarantees the allocation will allow more memory to be freed @@ -135,7 +132,6 @@ typedef unsigned int __bitwise gfp_t;* %__GFP_NOMEMALLOC is used to explicitly forbid access to emergency reserves. * This takes precedence over the %__GFP_MEMALLOC flag if both are set. */ -#define __GFP_ATOMIC ((__force gfp_t)___GFP_ATOMIC)#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH)#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC)#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)@@ -329,7 +325,7 @@ typedef unsigned int __bitwise gfp_t;* version does not attempt reclaim/compaction at all and is by default used * in page fault path, while the non-light is used by khugepaged. */ -#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) +#define GFP_ATOMIC (__GFP_HIGH|__GFP_KSWAPD_RECLAIM)#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)include/trace/events/mmflags.h +0
-1@@ -31,7 +31,6 @@gfpflag_string (__GFP_HIGHMEM), \gfpflag_string (GFP_DMA32 ), \gfpflag_string (__GFP_HIGH), \ -gfpflag_string (__GFP_ATOMIC), \gfpflag_string (__GFP_IO), \gfpflag_string (__GFP_FS), \ gfpflag_string(__GFP_NOWARN), \lib/test_printf.c +4
-4@@ -686,17 +686,17 @@ flags(void) gfp =GFP_ATOMIC |__GFP_DMA;test ("GFP_ATOMIC|GFP_DMA" ,"%pGg" , &gfp); - gfp = __GFP_ATOMIC; -test ("__GFP_ATOMIC" ,"%pGg" , &gfp); + gfp = __GFP_HIGH; +test ("__GFP_HIGH" ,"%pGg" , &gfp);/* Any flags not translated by the table should remain numeric */ gfp = ~__GFP_BITS_MASK;snprintf (cmp_buffer,BUF_SIZE ,"%#lx" , (unsigned long ) gfp);test (cmp_buffer,"%pGg" , &gfp); -snprintf (cmp_buffer,BUF_SIZE ,"__GFP_ATOMIC|%#lx" , +snprintf (cmp_buffer,BUF_SIZE ,"__GFP_HIGH|%#lx" , (unsigned long ) gfp); - gfp |= __GFP_ATOMIC; + gfp |= __GFP_HIGH;test (cmp_buffer,"%pGg" , &gfp);kfree (cmp_buffer);mm/internal.h +1
-1@@ -24,7 +24,7 @@ struct folio_batch;#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\ __GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\ __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\ - __GFP_ATOMIC|__GFP_NOLOCKDEP) + __GFP_NOLOCKDEP)/* The GFP flags allowed during early boot */ #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))mm/page_alloc.c +3
-10@@ -4081,13 +4081,14 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,if (__zone_watermark_ok (z, order, mark, highest_zoneidx, alloc_flags, free_pages))return true; +/* -* Ignore watermark boosting for GFP_ATOMIC order-0 allocations +* Ignore watermark boosting for GFP_HIGH order-0 allocations * when checking the min watermark. The min watermark is the * point where boosting is ignored so that kswapd is woken up * when below the low watermark. */ -if (unlikely (!order && (gfp_mask & __GFP_ATOMIC) && z->watermark_boost +if (unlikely (!order && (alloc_flags &ALLOC_MIN_RESERVE ) && z->watermark_boost && ((alloc_flags &ALLOC_WMARK_MASK ) ==WMARK_MIN ))) { mark = z->_watermark[WMARK_MIN ]; return __zone_watermark_ok(z, order, mark, highest_zoneidx,@@ -5052,14 +5053,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,unsigned int zonelist_iter_cookie;int reserve_flags; -/* -* We also sanity check to catch abuse of atomic reserves being used by -* callers that are not in atomic context. -*/ -if (WARN_ON_ONCE ((gfp_mask & (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) == - (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM))) - gfp_mask &= ~__GFP_ATOMIC; - restart: compaction_retries =0 ; no_progress_loops =0 ;tools/perf/builtin-kmem.c +0
-1@@ -640,7 +640,6 @@ static const struct { { "__GFP_HIGHMEM", "HM" }, { "GFP_DMA32", "D32" }, { "__GFP_HIGH", "H" }, - { "__GFP_ATOMIC", "_A" }, { "__GFP_IO", "I" }, { "__GFP_FS", "F" }, { "__GFP_NOWARN", "NWR" },Signature · 1 line
2.35.3
Signature · 2 lines
Sincerely yours, Mike.
Re: [PATCH 6/6] mm: discard __GFP_ATOMIC
Quoted 48 lines · Mike Rapoport
Hi Mel,
Quoted 38 lines · Mel Gorman
From: NeilBrown <[email protected]>
__GFP_ATOMICserves little purpose. Its main effect is to setALLOC_HARDERwhich adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.It is *always* paired with
__GFP_HIGHwhich setsALLOC_HIGHwhich also adjusts this watermark. It is probable that other users of__GFP_HIGHshould benefit from the other little bonuses that__GFP_ATOMICgets.
__GFP_ATOMICalso gives a warning if used with__GFP_DIRECT_RECLAIM. There is little point to this. We already get amight_sleep()warning if__GFP_DIRECT_RECLAIMis set.
__GFP_ATOMICallows the "watermark_boost" to be side-stepped. It is probable that testingALLOC_HARDERis a better fit here.
__GFP_ATOMICis used bytegra-smmu.cto check if the allocation might sleep. This should test__GFP_DIRECT_RECLAIMinstead.This patch:
- removes__GFP_ATOMIC
- allows__GFP_HIGHallocations to ignore watermark boosting as well asGFP_ATOMICrequests.
- makes other adjustments as suggested by the above.The net result is not change to
GFP_ATOMICallocations. Other allocations that use__GFP_HIGHwill benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.Quoted 6 lines
[mgorman: Minor adjustments to rework on top of a series]Signed-off-by NeilBrown <[email protected]>Signed-off-by Mel Gorman <[email protected]>--- Documentation/mm/balance.rst | 2 +-
Quoted 2 lines
Documentation/core-api/memory-allocation.rstneeds an update as well, and there are other mentions ofGFP_ATOMICinDocumentation/
Note that this patch removes __GFP_ATOMIC, but does not change the behaviour of GFP_ATOMIC. So I don't believe there is any other documentation that need changing.
Thanks,
NeilBrown
Quoted 194 lines
Quoted 189 lines
drivers/iommu/tegra-smmu.c | 4 ++-- include/linux/gfp_types.h | 12 ++++-------- include/trace/events/mmflags.h | 1 - lib/test_printf.c | 8 ++++---- mm/internal.h | 2 +- mm/page_alloc.c | 13 +++---------- tools/perf/builtin-kmem.c | 1 - 8 files changed, 15 insertions(+), 28 deletions(-)Documentation/mm/balance.rst +1
-1@@ -6,7 +6,7 @@ Memory Balancing Started Jan 2000 by Kanoj Sarcar <[email protected]> -Memory balancing is needed for !__GFP_ATOMIC and !__GFP_KSWAPD_RECLAIM as +Memory balancing is needed for !__GFP_HIGH and !__GFP_KSWAPD_RECLAIM as well as for non __GFP_IO allocations. The first reason why a caller may avoid reclaim is that the caller can notdrivers/iommu/tegra-smmu.c +2
-2@@ -671,12 +671,12 @@ static struct page *as_get_pde_page(struct tegra_smmu_as *as,* allocate page in a sleeping context if GFP flags permit. Hence * spinlock needs to be unlocked and re-locked after allocation. */ -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_unlock_irqrestore (&as->lock, *flags); page =alloc_page (gfp | __GFP_DMA | __GFP_ZERO); -if (!(gfp & __GFP_ATOMIC)) +if (gfpflags_allow_blocking (gfp))spin_lock_irqsave (&as->lock, *flags);/* include/linux/gfp_types.h +4
-8@@ -31,7 +31,7 @@ typedef unsigned int __bitwise gfp_t;#define ___GFP_IO 0x40u#define ___GFP_FS 0x80u#define ___GFP_ZERO 0x100u -#define ___GFP_ATOMIC 0x200u +/* 0x200u unused */ #define ___GFP_DIRECT_RECLAIM 0x400u#define ___GFP_KSWAPD_RECLAIM 0x800u#define ___GFP_WRITE 0x1000u@@ -116,11 +116,8 @@ typedef unsigned int __bitwise gfp_t;* * %__GFP_HIGH indicates that the caller is high-priority and that granting * the request is necessary before the system can make forward progress. -* For example, creating an IO context to clean pages. -* -* %__GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is -* high priority. Users are typically interrupt handlers. This may be -* used in conjunction with %__GFP_HIGH +* For example creating an IO context to clean pages and requests +* from atomic context. * * %__GFP_MEMALLOC allows access to all memory. This should only be used when * the caller guarantees the allocation will allow more memory to be freed @@ -135,7 +132,6 @@ typedef unsigned int __bitwise gfp_t;* %__GFP_NOMEMALLOC is used to explicitly forbid access to emergency reserves. * This takes precedence over the %__GFP_MEMALLOC flag if both are set. */ -#define __GFP_ATOMIC ((__force gfp_t)___GFP_ATOMIC)#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH)#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC)#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC)@@ -329,7 +325,7 @@ typedef unsigned int __bitwise gfp_t;* version does not attempt reclaim/compaction at all and is by default used * in page fault path, while the non-light is used by khugepaged. */ -#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) +#define GFP_ATOMIC (__GFP_HIGH|__GFP_KSWAPD_RECLAIM)#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)include/trace/events/mmflags.h +0
-1@@ -31,7 +31,6 @@gfpflag_string (__GFP_HIGHMEM), \gfpflag_string (GFP_DMA32 ), \gfpflag_string (__GFP_HIGH), \ -gfpflag_string (__GFP_ATOMIC), \gfpflag_string (__GFP_IO), \gfpflag_string (__GFP_FS), \ gfpflag_string(__GFP_NOWARN), \lib/test_printf.c +4
-4@@ -686,17 +686,17 @@ flags(void) gfp =GFP_ATOMIC |__GFP_DMA;test ("GFP_ATOMIC|GFP_DMA" ,"%pGg" , &gfp); - gfp = __GFP_ATOMIC; -test ("__GFP_ATOMIC" ,"%pGg" , &gfp); + gfp = __GFP_HIGH; +test ("__GFP_HIGH" ,"%pGg" , &gfp);/* Any flags not translated by the table should remain numeric */ gfp = ~__GFP_BITS_MASK;snprintf (cmp_buffer,BUF_SIZE ,"%#lx" , (unsigned long ) gfp);test (cmp_buffer,"%pGg" , &gfp); -snprintf (cmp_buffer,BUF_SIZE ,"__GFP_ATOMIC|%#lx" , +snprintf (cmp_buffer,BUF_SIZE ,"__GFP_HIGH|%#lx" , (unsigned long ) gfp); - gfp |= __GFP_ATOMIC; + gfp |= __GFP_HIGH;test (cmp_buffer,"%pGg" , &gfp);kfree (cmp_buffer);mm/internal.h +1
-1@@ -24,7 +24,7 @@ struct folio_batch;#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\ __GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\ __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\ - __GFP_ATOMIC|__GFP_NOLOCKDEP) + __GFP_NOLOCKDEP)/* The GFP flags allowed during early boot */ #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))mm/page_alloc.c +3
-10@@ -4081,13 +4081,14 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,if (__zone_watermark_ok (z, order, mark, highest_zoneidx, alloc_flags, free_pages))return true; +/* -* Ignore watermark boosting for GFP_ATOMIC order-0 allocations +* Ignore watermark boosting for GFP_HIGH order-0 allocations * when checking the min watermark. The min watermark is the * point where boosting is ignored so that kswapd is woken up * when below the low watermark. */ -if (unlikely (!order && (gfp_mask & __GFP_ATOMIC) && z->watermark_boost +if (unlikely (!order && (alloc_flags &ALLOC_MIN_RESERVE ) && z->watermark_boost && ((alloc_flags &ALLOC_WMARK_MASK ) ==WMARK_MIN ))) { mark = z->_watermark[WMARK_MIN ]; return __zone_watermark_ok(z, order, mark, highest_zoneidx,@@ -5052,14 +5053,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,unsigned int zonelist_iter_cookie;int reserve_flags; -/* -* We also sanity check to catch abuse of atomic reserves being used by -* callers that are not in atomic context. -*/ -if (WARN_ON_ONCE ((gfp_mask & (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) == - (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM))) - gfp_mask &= ~__GFP_ATOMIC; - restart: compaction_retries =0 ; no_progress_loops =0 ;tools/perf/builtin-kmem.c +0
-1@@ -640,7 +640,6 @@ static const struct { { "__GFP_HIGHMEM", "HM" }, { "GFP_DMA32", "D32" }, { "__GFP_HIGH", "H" }, - { "__GFP_ATOMIC", "_A" }, { "__GFP_IO", "I" }, { "__GFP_FS", "F" }, { "__GFP_NOWARN", "NWR" },Signature · 1 line
2.35.3Signature · 2 lines
Sincerely yours, Mike.
Re: [PATCH 6/6] mm: discard __GFP_ATOMIC
In reply to Mike RapoportQuoted 48 lines · Mike Rapoport
Hi Mel,
Quoted 38 lines · Mel Gorman
From: NeilBrown <[email protected]>
__GFP_ATOMICserves little purpose. Its main effect is to setALLOC_HARDERwhich adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.It is *always* paired with
__GFP_HIGHwhich setsALLOC_HIGHwhich also adjusts this watermark. It is probable that other users of__GFP_HIGHshould benefit from the other little bonuses that__GFP_ATOMICgets.
__GFP_ATOMICalso gives a warning if used with__GFP_DIRECT_RECLAIM. There is little point to this. We already get amight_sleep()warning if__GFP_DIRECT_RECLAIMis set.
__GFP_ATOMICallows the "watermark_boost" to be side-stepped. It is probable that testingALLOC_HARDERis a better fit here.
__GFP_ATOMICis used bytegra-smmu.cto check if the allocation might sleep. This should test__GFP_DIRECT_RECLAIMinstead.This patch:
- removes__GFP_ATOMIC
- allows__GFP_HIGHallocations to ignore watermark boosting as well asGFP_ATOMICrequests.
- makes other adjustments as suggested by the above.The net result is not change to
GFP_ATOMICallocations. Other allocations that use__GFP_HIGHwill benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.Quoted 6 lines
[mgorman: Minor adjustments to rework on top of a series]Signed-off-by NeilBrown <[email protected]>Signed-off-by Mel Gorman <[email protected]>--- Documentation/mm/balance.rst | 2 +-
Quoted 3 lines
Documentation/core-api/memory-allocation.rstneeds an update as well, and there are other mentions ofGFP_ATOMICinDocumentation/
What part do you think needs updating in that file?
There are two references to GFP_ATOMIC in that file, one about accessing reserves and another about non-sleeping allocations and the accuracy does not change after the series. If anything, this statement should change because it invites GFP_ATOMIC abuse for spurious reasons
* If you think that accessing memory reserves is justified and the kernel will be stressed unless allocation succeeds, you may use ``GFP_ATOMIC``.
There are other references to GFP_ATOMIC in Documentation/ that are are a little inaccurate but not in a way that is harmful and is not changed by the series. For example;
GFP_ATOMIC requests are kernel internal allocations that must be satisfied, immediately. The kernel may drop some request, in rare cases even panic, if a GFP_ATOMIC alloc fails.
This is a stronger statement than GFP_ATOMIC deserves but it's close enough in the given context.
Signature · 2 lines
Mel Gorman SUSE Labs
Mike Rapoport
reviewerRe: [PATCH 6/6] mm: discard __GFP_ATOMIC
Quoted 53 lines · Mel Gorman
Quoted 48 lines · Mike Rapoport
Hi Mel,
Quoted 38 lines · Mel Gorman
From: NeilBrown <[email protected]>
__GFP_ATOMICserves little purpose. Its main effect is to setALLOC_HARDERwhich adds a few little boosts to increase the chance of an allocation succeeding, one of which is to lower the water-mark at which it will succeed.It is *always* paired with
__GFP_HIGHwhich setsALLOC_HIGHwhich also adjusts this watermark. It is probable that other users of__GFP_HIGHshould benefit from the other little bonuses that__GFP_ATOMICgets.
__GFP_ATOMICalso gives a warning if used with__GFP_DIRECT_RECLAIM. There is little point to this. We already get amight_sleep()warning if__GFP_DIRECT_RECLAIMis set.
__GFP_ATOMICallows the "watermark_boost" to be side-stepped. It is probable that testingALLOC_HARDERis a better fit here.
__GFP_ATOMICis used bytegra-smmu.cto check if the allocation might sleep. This should test__GFP_DIRECT_RECLAIMinstead.This patch:
- removes__GFP_ATOMIC
- allows__GFP_HIGHallocations to ignore watermark boosting as well asGFP_ATOMICrequests.
- makes other adjustments as suggested by the above.The net result is not change to
GFP_ATOMICallocations. Other allocations that use__GFP_HIGHwill benefit from a few different extra privileges. This affects:
xen, dm, md, ntfs3
the vermillion frame buffer
hibernation
ksm
swap
all of which likely produce more benefit than cost if these selected allocation are more likely to succeed quickly.Quoted 6 lines
[mgorman: Minor adjustments to rework on top of a series]Signed-off-by NeilBrown <[email protected]>Signed-off-by Mel Gorman <[email protected]>--- Documentation/mm/balance.rst | 2 +-Quoted 3 lines
Documentation/core-api/memory-allocation.rstneeds an update as well, and there are other mentions ofGFP_ATOMICinDocumentation/
Quoted 5 lines
What part do you think needs updating in that file?
There are two references to
GFP_ATOMICin that file, one about accessing reserves and another about non-sleeping allocations and the accuracy does not change after the series.
You are right, I got confused.
Quoted 5 lines
If anything, this statement should change because it invites
GFP_ATOMICabuse for spurious reasons* If you think that accessing memory reserves is justified and the kernel will be stressed unless allocation succeeds, you may use ``GFP_ATOMIC``.
Care to send a patch? ;-)
Quoted 15 lines
There are other references to
GFP_ATOMICinDocumentation/that are are a little inaccurate but not in a way that is harmful and is not changed by the series. For example;
GFP_ATOMICrequests are kernel internal allocations that must be satisfied, immediately. The kernel may drop some request, in rare cases even panic, if aGFP_ATOMICalloc fails.This is a stronger statement than
GFP_ATOMICdeserves but it's close enough in the given context.Signature · 2 lines
Mel Gorman SUSE Labs
Signature · 2 lines
Sincerely yours, Mike.