0007-mm-shmem-do-not-wait-for-lock_page-in-shmem_unused_h.patch 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: "Kirill A. Shutemov" <[email protected]>
  3. Date: Fri, 23 Mar 2018 09:19:21 +0100
  4. Subject: [PATCH] mm/shmem: do not wait for lock_page() in
  5. shmem_unused_huge_shrink()
  6. MIME-Version: 1.0
  7. Content-Type: text/plain; charset=UTF-8
  8. Content-Transfer-Encoding: 8bit
  9. shmem_unused_huge_shrink() gets called from reclaim path. Waiting for
  10. page lock may lead to deadlock there.
  11. There was a bug report that may be attributed to this:
  12. http://lkml.kernel.org/r/[email protected]
  13. Replace lock_page() with trylock_page() and skip the page if we failed to
  14. lock it. We will get to the page on the next scan.
  15. We can test for the PageTransHuge() outside the page lock as we only need
  16. protection against splitting the page under us. Holding pin oni the page
  17. is enough for this.
  18. Link: http://lkml.kernel.org/r/[email protected]
  19. Fixes: 779750d20b93 ("shmem: split huge pages beyond i_size under memory pressure")
  20. Signed-off-by: Kirill A. Shutemov <[email protected]>
  21. Reported-by: Eric Wheeler <[email protected]>
  22. Acked-by: Michal Hocko <[email protected]>
  23. Reviewed-by: Andrew Morton <[email protected]>
  24. Cc: Tetsuo Handa <[email protected]>
  25. Cc: Hugh Dickins <[email protected]>
  26. Cc: <[email protected]> [4.8+]
  27. Signed-off-by: Andrew Morton <>
  28. (cherry-picked from https://git.kernel.org/pub/scm/linux/kernel/git/mhocko/mm.git/commit/?h=since-4.15&id=73eccc61c701ee7b4223aea2079542a712feeea7)
  29. Signed-off-by: Fabian Grünbichler <[email protected]>
  30. ---
  31. mm/shmem.c | 31 ++++++++++++++++++++-----------
  32. 1 file changed, 20 insertions(+), 11 deletions(-)
  33. diff --git a/mm/shmem.c b/mm/shmem.c
  34. index f6695c111086..800482fe6ed6 100644
  35. --- a/mm/shmem.c
  36. +++ b/mm/shmem.c
  37. @@ -497,36 +497,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
  38. info = list_entry(pos, struct shmem_inode_info, shrinklist);
  39. inode = &info->vfs_inode;
  40. - if (nr_to_split && split >= nr_to_split) {
  41. - iput(inode);
  42. - continue;
  43. - }
  44. + if (nr_to_split && split >= nr_to_split)
  45. + goto leave;
  46. - page = find_lock_page(inode->i_mapping,
  47. + page = find_get_page(inode->i_mapping,
  48. (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT);
  49. if (!page)
  50. goto drop;
  51. + /* No huge page at the end of the file: nothing to split */
  52. if (!PageTransHuge(page)) {
  53. - unlock_page(page);
  54. put_page(page);
  55. goto drop;
  56. }
  57. + /*
  58. + * Leave the inode on the list if we failed to lock
  59. + * the page at this time.
  60. + *
  61. + * Waiting for the lock may lead to deadlock in the
  62. + * reclaim path.
  63. + */
  64. + if (!trylock_page(page)) {
  65. + put_page(page);
  66. + goto leave;
  67. + }
  68. +
  69. ret = split_huge_page(page);
  70. unlock_page(page);
  71. put_page(page);
  72. - if (ret) {
  73. - /* split failed: leave it on the list */
  74. - iput(inode);
  75. - continue;
  76. - }
  77. + /* If split failed leave the inode on the list */
  78. + if (ret)
  79. + goto leave;
  80. split++;
  81. drop:
  82. list_del_init(&info->shrinklist);
  83. removed++;
  84. +leave:
  85. iput(inode);
  86. }
  87. --
  88. 2.14.2