diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 767bac135787..5df2c08e2720 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -569,7 +569,8 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
 static inline enum oom_status task_in_memcg_oom_set(struct task_struct *p,
 						    struct mem_cgroup *memcg,
 						    gfp_t mask,
-						    int order)
+						    int order,
+						    bool force)
 {
 	if (!current->in_user_fault)
 		return OOM_SKIPPED;
@@ -578,6 +579,8 @@ static inline enum oom_status task_in_memcg_oom_set(struct task_struct *p,
 	p->memcg_in_oom = memcg;
 	p->memcg_oom_gfp_mask = mask;
 	p->memcg_oom_order = order;
+	if (force)
+		p->memcg_oom_wait = true;
 
 	return OOM_ASYNC;
 }
@@ -1051,7 +1054,8 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
 static inline enum oom_status task_in_memcg_oom_set(struct task_struct *p,
 						    struct mem_cgroup *memcg,
 						    gfp_t mask,
-						    int order)
+						    int order,
+						    bool force)
 {
 	return OOM_SUCCESS;
 }
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4418f5cb8324..cc1c7de7c248 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -774,6 +774,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_MEMCG
 	unsigned			in_user_fault:1;
+	unsigned			memcg_oom_wait:1;
 #endif
 #ifdef CONFIG_COMPAT_BRK
 	unsigned			brk_randomized:1;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index d6cb1b786045..a637e13a4964 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1801,7 +1801,8 @@ static enum oom_status mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int
 	 * victim and then we have to bail out from the charge path.
 	 */
 	if (memcg->oom_kill_disable)
-		return task_in_memcg_oom_set(current, memcg, mask, order);
+		return task_in_memcg_oom_set(current, memcg, mask,
+					     order, false);
 
 	mem_cgroup_mark_under_oom(memcg);
 
@@ -1863,7 +1864,8 @@ bool mem_cgroup_oom_synchronize(bool handle)
 	if (locked)
 		mem_cgroup_oom_notify(memcg);
 
-	if (locked && !memcg->oom_kill_disable) {
+	if (locked && !memcg->oom_kill_disable &&
+	    !current->memcg_oom_wait) {
 		mem_cgroup_unmark_under_oom(memcg);
 		finish_wait(&memcg_oom_waitq, &owait.wait);
 		mem_cgroup_out_of_memory(memcg, current->memcg_oom_gfp_mask,
@@ -1883,7 +1885,10 @@ bool mem_cgroup_oom_synchronize(bool handle)
 		 */
 		memcg_oom_recover(memcg);
 	}
+
 cleanup:
+	if (current->memcg_oom_wait)
+		current->memcg_oom_wait = false;
 	current->memcg_in_oom = NULL;
 	css_put(&memcg->css);
 	return true;
@@ -6056,6 +6061,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 	struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
 	unsigned int nr_reclaims = MEM_CGROUP_RECLAIM_RETRIES;
 	bool drained = false;
+	bool enlarge = false;
 	unsigned long max;
 	int err;
 
@@ -6069,7 +6075,12 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 	for (;;) {
 		unsigned long nr_pages = page_counter_read(&memcg->memory);
 
-		if (nr_pages <= max)
+		if (nr_pages < max) {
+			enlarge = true;
+			break;
+		}
+
+		if (nr_pages == max)
 			break;
 
 		if (signal_pending(current))
@@ -6081,6 +6092,9 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 			continue;
 		}
 
+		if (memcg->under_oom)
+			break;
+
 		if (nr_reclaims) {
 			if (!try_to_free_mem_cgroup_pages(memcg, nr_pages - max,
 							  GFP_KERNEL, true))
@@ -6089,11 +6103,14 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 		}
 
 		memcg_memory_event(memcg, MEMCG_OOM);
-		if (mem_cgroup_out_of_memory(memcg, GFP_KERNEL, 0) !=
+		if (mem_cgroup_out_of_memory(memcg, GFP_KERNEL, -2) !=
 		    OOM_SUCCESS)
 			break;
 	}
 
+	if (enlarge)
+		memcg_oom_recover(memcg);
+
 	memcg_wb_domain_size_changed(memcg);
 	return nbytes;
 }
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index d5a941bea2d7..df564495c8b2 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -158,6 +158,15 @@ static inline bool is_sysrq_oom(struct oom_control *oc)
 	return oc->order == -1;
 }
 
+/*
+ * order == -2 means the oom kill is triggered by reducing memcg max,
+ * otherwise only for display puerposes.
+ */
+static bool is_max_write_oom(struct oom_control *oc)
+{
+	return oc->order == -2;
+}
+
 /* return true if the task is not adequate as candidate victim task. */
 static bool oom_unkillable_task(struct task_struct *p)
 {
@@ -1108,6 +1117,19 @@ enum oom_status out_of_memory(struct oom_control *oc)
 		 */
 		if (!is_sysrq_oom(oc) && !is_memcg_oom(oc))
 			panic("System is deadlocked on memory\n");
+
+		/* Bail out from the charge path if we can't find a victim. */
+		if (is_memcg_oom(oc)) {
+			if (is_max_write_oom(oc))
+				return OOM_SKIPPED;
+
+			return task_in_memcg_oom_set(current,
+						     oc->memcg,
+						     oc->gfp_mask,
+						     oc->order,
+						     true);
+		}
+
 	}
 	if (oc->chosen && oc->chosen != (void *)-1UL)
 		oom_kill_process(oc, !is_memcg_oom(oc) ? "Out of memory" :
