]> git.ipfire.org Git - thirdparty/kernel/linux.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)
committerHeiko Carstens <hca@linux.ibm.com>
Thu, 5 Sep 2024 13:17:23 +0000 (15:17 +0200)
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>
arch/s390/mm/cmm.c

index 75d15bf41d97c3b3788a7b1e3352ab3bc0c34836..d01724a715d0fc035165bdbc14b60a654f43d6cf 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)
 {