Skip to content

Commit

Permalink
s390/mm: Add cond_resched() to cmm_alloc/free_pages()
Browse files Browse the repository at this point in the history
[ 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 <[email protected]>
Reviewed-by: Heiko Carstens <[email protected]>
Signed-off-by: Heiko Carstens <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
gerald-schaefer authored and gregkh committed Oct 17, 2024
1 parent 1cd1978 commit dced2c9
Showing 1 changed file with 17 additions and 1 deletion.
18 changes: 17 additions & 1 deletion arch/s390/mm/cmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
{
Expand Down

0 comments on commit dced2c9

Please sign in to comment.