diff mbox

[10/12] mm: page_alloc: emergency reserve access for __GFP_NOFAIL allocations

Message ID 1427264236-17249-11-git-send-email-hannes@cmpxchg.org (mailing list archive)
State New, archived
Headers show

Commit Message

Johannes Weiner March 25, 2015, 6:17 a.m. UTC
__GFP_NOFAIL allocations can deadlock the OOM killer when they're
holding locks that the OOM victim might need to exit.  When that
happens the allocation may never complete, which has disastrous
effects on things like in-flight filesystem transactions.

When the system is OOM, allow __GFP_NOFAIL allocations to dip into the
emergency reserves in the hope that this will allow transactions and
writeback to complete and the deadlock can be avoided.

Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Suggested-by: Andrea Arcangeli <aarcange@redhat.com>
---
 mm/page_alloc.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

Comments

Michal Hocko April 14, 2015, 4:55 p.m. UTC | #1
On Wed 25-03-15 02:17:14, Johannes Weiner wrote:
> __GFP_NOFAIL allocations can deadlock the OOM killer when they're
> holding locks that the OOM victim might need to exit.  When that
> happens the allocation may never complete, which has disastrous
> effects on things like in-flight filesystem transactions.
> 
> When the system is OOM, allow __GFP_NOFAIL allocations to dip into the
> emergency reserves in the hope that this will allow transactions and
> writeback to complete and the deadlock can be avoided.

This one slipped through. Sorry.

> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
> Suggested-by: Andrea Arcangeli <aarcange@redhat.com>

Acked-by: Michal Hocko <mhocko@suse.cz>

> ---
>  mm/page_alloc.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 3c165016175d..832ad1c7cd4f 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2403,9 +2403,17 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, int alloc_flags,
>  	 * from exiting.  While allocations can use OOM kills to free
>  	 * memory, they can not necessarily rely on their *own* kills
>  	 * to make forward progress.
> +	 *
> +	 * This last point is crucial for __GFP_NOFAIL allocations.
> +	 * Since they can't quit, they might actually deadlock, so
> +	 * give them hail mary access to the emergency reserves.
>  	 */
> -	alloc_flags &= ~ALLOC_WMARK_MASK;
> -	alloc_flags |= ALLOC_WMARK_OOM;
> +	if (gfp_mask & __GFP_NOFAIL) {
> +		alloc_flags |= ALLOC_NO_WATERMARKS;
> +	} else {
> +		alloc_flags &= ~ALLOC_WMARK_MASK;
> +		alloc_flags |= ALLOC_WMARK_OOM;
> +	}
>  out:
>  	mutex_unlock(&oom_lock);
>  alloc:
> -- 
> 2.3.3
>
diff mbox

Patch

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3c165016175d..832ad1c7cd4f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2403,9 +2403,17 @@  __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, int alloc_flags,
 	 * from exiting.  While allocations can use OOM kills to free
 	 * memory, they can not necessarily rely on their *own* kills
 	 * to make forward progress.
+	 *
+	 * This last point is crucial for __GFP_NOFAIL allocations.
+	 * Since they can't quit, they might actually deadlock, so
+	 * give them hail mary access to the emergency reserves.
 	 */
-	alloc_flags &= ~ALLOC_WMARK_MASK;
-	alloc_flags |= ALLOC_WMARK_OOM;
+	if (gfp_mask & __GFP_NOFAIL) {
+		alloc_flags |= ALLOC_NO_WATERMARKS;
+	} else {
+		alloc_flags &= ~ALLOC_WMARK_MASK;
+		alloc_flags |= ALLOC_WMARK_OOM;
+	}
 out:
 	mutex_unlock(&oom_lock);
 alloc: