diff options
author | Hugh Dickins <hughd@google.com> | 2023-08-22 22:14:47 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-08-30 16:11:06 +0200 |
commit | d13f3a63d236d311fceece5f34133636fd334bde (patch) | |
tree | e3be66f3fdd6d600118d241720cba30e24a67f20 | |
parent | 091591f6e7c35fc2f0a74c9d044b0638a37b0f3f (diff) | |
download | linux-d13f3a63d236d311fceece5f34133636fd334bde.tar.gz |
shmem: fix smaps BUG sleeping while atomic
commit e5548f85b4527c4c803b7eae7887c10bf8f90c97 upstream. smaps_pte_hole_lookup() is calling shmem_partial_swap_usage() with page table lock held: but shmem_partial_swap_usage() does cond_resched_rcu() if need_resched(): "BUG: sleeping function called from invalid context". Since shmem_partial_swap_usage() is designed to count across a range, but smaps_pte_hole_lookup() only calls it for a single page slot, just break out of the loop on the last or only page, before checking need_resched(). Link: https://lkml.kernel.org/r/6fe3b3ec-abdf-332f-5c23-6a3b3a3b11a9@google.com Fixes: 230100321518 ("mm/smaps: simplify shmem handling of pte holes") Signed-off-by: Hugh Dickins <hughd@google.com> Acked-by: Peter Xu <peterx@redhat.com> Cc: <stable@vger.kernel.org> [5.16+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | mm/shmem.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index aba041a3df73..10365ced5b1f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -800,14 +800,16 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping, XA_STATE(xas, &mapping->i_pages, start); struct page *page; unsigned long swapped = 0; + unsigned long max = end - 1; rcu_read_lock(); - xas_for_each(&xas, page, end - 1) { + xas_for_each(&xas, page, max) { if (xas_retry(&xas, page)) continue; if (xa_is_value(page)) swapped++; - + if (xas.xa_index == max) + break; if (need_resched()) { xas_pause(&xas); cond_resched_rcu(); |