]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
s390/mm: Add cond_resched() to cmm_alloc/free_pages()
authorGerald Schaefer <gerald.schaefer@linux.ibm.com>
Mon, 2 Sep 2024 12:02:19 +0000 (14:02 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2024 13:11:49 +0000 (15:11 +0200)
[ 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>
arch/s390/mm/cmm.c

index 1141c8d5c0d038a23ca3ecc2ced56e7b63a3c47a..9b4304fa37bfc47d1c5df68433d7a40d6131ab4b 100644 (file)
@@ -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)
 {