summaryrefslogtreecommitdiff
path: root/arch/s390
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@linux.ibm.com>2024-09-02 15:02:19 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-10-17 16:08:30 +0300
commitdced2c9d661e3eee3d80550730d9f3c5c3e04d1a (patch)
tree422d79ccf77e0fdb1de78d479af4f3962a116064 /arch/s390
parent1cd197813eb85905b54a7efd34abb9d110fffe2a (diff)
downloadlinux-dced2c9d661e3eee3d80550730d9f3c5c3e04d1a.tar.xz
s390/mm: Add cond_resched() to cmm_alloc/free_pages()
[ Upstream commit 131b8db78558120f58c5dc745ea9655f6b854162 ] Adding/removing large amount of pages at once to/from the CMM balloon can result in rcu_sched stalls or workqueue lockups, because of busy looping w/o cond_resched(). Prevent this by adding a cond_resched(). cmm_free_pages() holds a spin_lock while looping, so it cannot be added directly to the existing loop. Instead, introduce a wrapper function that operates on maximum 256 pages at once, and add it there. Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/mm/cmm.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index 1141c8d5c0d0..9b4304fa37bf 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -95,11 +95,12 @@ static long cmm_alloc_pages(long nr, long *counter,
(*counter)++;
spin_unlock(&cmm_lock);
nr--;
+ cond_resched();
}
return nr;
}
-static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
+static long __cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
{
struct cmm_page_array *pa;
unsigned long addr;
@@ -123,6 +124,21 @@ static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
return nr;
}
+static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
+{
+ long inc = 0;
+
+ while (nr) {
+ inc = min(256L, nr);
+ nr -= inc;
+ inc = __cmm_free_pages(inc, counter, list);
+ if (inc)
+ break;
+ cond_resched();
+ }
+ return nr + inc;
+}
+
static int cmm_oom_notify(struct notifier_block *self,
unsigned long dummy, void *parm)
{