Home Home > GIT Browse > SLE12-SP4
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-01-14 10:40:58 +0100
committerTakashi Iwai <tiwai@suse.de>2019-01-14 10:40:58 +0100
commit9bd3a7631ddc40ffab36dfb21d67e68a60854342 (patch)
tree7a6b1c3a061d3e20f2194887629d05e49d232ff7
parentc42e195e74ff4f95464ad7889cb0084e304f5ebb (diff)
parent2b8ff432714af9ec566f169109853deeabaa0193 (diff)
Merge branch 'users/vbabka/SLE15/for-next' into SLE15
Pull mm fixes from Vlastimil Babka
-rw-r--r--patches.fixes/mm-huge_memory-fix-lockdep-complaint-on-32-bit-i_size_read.patch99
-rw-r--r--patches.fixes/mm-huge_memory-rename-freeze_page-to-unmap_page.patch87
-rw-r--r--patches.fixes/mm-huge_memory-splitting-set-mapping-index-before-unfreeze.patch66
-rw-r--r--patches.fixes/mm-khugepaged-collapse_shmem-do-not-crash-on-compound.patch48
-rw-r--r--patches.fixes/mm-khugepaged-collapse_shmem-remember-to-clear-holes.patch59
-rw-r--r--patches.fixes/mm-khugepaged-collapse_shmem-stop-if-punched-or-truncated.patch60
-rw-r--r--patches.fixes/mm-khugepaged-collapse_shmem-without-freezing-new_page.patch115
-rw-r--r--patches.fixes/mm-khugepaged-fix-crashes-due-to-misaccounted-holes.patch88
-rw-r--r--patches.fixes/mm-khugepaged-minor-reorderings-in-collapse_shmem.patch232
-rw-r--r--patches.fixes/shmem-introduce-shmem_inode_acct_block.patch247
-rw-r--r--patches.fixes/shmem-shmem_charge-verify-max_block-is-not-exceeded-before-inode-update.patch78
-rw-r--r--patches.fixes/userfaultfd-shmem-add-i_size-checks.patch8
-rw-r--r--series.conf11
13 files changed, 1194 insertions, 4 deletions
diff --git a/patches.fixes/mm-huge_memory-fix-lockdep-complaint-on-32-bit-i_size_read.patch b/patches.fixes/mm-huge_memory-fix-lockdep-complaint-on-32-bit-i_size_read.patch
new file mode 100644
index 0000000000..b6dfab4f10
--- /dev/null
+++ b/patches.fixes/mm-huge_memory-fix-lockdep-complaint-on-32-bit-i_size_read.patch
@@ -0,0 +1,99 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:21 -0800
+Subject: mm/huge_memory: fix lockdep complaint on 32-bit i_size_read()
+Git-commit: 006d3ff27e884f80bd7d306b041afc415f63598f
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+Huge tmpfs testing, on 32-bit kernel with lockdep enabled, showed that
+__split_huge_page() was using i_size_read() while holding the irq-safe
+lru_lock and page tree lock, but the 32-bit i_size_read() uses an
+irq-unsafe seqlock which should not be nested inside them.
+
+Instead, read the i_size earlier in split_huge_page_to_list(), and pass
+the end offset down to __split_huge_page(): all while holding head page
+lock, which is enough to prevent truncation of that extent before the
+page tree lock has been taken.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261520070.2275@eggly.anvils
+Fixes: baa355fd33142 ("thp: file pages support for split_huge_page()")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/huge_memory.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2260,12 +2260,11 @@ static void __split_huge_page_tail(struc
+ }
+
+ static void __split_huge_page(struct page *page, struct list_head *list,
+- unsigned long flags)
++ pgoff_t end, unsigned long flags)
+ {
+ struct page *head = compound_head(page);
+ struct zone *zone = page_zone(head);
+ struct lruvec *lruvec;
+- pgoff_t end = -1;
+ int i;
+
+ lruvec = mem_cgroup_page_lruvec(head, zone->zone_pgdat);
+@@ -2273,9 +2272,6 @@ static void __split_huge_page(struct pag
+ /* complete memcg works before add pages to LRU */
+ mem_cgroup_split_huge_fixup(head);
+
+- if (!PageAnon(page))
+- end = DIV_ROUND_UP(i_size_read(head->mapping->host), PAGE_SIZE);
+-
+ for (i = HPAGE_PMD_NR - 1; i >= 1; i--) {
+ __split_huge_page_tail(head, i, lruvec, list);
+ /* Some pages can be beyond i_size: drop them from page cache */
+@@ -2428,6 +2424,7 @@ int split_huge_page_to_list(struct page
+ int count, mapcount, extra_pins, ret;
+ bool mlocked;
+ unsigned long flags;
++ pgoff_t end;
+
+ VM_BUG_ON_PAGE(is_huge_zero_page(page), page);
+ VM_BUG_ON_PAGE(!PageLocked(page), page);
+@@ -2448,6 +2445,7 @@ int split_huge_page_to_list(struct page
+ goto out;
+ }
+ extra_pins = 0;
++ end = -1;
+ mapping = NULL;
+ anon_vma_lock_write(anon_vma);
+ } else {
+@@ -2463,6 +2461,15 @@ int split_huge_page_to_list(struct page
+ extra_pins = HPAGE_PMD_NR;
+ anon_vma = NULL;
+ i_mmap_lock_read(mapping);
++
++ /*
++ *__split_huge_page() may need to trim off pages beyond EOF:
++ * but on 32-bit, i_size_read() takes an irq-unsafe seqlock,
++ * which cannot be nested inside the page tree lock. So note
++ * end now: i_size itself may be changed at any moment, but
++ * head page lock is good enough to serialize the trimming.
++ */
++ end = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE);
+ }
+
+ /*
+@@ -2512,7 +2519,7 @@ int split_huge_page_to_list(struct page
+ if (mapping)
+ __dec_node_page_state(page, NR_SHMEM_THPS);
+ spin_unlock(&pgdata->split_queue_lock);
+- __split_huge_page(page, list, flags);
++ __split_huge_page(page, list, end, flags);
+ ret = 0;
+ } else {
+ if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) {
diff --git a/patches.fixes/mm-huge_memory-rename-freeze_page-to-unmap_page.patch b/patches.fixes/mm-huge_memory-rename-freeze_page-to-unmap_page.patch
new file mode 100644
index 0000000000..9106bc3635
--- /dev/null
+++ b/patches.fixes/mm-huge_memory-rename-freeze_page-to-unmap_page.patch
@@ -0,0 +1,87 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:13 -0800
+Subject: mm/huge_memory: rename freeze_page() to unmap_page()
+Git-commit: 906f9cdfc2a0800f13683f9e4ebdfd08c12ee81b
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+The term "freeze" is used in several ways in the kernel, and in mm it
+has the particular meaning of forcing page refcount temporarily to 0.
+freeze_page() is just too confusing a name for a function that unmaps a
+page: rename it unmap_page(), and rename unfreeze_page() remap_page().
+
+Went to change the mention of freeze_page() added later in mm/rmap.c,
+but found it to be incorrect: ordinary page reclaim reaches there too;
+but the substance of the comment still seems correct, so edit it down.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261514080.2275@eggly.anvils
+Fixes: e9b61f19858a5 ("thp: reintroduce split_huge_page()")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/huge_memory.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2179,7 +2179,7 @@ void vma_adjust_trans_huge(struct vm_are
+ }
+ }
+
+-static void freeze_page(struct page *page)
++static void unmap_page(struct page *page)
+ {
+ enum ttu_flags ttu_flags = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS |
+ TTU_RMAP_LOCKED | TTU_SPLIT_HUGE_PMD;
+@@ -2194,7 +2194,7 @@ static void freeze_page(struct page *pag
+ VM_BUG_ON_PAGE(!unmap_success, page);
+ }
+
+-static void unfreeze_page(struct page *page)
++static void remap_page(struct page *page)
+ {
+ int i;
+ if (PageTransHuge(page)) {
+@@ -2300,7 +2300,7 @@ static void __split_huge_page(struct pag
+
+ spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
+
+- unfreeze_page(head);
++ remap_page(head);
+
+ for (i = 0; i < HPAGE_PMD_NR; i++) {
+ struct page *subpage = head + i;
+@@ -2466,7 +2466,7 @@ int split_huge_page_to_list(struct page
+ }
+
+ /*
+- * Racy check if we can split the page, before freeze_page() will
++ * Racy check if we can split the page, before unmap_page() will
+ * split PMDs
+ */
+ if (total_mapcount(head) != page_count(head) - extra_pins - 1) {
+@@ -2475,7 +2475,7 @@ int split_huge_page_to_list(struct page
+ }
+
+ mlocked = PageMlocked(page);
+- freeze_page(head);
++ unmap_page(head);
+ VM_BUG_ON_PAGE(compound_mapcount(head), head);
+
+ /* Make sure the page is not on per-CPU pagevec as it takes pin */
+@@ -2527,7 +2527,7 @@ int split_huge_page_to_list(struct page
+ fail: if (mapping)
+ spin_unlock(&mapping->tree_lock);
+ spin_unlock_irqrestore(zone_lru_lock(page_zone(head)), flags);
+- unfreeze_page(head);
++ remap_page(head);
+ ret = -EBUSY;
+ }
+
diff --git a/patches.fixes/mm-huge_memory-splitting-set-mapping-index-before-unfreeze.patch b/patches.fixes/mm-huge_memory-splitting-set-mapping-index-before-unfreeze.patch
new file mode 100644
index 0000000000..acd1c39b60
--- /dev/null
+++ b/patches.fixes/mm-huge_memory-splitting-set-mapping-index-before-unfreeze.patch
@@ -0,0 +1,66 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:16 -0800
+Subject: mm/huge_memory: splitting set mapping+index before unfreeze
+Git-commit: 173d9d9fd3ddae84c110fea8aedf1f26af6be9ec
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+Huge tmpfs stress testing has occasionally hit shmem_undo_range()'s
+VM_BUG_ON_PAGE(page_to_pgoff(page) != index, page).
+
+Move the setting of mapping and index up before the page_ref_unfreeze()
+in __split_huge_page_tail() to fix this: so that a page cache lookup
+cannot get a reference while the tail's mapping and index are unstable.
+
+In fact, might as well move them up before the smp_wmb(): I don't see an
+actual need for that, but if I'm missing something, this way round is
+safer than the other, and no less efficient.
+
+You might argue that VM_BUG_ON_PAGE(page_to_pgoff(page) != index, page) is
+misplaced, and should be left until after the trylock_page(); but left as
+is has not crashed since, and gives more stringent assurance.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261516380.2275@eggly.anvils
+Fixes: e9b61f19858a5 ("thp: reintroduce split_huge_page()")
+Requires: 605ca5ede764 ("mm/huge_memory.c: reorder operations in __split_huge_page_tail()")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/huge_memory.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -2229,6 +2229,12 @@ static void __split_huge_page_tail(struc
+ (1L << PG_unevictable) |
+ (1L << PG_dirty)));
+
++ /* ->mapping in first tail page is compound_mapcount */
++ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING,
++ page_tail);
++ page_tail->mapping = head->mapping;
++ page_tail->index = head->index + tail;
++
+ /* Page flags must be visible before we make the page non-compound. */
+ smp_wmb();
+
+@@ -2249,12 +2255,6 @@ static void __split_huge_page_tail(struc
+ if (page_is_idle(head))
+ set_page_idle(page_tail);
+
+- /* ->mapping in first tail page is compound_mapcount */
+- VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING,
+- page_tail);
+- page_tail->mapping = head->mapping;
+-
+- page_tail->index = head->index + tail;
+ page_cpupid_xchg_last(page_tail, page_cpupid_last(head));
+ lru_add_page_tail(head, page_tail, lruvec, list);
+ }
diff --git a/patches.fixes/mm-khugepaged-collapse_shmem-do-not-crash-on-compound.patch b/patches.fixes/mm-khugepaged-collapse_shmem-do-not-crash-on-compound.patch
new file mode 100644
index 0000000000..58d8996e22
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-collapse_shmem-do-not-crash-on-compound.patch
@@ -0,0 +1,48 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:47 -0800
+Subject: mm/khugepaged: collapse_shmem() do not crash on Compound
+Git-commit: 06a5e1268a5fb9c2b346a3da6b97e85f2eba0f07
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+collapse_shmem()'s VM_BUG_ON_PAGE(PageTransCompound) was unsafe: before
+it holds page lock of the first page, racing truncation then extension
+might conceivably have inserted a hugepage there already. Fail with the
+SCAN_PAGE_COMPOUND result, instead of crashing (CONFIG_DEBUG_VM=y) or
+otherwise mishandling the unexpected hugepage - though later we might
+code up a more constructive way of handling it, with SCAN_SUCCESS.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261529310.2275@eggly.anvils
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1396,7 +1396,15 @@ static void collapse_shmem(struct mm_str
+ */
+ VM_BUG_ON_PAGE(!PageLocked(page), page);
+ VM_BUG_ON_PAGE(!PageUptodate(page), page);
+- VM_BUG_ON_PAGE(PageTransCompound(page), page);
++
++ /*
++ * If file was truncated then extended, or hole-punched, before
++ * we locked the first page, then a THP might be there already.
++ */
++ if (PageTransCompound(page)) {
++ result = SCAN_PAGE_COMPOUND;
++ goto out_unlock;
++ }
+
+ if (page_mapping(page) != mapping) {
+ result = SCAN_TRUNCATED;
diff --git a/patches.fixes/mm-khugepaged-collapse_shmem-remember-to-clear-holes.patch b/patches.fixes/mm-khugepaged-collapse_shmem-remember-to-clear-holes.patch
new file mode 100644
index 0000000000..9651bc93ce
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-collapse_shmem-remember-to-clear-holes.patch
@@ -0,0 +1,59 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:35 -0800
+Subject: mm/khugepaged: collapse_shmem() remember to clear holes
+Git-commit: 2af8ff291848cc4b1cce24b6c943394eb2c761e8
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+Huge tmpfs testing reminds us that there is no __GFP_ZERO in the gfp
+flags khugepaged uses to allocate a huge page - in all common cases it
+would just be a waste of effort - so collapse_shmem() must remember to
+clear out any holes that it instantiates.
+
+The obvious place to do so, where they are put into the page cache tree,
+is not a good choice: because interrupts are disabled there. Leave it
+until further down, once success is assured, where the other pages are
+copied (before setting PageUptodate).
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261525080.2275@eggly.anvils
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1497,7 +1497,12 @@ tree_unlocked:
+ * Replacing old pages with new one has succeed, now we need to
+ * copy the content and free old pages.
+ */
++ index = start;
+ list_for_each_entry_safe(page, tmp, &pagelist, lru) {
++ while (index < page->index) {
++ clear_highpage(new_page + (index % HPAGE_PMD_NR));
++ index++;
++ }
+ copy_highpage(new_page + (page->index % HPAGE_PMD_NR),
+ page);
+ list_del(&page->lru);
+@@ -1507,6 +1512,11 @@ tree_unlocked:
+ ClearPageActive(page);
+ ClearPageUnevictable(page);
+ put_page(page);
++ index++;
++ }
++ while (index < end) {
++ clear_highpage(new_page + (index % HPAGE_PMD_NR));
++ index++;
+ }
+
+ local_irq_save(flags);
diff --git a/patches.fixes/mm-khugepaged-collapse_shmem-stop-if-punched-or-truncated.patch b/patches.fixes/mm-khugepaged-collapse_shmem-stop-if-punched-or-truncated.patch
new file mode 100644
index 0000000000..c746dde23f
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-collapse_shmem-stop-if-punched-or-truncated.patch
@@ -0,0 +1,60 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:25 -0800
+Subject: mm/khugepaged: collapse_shmem() stop if punched or truncated
+Git-commit: 701270fa193aadf00bdcf607738f64997275d4c7
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+[ vbabka@suse.cz: use the 4.14 pre-xarray stable backport ]
+
+Huge tmpfs testing showed that although collapse_shmem() recognizes a
+concurrently truncated or hole-punched page correctly, its handling of
+holes was liable to refill an emptied extent. Add check to stop that.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261522040.2275@eggly.anvils
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Reviewed-by: Matthew Wilcox <willy@infradead.org>
+Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1348,6 +1348,16 @@ static void collapse_shmem(struct mm_str
+ int n = min(iter.index, end) - index;
+
+ /*
++ * Stop if extent has been hole-punched, and is now completely
++ * empty (the more obvious i_size_read() check would take an
++ * irq-unsafe seqlock on 32-bit).
++ */
++ if (n >= HPAGE_PMD_NR) {
++ result = SCAN_TRUNCATED;
++ goto tree_locked;
++ }
++
++ /*
+ * Handle holes in the radix tree: charge it from shmem and
+ * insert relevant subpage of new_page into the radix-tree.
+ */
+@@ -1458,6 +1468,11 @@ out_unlock:
+ if (result == SCAN_SUCCEED && index < end) {
+ int n = end - index;
+
++ /* Stop if extent has been truncated, and is now empty */
++ if (n >= HPAGE_PMD_NR) {
++ result = SCAN_TRUNCATED;
++ goto tree_locked;
++ }
+ if (!shmem_charge(mapping->host, n)) {
+ result = SCAN_FAIL;
+ goto tree_locked;
diff --git a/patches.fixes/mm-khugepaged-collapse_shmem-without-freezing-new_page.patch b/patches.fixes/mm-khugepaged-collapse_shmem-without-freezing-new_page.patch
new file mode 100644
index 0000000000..e6c560bc7d
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-collapse_shmem-without-freezing-new_page.patch
@@ -0,0 +1,115 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:43 -0800
+Subject: mm/khugepaged: collapse_shmem() without freezing new_page
+Git-commit: 87c460a0bded56195b5eb497d44709777ef7b415
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+[ vbabka@suse.cz: use stable 4.14 pre-xarray backport ]
+
+khugepaged's collapse_shmem() does almost all of its work, to assemble
+the huge new_page from 512 scattered old pages, with the new_page's
+refcount frozen to 0 (and refcounts of all old pages so far also frozen
+to 0). Including shmem_getpage() to read in any which were out on swap,
+memory reclaim if necessary to allocate their intermediate pages, and
+copying over all the data from old to new.
+
+Imagine the frozen refcount as a spinlock held, but without any lock
+debugging to highlight the abuse: it's not good, and under serious load
+heads into lockups - speculative getters of the page are not expecting
+to spin while khugepaged is rescheduled.
+
+One can get a little further under load by hacking around elsewhere; but
+fortunately, freezing the new_page turns out to have been entirely
+unnecessary, with no hacks needed elsewhere.
+
+The huge new_page lock is already held throughout, and guards all its
+subpages as they are brought one by one into the page cache tree; and
+anything reading the data in that page, without the lock, before it has
+been marked PageUptodate, would already be in the wrong. So simply
+eliminate the freezing of the new_page.
+
+Each of the old pages remains frozen with refcount 0 after it has been
+replaced by a new_page subpage in the page cache tree, until they are
+all unfrozen on success or failure: just as before. They could be
+unfrozen sooner, but cause no problem once no longer visible to
+find_get_entry(), filemap_map_pages() and other speculative lookups.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261527570.2275@eggly.anvils
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 19 +++++++------------
+ 1 file changed, 7 insertions(+), 12 deletions(-)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1285,7 +1285,7 @@ static void retract_page_tables(struct a
+ * collapse_shmem - collapse small tmpfs/shmem pages into huge one.
+ *
+ * Basic scheme is simple, details are more complex:
+- * - allocate and freeze a new huge page;
++ * - allocate and lock a new huge page;
+ * - scan over radix tree replacing old pages the new one
+ * + swap in pages if necessary;
+ * + fill in gaps;
+@@ -1293,11 +1293,11 @@ static void retract_page_tables(struct a
+ * - if replacing succeed:
+ * + copy data over;
+ * + free old pages;
+- * + unfreeze huge page;
++ * + unlock huge page;
+ * - if replacing failed;
+ * + put all pages back and unfreeze them;
+ * + restore gaps in the radix-tree;
+- * + free huge page;
++ * + unlock and free huge page;
+ */
+ static void collapse_shmem(struct mm_struct *mm,
+ struct address_space *mapping, pgoff_t start,
+@@ -1332,13 +1332,11 @@ static void collapse_shmem(struct mm_str
+ __SetPageSwapBacked(new_page);
+ new_page->index = start;
+ new_page->mapping = mapping;
+- BUG_ON(!page_ref_freeze(new_page, 1));
+
+ /*
+- * At this point the new_page is 'frozen' (page_count() is zero), locked
+- * and not up-to-date. It's safe to insert it into radix tree, because
+- * nobody would be able to map it or use it in other way until we
+- * unfreeze it.
++ * At this point the new_page is locked and not up-to-date.
++ * It's safe to insert it into the page cache, because nobody would
++ * be able to map it or use it in another way until we unlock it.
+ */
+
+ index = start;
+@@ -1516,9 +1514,8 @@ tree_unlocked:
+ index++;
+ }
+
+- /* Everything is ready, let's unfreeze the new_page */
+ SetPageUptodate(new_page);
+- page_ref_unfreeze(new_page, HPAGE_PMD_NR);
++ page_ref_add(new_page, HPAGE_PMD_NR - 1);
+ set_page_dirty(new_page);
+ mem_cgroup_commit_charge(new_page, memcg, false, true);
+ lru_cache_add_anon(new_page);
+@@ -1566,8 +1563,6 @@ tree_unlocked:
+ VM_BUG_ON(nr_none);
+ spin_unlock_irq(&mapping->tree_lock);
+
+- /* Unfreeze new_page, caller would take care about freeing it */
+- page_ref_unfreeze(new_page, 1);
+ mem_cgroup_cancel_charge(new_page, memcg, true);
+ new_page->mapping = NULL;
+ }
diff --git a/patches.fixes/mm-khugepaged-fix-crashes-due-to-misaccounted-holes.patch b/patches.fixes/mm-khugepaged-fix-crashes-due-to-misaccounted-holes.patch
new file mode 100644
index 0000000000..99c0a49393
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-fix-crashes-due-to-misaccounted-holes.patch
@@ -0,0 +1,88 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:29 -0800
+Subject: mm/khugepaged: fix crashes due to misaccounted holes
+Git-commit: aaa52e340073b7f4593b3c4ddafcafa70cf838b5
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+[ vbabka@suse.cz: use 4.14 pre-xarray stable backport ]
+
+Huge tmpfs testing on a shortish file mapped into a pmd-rounded extent
+hit shmem_evict_inode()'s WARN_ON(inode->i_blocks) followed by
+clear_inode()'s BUG_ON(inode->i_data.nrpages) when the file was later
+closed and unlinked.
+
+khugepaged's collapse_shmem() was forgetting to update mapping->nrpages
+on the rollback path, after it had added but then needs to undo some
+holes.
+
+There is indeed an irritating asymmetry between shmem_charge(), whose
+callers want it to increment nrpages after successfully accounting
+blocks, and shmem_uncharge(), when __delete_from_page_cache() already
+decremented nrpages itself: oh well, just add a comment on that to them
+both.
+
+And shmem_recalc_inode() is supposed to be called when the accounting is
+expected to be in balance (so it can deduce from imbalance that reclaim
+discarded some pages): so change shmem_charge() to update nrpages
+earlier (though it's rare for the difference to matter at all).
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261523450.2275@eggly.anvils
+Fixes: 800d8c63b2e98 ("shmem: add huge pages support")
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 4 +++-
+ mm/shmem.c | 6 +++++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1534,8 +1534,10 @@ tree_unlocked:
+ *hpage = NULL;
+ } else {
+ /* Something went wrong: rollback changes to the radix-tree */
+- shmem_uncharge(mapping->host, nr_none);
+ spin_lock_irq(&mapping->tree_lock);
++ mapping->nrpages -= nr_none;
++ shmem_uncharge(mapping->host, nr_none);
++
+ radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
+ start) {
+ if (iter.index >= end)
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -294,12 +294,14 @@ bool shmem_charge(struct inode *inode, l
+ if (!shmem_inode_acct_block(inode, pages))
+ return false;
+
++ /* nrpages adjustment first, then shmem_recalc_inode() when balanced */
++ inode->i_mapping->nrpages += pages;
++
+ spin_lock_irqsave(&info->lock, flags);
+ info->alloced += pages;
+ inode->i_blocks += pages * BLOCKS_PER_PAGE;
+ shmem_recalc_inode(inode);
+ spin_unlock_irqrestore(&info->lock, flags);
+- inode->i_mapping->nrpages += pages;
+
+ return true;
+ }
+@@ -309,6 +311,8 @@ void shmem_uncharge(struct inode *inode,
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ unsigned long flags;
+
++ /* nrpages adjustment done by __delete_from_page_cache() or caller */
++
+ spin_lock_irqsave(&info->lock, flags);
+ info->alloced -= pages;
+ inode->i_blocks -= pages * BLOCKS_PER_PAGE;
diff --git a/patches.fixes/mm-khugepaged-minor-reorderings-in-collapse_shmem.patch b/patches.fixes/mm-khugepaged-minor-reorderings-in-collapse_shmem.patch
new file mode 100644
index 0000000000..f4c0d7ca23
--- /dev/null
+++ b/patches.fixes/mm-khugepaged-minor-reorderings-in-collapse_shmem.patch
@@ -0,0 +1,232 @@
+From: Hugh Dickins <hughd@google.com>
+Date: Fri, 30 Nov 2018 14:10:39 -0800
+Subject: mm/khugepaged: minor reorderings in collapse_shmem()
+Git-commit: 042a30824871fa3149b0127009074b75cc25863c
+Patch-mainline: v4.20-rc5
+References: VM Functionality, bsc#1121599
+
+[ vbabka@suse.cz: use stable 4.14 pre-xarray backport ]
+
+Several cleanups in collapse_shmem(): most of which probably do not
+really matter, beyond doing things in a more familiar and reassuring
+order. Simplify the failure gotos in the main loop, and on success
+update stats while interrupts still disabled from the last iteration.
+
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1811261526400.2275@eggly.anvils
+Fixes: f3f0e1d2150b2 ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Jerome Glisse <jglisse@redhat.com>
+Cc: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/khugepaged.c | 73 +++++++++++++++++++++++---------------------------------
+ 1 file changed, 30 insertions(+), 43 deletions(-)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1328,13 +1328,12 @@ static void collapse_shmem(struct mm_str
+ goto out;
+ }
+
++ __SetPageLocked(new_page);
++ __SetPageSwapBacked(new_page);
+ new_page->index = start;
+ new_page->mapping = mapping;
+- __SetPageSwapBacked(new_page);
+- __SetPageLocked(new_page);
+ BUG_ON(!page_ref_freeze(new_page, 1));
+
+-
+ /*
+ * At this point the new_page is 'frozen' (page_count() is zero), locked
+ * and not up-to-date. It's safe to insert it into radix tree, because
+@@ -1363,13 +1362,13 @@ static void collapse_shmem(struct mm_str
+ */
+ if (n && !shmem_charge(mapping->host, n)) {
+ result = SCAN_FAIL;
+- break;
++ goto tree_locked;
+ }
+- nr_none += n;
+ for (; index < min(iter.index, end); index++) {
+ radix_tree_insert(&mapping->page_tree, index,
+ new_page + (index % HPAGE_PMD_NR));
+ }
++ nr_none += n;
+
+ /* We are done. */
+ if (index >= end)
+@@ -1385,12 +1384,12 @@ static void collapse_shmem(struct mm_str
+ result = SCAN_FAIL;
+ goto tree_unlocked;
+ }
+- spin_lock_irq(&mapping->tree_lock);
+ } else if (trylock_page(page)) {
+ get_page(page);
++ spin_unlock_irq(&mapping->tree_lock);
+ } else {
+ result = SCAN_PAGE_LOCK;
+- break;
++ goto tree_locked;
+ }
+
+ /*
+@@ -1405,11 +1404,10 @@ static void collapse_shmem(struct mm_str
+ result = SCAN_TRUNCATED;
+ goto out_unlock;
+ }
+- spin_unlock_irq(&mapping->tree_lock);
+
+ if (isolate_lru_page(page)) {
+ result = SCAN_DEL_PAGE_LRU;
+- goto out_isolate_failed;
++ goto out_unlock;
+ }
+
+ if (page_mapped(page))
+@@ -1431,7 +1429,9 @@ static void collapse_shmem(struct mm_str
+ */
+ if (!page_ref_freeze(page, 3)) {
+ result = SCAN_PAGE_COUNT;
+- goto out_lru;
++ spin_unlock_irq(&mapping->tree_lock);
++ putback_lru_page(page);
++ goto out_unlock;
+ }
+
+ /*
+@@ -1447,17 +1447,10 @@ static void collapse_shmem(struct mm_str
+ slot = radix_tree_iter_resume(slot, &iter);
+ index++;
+ continue;
+-out_lru:
+- spin_unlock_irq(&mapping->tree_lock);
+- putback_lru_page(page);
+-out_isolate_failed:
+- unlock_page(page);
+- put_page(page);
+- goto tree_unlocked;
+ out_unlock:
+ unlock_page(page);
+ put_page(page);
+- break;
++ goto tree_unlocked;
+ }
+
+ /*
+@@ -1465,7 +1458,7 @@ out_unlock:
+ * This code only triggers if there's nothing in radix tree
+ * beyond 'end'.
+ */
+- if (result == SCAN_SUCCEED && index < end) {
++ if (index < end) {
+ int n = end - index;
+
+ /* Stop if extent has been truncated, and is now empty */
+@@ -1477,7 +1470,6 @@ out_unlock:
+ result = SCAN_FAIL;
+ goto tree_locked;
+ }
+-
+ for (; index < end; index++) {
+ radix_tree_insert(&mapping->page_tree, index,
+ new_page + (index % HPAGE_PMD_NR));
+@@ -1485,14 +1477,19 @@ out_unlock:
+ nr_none += n;
+ }
+
++ __inc_node_page_state(new_page, NR_SHMEM_THPS);
++ if (nr_none) {
++ struct zone *zone = page_zone(new_page);
++
++ __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
++ __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
++ }
++
+ tree_locked:
+ spin_unlock_irq(&mapping->tree_lock);
+ tree_unlocked:
+
+ if (result == SCAN_SUCCEED) {
+- unsigned long flags;
+- struct zone *zone = page_zone(new_page);
+-
+ /*
+ * Replacing old pages with new one has succeed, now we need to
+ * copy the content and free old pages.
+@@ -1506,11 +1503,11 @@ tree_unlocked:
+ copy_highpage(new_page + (page->index % HPAGE_PMD_NR),
+ page);
+ list_del(&page->lru);
+- unlock_page(page);
+- page_ref_unfreeze(page, 1);
+ page->mapping = NULL;
++ page_ref_unfreeze(page, 1);
+ ClearPageActive(page);
+ ClearPageUnevictable(page);
++ unlock_page(page);
+ put_page(page);
+ index++;
+ }
+@@ -1519,28 +1516,17 @@ tree_unlocked:
+ index++;
+ }
+
+- local_irq_save(flags);
+- __inc_node_page_state(new_page, NR_SHMEM_THPS);
+- if (nr_none) {
+- __mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
+- __mod_node_page_state(zone->zone_pgdat, NR_SHMEM, nr_none);
+- }
+- local_irq_restore(flags);
+-
+- /*
+- * Remove pte page tables, so we can re-faulti
+- * the page as huge.
+- */
+- retract_page_tables(mapping, start);
+-
+ /* Everything is ready, let's unfreeze the new_page */
+- set_page_dirty(new_page);
+ SetPageUptodate(new_page);
+ page_ref_unfreeze(new_page, HPAGE_PMD_NR);
++ set_page_dirty(new_page);
+ mem_cgroup_commit_charge(new_page, memcg, false, true);
+ lru_cache_add_anon(new_page);
+- unlock_page(new_page);
+
++ /*
++ * Remove pte page tables, so we can re-fault the page as huge.
++ */
++ retract_page_tables(mapping, start);
+ *hpage = NULL;
+ } else {
+ /* Something went wrong: rollback changes to the radix-tree */
+@@ -1573,8 +1559,8 @@ tree_unlocked:
+ slot, page);
+ slot = radix_tree_iter_resume(slot, &iter);
+ spin_unlock_irq(&mapping->tree_lock);
+- putback_lru_page(page);
+ unlock_page(page);
++ putback_lru_page(page);
+ spin_lock_irq(&mapping->tree_lock);
+ }
+ VM_BUG_ON(nr_none);
+@@ -1583,9 +1569,10 @@ tree_unlocked:
+ /* Unfreeze new_page, caller would take care about freeing it */
+ page_ref_unfreeze(new_page, 1);
+ mem_cgroup_cancel_charge(new_page, memcg, true);
+- unlock_page(new_page);
+ new_page->mapping = NULL;
+ }
++
++ unlock_page(new_page);
+ out:
+ VM_BUG_ON(!list_empty(&pagelist));
+ /* TODO: tracepoints */
diff --git a/patches.fixes/shmem-introduce-shmem_inode_acct_block.patch b/patches.fixes/shmem-introduce-shmem_inode_acct_block.patch
new file mode 100644
index 0000000000..1363e6117a
--- /dev/null
+++ b/patches.fixes/shmem-introduce-shmem_inode_acct_block.patch
@@ -0,0 +1,247 @@
+From: Mike Rapoport <rppt@linux.vnet.ibm.com>
+Date: Wed, 6 Sep 2017 16:22:59 -0700
+Subject: shmem: introduce shmem_inode_acct_block
+Git-commit: 0f0796945614b7523987f7eea32407421af4b1ee
+Patch-mainline: v4.14-rc1
+References: VM Functionality, bsc#1121599
+
+The shmem_acct_block and the update of used_blocks are following one
+another in all the places they are used. Combine these two into a
+helper function.
+
+Link: http://lkml.kernel.org/r/1497939652-16528-3-git-send-email-rppt@linux.vnet.ibm.com
+Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
+Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
+Cc: Hugh Dickins <hughd@google.com>
+Cc: Pavel Emelyanov <xemul@virtuozzo.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/shmem.c | 102 +++++++++++++++++++++++++++----------------------------------
+ 1 file changed, 46 insertions(+), 56 deletions(-)
+
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -187,6 +187,38 @@ static inline void shmem_unacct_blocks(u
+ vm_unacct_memory(pages * VM_ACCT(PAGE_SIZE));
+ }
+
++static inline bool shmem_inode_acct_block(struct inode *inode, long pages)
++{
++ struct shmem_inode_info *info = SHMEM_I(inode);
++ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
++
++ if (shmem_acct_block(info->flags, pages))
++ return false;
++
++ if (sbinfo->max_blocks) {
++ if (percpu_counter_compare(&sbinfo->used_blocks,
++ sbinfo->max_blocks - pages) > 0)
++ goto unacct;
++ percpu_counter_add(&sbinfo->used_blocks, pages);
++ }
++
++ return true;
++
++unacct:
++ shmem_unacct_blocks(info->flags, pages);
++ return false;
++}
++
++static inline void shmem_inode_unacct_blocks(struct inode *inode, long pages)
++{
++ struct shmem_inode_info *info = SHMEM_I(inode);
++ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
++
++ if (sbinfo->max_blocks)
++ percpu_counter_sub(&sbinfo->used_blocks, pages);
++ shmem_unacct_blocks(info->flags, pages);
++}
++
+ static const struct super_operations shmem_ops;
+ static const struct address_space_operations shmem_aops;
+ static const struct file_operations shmem_file_operations;
+@@ -248,31 +280,20 @@ static void shmem_recalc_inode(struct in
+
+ freed = info->alloced - info->swapped - inode->i_mapping->nrpages;
+ if (freed > 0) {
+- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+- if (sbinfo->max_blocks)
+- percpu_counter_add(&sbinfo->used_blocks, -freed);
+ info->alloced -= freed;
+ inode->i_blocks -= freed * BLOCKS_PER_PAGE;
+- shmem_unacct_blocks(info->flags, freed);
++ shmem_inode_unacct_blocks(inode, freed);
+ }
+ }
+
+ bool shmem_charge(struct inode *inode, long pages)
+ {
+ struct shmem_inode_info *info = SHMEM_I(inode);
+- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+ unsigned long flags;
+
+- if (shmem_acct_block(info->flags, pages))
++ if (!shmem_inode_acct_block(inode, pages))
+ return false;
+
+- if (sbinfo->max_blocks) {
+- if (percpu_counter_compare(&sbinfo->used_blocks,
+- sbinfo->max_blocks - pages) > 0)
+- goto unacct;
+- percpu_counter_add(&sbinfo->used_blocks, pages);
+- }
+-
+ spin_lock_irqsave(&info->lock, flags);
+ info->alloced += pages;
+ inode->i_blocks += pages * BLOCKS_PER_PAGE;
+@@ -281,16 +302,11 @@ bool shmem_charge(struct inode *inode, l
+ inode->i_mapping->nrpages += pages;
+
+ return true;
+-
+-unacct:
+- shmem_unacct_blocks(info->flags, pages);
+- return false;
+ }
+
+ void shmem_uncharge(struct inode *inode, long pages)
+ {
+ struct shmem_inode_info *info = SHMEM_I(inode);
+- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+@@ -299,9 +315,7 @@ void shmem_uncharge(struct inode *inode,
+ shmem_recalc_inode(inode);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+- if (sbinfo->max_blocks)
+- percpu_counter_sub(&sbinfo->used_blocks, pages);
+- shmem_unacct_blocks(info->flags, pages);
++ shmem_inode_unacct_blocks(inode, pages);
+ }
+
+ /*
+@@ -1450,9 +1464,10 @@ static struct page *shmem_alloc_page(gfp
+ }
+
+ static struct page *shmem_alloc_and_acct_page(gfp_t gfp,
+- struct shmem_inode_info *info, struct shmem_sb_info *sbinfo,
++ struct inode *inode,
+ pgoff_t index, bool huge)
+ {
++ struct shmem_inode_info *info = SHMEM_I(inode);
+ struct page *page;
+ int nr;
+ int err = -ENOSPC;
+@@ -1461,14 +1476,8 @@ static struct page *shmem_alloc_and_acct
+ huge = false;
+ nr = huge ? HPAGE_PMD_NR : 1;
+
+- if (shmem_acct_block(info->flags, nr))
++ if (!shmem_inode_acct_block(inode, nr))
+ goto failed;
+- if (sbinfo->max_blocks) {
+- if (percpu_counter_compare(&sbinfo->used_blocks,
+- sbinfo->max_blocks - nr) > 0)
+- goto unacct;
+- percpu_counter_add(&sbinfo->used_blocks, nr);
+- }
+
+ if (huge)
+ page = shmem_alloc_hugepage(gfp, info, index);
+@@ -1481,10 +1490,7 @@ static struct page *shmem_alloc_and_acct
+ }
+
+ err = -ENOMEM;
+- if (sbinfo->max_blocks)
+- percpu_counter_add(&sbinfo->used_blocks, -nr);
+-unacct:
+- shmem_unacct_blocks(info->flags, nr);
++ shmem_inode_unacct_blocks(inode, nr);
+ failed:
+ return ERR_PTR(err);
+ }
+@@ -1750,10 +1756,9 @@ repeat:
+ }
+
+ alloc_huge:
+- page = shmem_alloc_and_acct_page(gfp, info, sbinfo,
+- index, true);
++ page = shmem_alloc_and_acct_page(gfp, inode, index, true);
+ if (IS_ERR(page)) {
+-alloc_nohuge: page = shmem_alloc_and_acct_page(gfp, info, sbinfo,
++alloc_nohuge: page = shmem_alloc_and_acct_page(gfp, inode,
+ index, false);
+ }
+ if (IS_ERR(page)) {
+@@ -1875,10 +1880,7 @@ clear:
+ * Error recovery.
+ */
+ unacct:
+- if (sbinfo->max_blocks)
+- percpu_counter_sub(&sbinfo->used_blocks,
+- 1 << compound_order(page));
+- shmem_unacct_blocks(info->flags, 1 << compound_order(page));
++ shmem_inode_unacct_blocks(inode, 1 << compound_order(page));
+
+ if (PageTransHuge(page)) {
+ unlock_page(page);
+@@ -2214,7 +2216,6 @@ int shmem_mcopy_atomic_pte(struct mm_str
+ {
+ struct inode *inode = file_inode(dst_vma->vm_file);
+ struct shmem_inode_info *info = SHMEM_I(inode);
+- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+ struct address_space *mapping = inode->i_mapping;
+ gfp_t gfp = mapping_gfp_mask(mapping);
+ pgoff_t pgoff = linear_page_index(dst_vma, dst_addr);
+@@ -2226,19 +2227,13 @@ int shmem_mcopy_atomic_pte(struct mm_str
+ int ret;
+
+ ret = -ENOMEM;
+- if (shmem_acct_block(info->flags, 1))
++ if (!shmem_inode_acct_block(inode, 1))
+ goto out;
+- if (sbinfo->max_blocks) {
+- if (percpu_counter_compare(&sbinfo->used_blocks,
+- sbinfo->max_blocks) >= 0)
+- goto out_unacct_blocks;
+- percpu_counter_inc(&sbinfo->used_blocks);
+- }
+
+ if (!*pagep) {
+ page = shmem_alloc_page(gfp, info, pgoff);
+ if (!page)
+- goto out_dec_used_blocks;
++ goto out_unacct_blocks;
+
+ page_kaddr = kmap_atomic(page);
+ ret = copy_from_user(page_kaddr, (const void __user *)src_addr,
+@@ -2248,9 +2243,7 @@ int shmem_mcopy_atomic_pte(struct mm_str
+ /* fallback to copy_from_user outside mmap_sem */
+ if (unlikely(ret)) {
+ *pagep = page;
+- if (sbinfo->max_blocks)
+- percpu_counter_add(&sbinfo->used_blocks, -1);
+- shmem_unacct_blocks(info->flags, 1);
++ shmem_inode_unacct_blocks(inode, 1);
+ /* don't free the page */
+ return -EFAULT;
+ }
+@@ -2313,11 +2306,8 @@ out_release_uncharge:
+ out_release:
+ unlock_page(page);
+ put_page(page);
+-out_dec_used_blocks:
+- if (sbinfo->max_blocks)
+- percpu_counter_add(&sbinfo->used_blocks, -1);
+ out_unacct_blocks:
+- shmem_unacct_blocks(info->flags, 1);
++ shmem_inode_unacct_blocks(inode, 1);
+ goto out;
+ }
+
diff --git a/patches.fixes/shmem-shmem_charge-verify-max_block-is-not-exceeded-before-inode-update.patch b/patches.fixes/shmem-shmem_charge-verify-max_block-is-not-exceeded-before-inode-update.patch
new file mode 100644
index 0000000000..ea08c966ec
--- /dev/null
+++ b/patches.fixes/shmem-shmem_charge-verify-max_block-is-not-exceeded-before-inode-update.patch
@@ -0,0 +1,78 @@
+From: Mike Rapoport <rppt@linux.vnet.ibm.com>
+Date: Wed, 6 Sep 2017 16:22:56 -0700
+Subject: shmem: shmem_charge: verify max_block is not exceeded before inode
+ update
+Git-commit: b1cc94ab2f2ba31fcb2c59df0b9cf03f6d720553
+Patch-mainline: v4.14-rc1
+References: VM Functionality, bsc#1121599
+
+Patch series "userfaultfd: enable zeropage support for shmem".
+
+These patches enable support for UFFDIO_ZEROPAGE for shared memory.
+
+The first two patches are not strictly related to userfaultfd, they are
+just minor refactoring to reduce amount of code duplication.
+
+This patch (of 7):
+
+Currently we update inode and shmem_inode_info before verifying that
+used_blocks will not exceed max_blocks. In case it will, we undo the
+update. Let's switch the order and move the verification of the blocks
+count before the inode and shmem_inode_info update.
+
+Link: http://lkml.kernel.org/r/1497939652-16528-2-git-send-email-rppt@linux.vnet.ibm.com
+Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Hugh Dickins <hughd@google.com>
+Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
+Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
+Cc: Pavel Emelyanov <xemul@virtuozzo.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+---
+ mm/shmem.c | 25 ++++++++++++-------------
+ 1 file changed, 12 insertions(+), 13 deletions(-)
+
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -265,6 +265,14 @@ bool shmem_charge(struct inode *inode, l
+
+ if (shmem_acct_block(info->flags, pages))
+ return false;
++
++ if (sbinfo->max_blocks) {
++ if (percpu_counter_compare(&sbinfo->used_blocks,
++ sbinfo->max_blocks - pages) > 0)
++ goto unacct;
++ percpu_counter_add(&sbinfo->used_blocks, pages);
++ }
++
+ spin_lock_irqsave(&info->lock, flags);
+ info->alloced += pages;
+ inode->i_blocks += pages * BLOCKS_PER_PAGE;
+@@ -272,20 +280,11 @@ bool shmem_charge(struct inode *inode, l
+ spin_unlock_irqrestore(&info->lock, flags);
+ inode->i_mapping->nrpages += pages;
+
+- if (!sbinfo->max_blocks)
+- return true;
+- if (percpu_counter_compare(&sbinfo->used_blocks,
+- sbinfo->max_blocks - pages) > 0) {
+- inode->i_mapping->nrpages -= pages;
+- spin_lock_irqsave(&info->lock, flags);
+- info->alloced -= pages;
+- shmem_recalc_inode(inode);
+- spin_unlock_irqrestore(&info->lock, flags);
+- shmem_unacct_blocks(info->flags, pages);
+- return false;
+- }
+- percpu_counter_add(&sbinfo->used_blocks, pages);
+ return true;
++
++unacct:
++ shmem_unacct_blocks(info->flags, pages);
++ return false;
+ }
+
+ void shmem_uncharge(struct inode *inode, long pages)
diff --git a/patches.fixes/userfaultfd-shmem-add-i_size-checks.patch b/patches.fixes/userfaultfd-shmem-add-i_size-checks.patch
index 7d3d9d2bc0..698ad77370 100644
--- a/patches.fixes/userfaultfd-shmem-add-i_size-checks.patch
+++ b/patches.fixes/userfaultfd-shmem-add-i_size-checks.patch
@@ -44,8 +44,8 @@ Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+ pgoff_t offset, max_off;
ret = -ENOMEM;
- if (shmem_acct_block(info->flags, 1))
-@@ -2274,6 +2275,12 @@ int shmem_mcopy_atomic_pte(struct mm_str
+ if (!shmem_inode_acct_block(inode, 1))
+@@ -2266,6 +2267,12 @@ int shmem_mcopy_atomic_pte(struct mm_str
__SetPageSwapBacked(page);
__SetPageUptodate(page);
@@ -58,7 +58,7 @@ Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
ret = mem_cgroup_try_charge(page, dst_mm, gfp, &memcg, false);
if (ret)
goto out_release;
-@@ -2292,8 +2299,14 @@ int shmem_mcopy_atomic_pte(struct mm_str
+@@ -2284,8 +2291,14 @@ int shmem_mcopy_atomic_pte(struct mm_str
if (dst_vma->vm_flags & VM_WRITE)
_dst_pte = pte_mkwrite(pte_mkdirty(_dst_pte));
@@ -74,7 +74,7 @@ Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
if (!pte_none(*dst_pte))
goto out_release_uncharge_unlock;
-@@ -2311,13 +2324,14 @@ int shmem_mcopy_atomic_pte(struct mm_str
+@@ -2303,13 +2316,14 @@ int shmem_mcopy_atomic_pte(struct mm_str
/* No need to invalidate - it was non-present before */
update_mmu_cache(dst_vma, dst_addr, dst_pte);
diff --git a/series.conf b/series.conf
index bee7fc6d26..d863c63580 100644
--- a/series.conf
+++ b/series.conf
@@ -6120,6 +6120,8 @@
patches.fixes/dax-explain-how-read-2-write-2-addresses-are-validat.patch
patches.fixes/dax-use-PG_PMD_COLOUR-instead-of-open-coding.patch
patches.fixes/dax-initialize-variable-pfn-before-using-it.patch
+ patches.fixes/shmem-shmem_charge-verify-max_block-is-not-exceeded-before-inode-update.patch
+ patches.fixes/shmem-introduce-shmem_inode_acct_block.patch
patches.fixes/userfaultfd-mcopy_atomic-introduce-mfill_atomic_pte-helper.patch
patches.fixes/mm-hugetlb-do-not-allocate-non-migrateable-gigantic-pages-from-movable-zones.patch
patches.drivers/mm-devm_memremap_pages-use-multi-order-radix-for-ZON.patch
@@ -19450,6 +19452,15 @@
patches.fixes/userfaultfd-shmem-hugetlbfs-only-allow-to-register-vm_maywrite-vmas.patch
patches.fixes/userfaultfd-shmem-add-i_size-checks.patch
patches.fixes/userfaultfd-shmem-uffdio_copy-set-the-page-dirty-if-vm_write-is-not-set.patch
+ patches.fixes/mm-huge_memory-rename-freeze_page-to-unmap_page.patch
+ patches.fixes/mm-huge_memory-splitting-set-mapping-index-before-unfreeze.patch
+ patches.fixes/mm-huge_memory-fix-lockdep-complaint-on-32-bit-i_size_read.patch
+ patches.fixes/mm-khugepaged-collapse_shmem-stop-if-punched-or-truncated.patch
+ patches.fixes/mm-khugepaged-fix-crashes-due-to-misaccounted-holes.patch
+ patches.fixes/mm-khugepaged-collapse_shmem-remember-to-clear-holes.patch
+ patches.fixes/mm-khugepaged-minor-reorderings-in-collapse_shmem.patch
+ patches.fixes/mm-khugepaged-collapse_shmem-without-freezing-new_page.patch
+ patches.fixes/mm-khugepaged-collapse_shmem-do-not-crash-on-compound.patch
patches.drivers/pci-imx6-fix-link-training-status-detection-in-link-up-check
patches.fixes/fs-fix-lost-error-code-in-dio_complete.patch
patches.fixes/nvme-free-ctrl-device-name-on-init-failure.patch