From db207012f9f8c58bd5fce8e0199e5f960e6a4ef3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 24 Jul 2014 14:41:34 -0700 Subject: [PATCH] 3.10-stable patches added patches: shmem-fix-splicing-from-a-hole-while-it-s-punched.patch --- queue-3.10/series | 1 + ...icing-from-a-hole-while-it-s-punched.patch | 129 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 queue-3.10/shmem-fix-splicing-from-a-hole-while-it-s-punched.patch diff --git a/queue-3.10/series b/queue-3.10/series index e585a93199d..e48af28e5f8 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -12,3 +12,4 @@ igb-do-a-reset-on-sr-iov-re-init-if-device-is-down.patch iwlwifi-dvm-don-t-enable-cts-to-self.patch shmem-fix-faulting-into-a-hole-while-it-s-punched.patch shmem-fix-faulting-into-a-hole-not-taking-i_mutex.patch +shmem-fix-splicing-from-a-hole-while-it-s-punched.patch diff --git a/queue-3.10/shmem-fix-splicing-from-a-hole-while-it-s-punched.patch b/queue-3.10/shmem-fix-splicing-from-a-hole-while-it-s-punched.patch new file mode 100644 index 00000000000..59e3d93d7d0 --- /dev/null +++ b/queue-3.10/shmem-fix-splicing-from-a-hole-while-it-s-punched.patch @@ -0,0 +1,129 @@ +From b1a366500bd537b50c3aad26dc7df083ec03a448 Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Wed, 23 Jul 2014 14:00:13 -0700 +Subject: shmem: fix splicing from a hole while it's punched + +From: Hugh Dickins + +commit b1a366500bd537b50c3aad26dc7df083ec03a448 upstream. + +shmem_fault() is the actual culprit in trinity's hole-punch starvation, +and the most significant cause of such problems: since a page faulted is +one that then appears page_mapped(), needing unmap_mapping_range() and +i_mmap_mutex to be unmapped again. + +But it is not the only way in which a page can be brought into a hole in +the radix_tree while that hole is being punched; and Vlastimil's testing +implies that if enough other processors are busy filling in the hole, +then shmem_undo_range() can be kept from completing indefinitely. + +shmem_file_splice_read() is the main other user of SGP_CACHE, which can +instantiate shmem pagecache pages in the read-only case (without holding +i_mutex, so perhaps concurrently with a hole-punch). Probably it's +silly not to use SGP_READ already (using the ZERO_PAGE for holes): which +ought to be safe, but might bring surprises - not a change to be rushed. + +shmem_read_mapping_page_gfp() is an internal interface used by +drivers/gpu/drm GEM (and next by uprobes): it should be okay. And +shmem_file_read_iter() uses the SGP_DIRTY variant of SGP_CACHE, when +called internally by the kernel (perhaps for a stacking filesystem, +which might rely on holes to be reserved): it's unclear whether it could +be provoked to keep hole-punch busy or not. + +We could apply the same umbrella as now used in shmem_fault() to +shmem_file_splice_read() and the others; but it looks ugly, and use over +a range raises questions - should it actually be per page? can these get +starved themselves? + +The origin of this part of the problem is my v3.1 commit d0823576bf4b +("mm: pincer in truncate_inode_pages_range"), once it was duplicated +into shmem.c. It seemed like a nice idea at the time, to ensure +(barring RCU lookup fuzziness) that there's an instant when the entire +hole is empty; but the indefinitely repeated scans to ensure that make +it vulnerable. + +Revert that "enhancement" to hole-punch from shmem_undo_range(), but +retain the unproblematic rescanning when it's truncating; add a couple +of comments there. + +Remove the "indices[0] >= end" test: that is now handled satisfactorily +by the inner loop, and mem_cgroup_uncharge_start()/end() are too light +to be worth avoiding here. + +But if we do not always loop indefinitely, we do need to handle the case +of swap swizzled back to page before shmem_free_swap() gets it: add a +retry for that case, as suggested by Konstantin Khlebnikov; and for the +case of page swizzled back to swap, as suggested by Johannes Weiner. + +Signed-off-by: Hugh Dickins +Reported-by: Sasha Levin +Suggested-by: Vlastimil Babka +Cc: Konstantin Khlebnikov +Cc: Johannes Weiner +Cc: Lukas Czerner +Cc: Dave Jones +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + + +--- + mm/shmem.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -534,22 +534,19 @@ static void shmem_undo_range(struct inod + return; + + index = start; +- for ( ; ; ) { ++ while (index < end) { + cond_resched(); + pvec.nr = shmem_find_get_pages_and_swap(mapping, index, + min(end - index, (pgoff_t)PAGEVEC_SIZE), + pvec.pages, indices); + if (!pvec.nr) { +- if (index == start || unfalloc) ++ /* If all gone or hole-punch or unfalloc, we're done */ ++ if (index == start || end != -1) + break; ++ /* But if truncating, restart to make sure all gone */ + index = start; + continue; + } +- if ((index == start || unfalloc) && indices[0] >= end) { +- shmem_deswap_pagevec(&pvec); +- pagevec_release(&pvec); +- break; +- } + mem_cgroup_uncharge_start(); + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; +@@ -561,8 +558,12 @@ static void shmem_undo_range(struct inod + if (radix_tree_exceptional_entry(page)) { + if (unfalloc) + continue; +- nr_swaps_freed += !shmem_free_swap(mapping, +- index, page); ++ if (shmem_free_swap(mapping, index, page)) { ++ /* Swap was replaced by page: retry */ ++ index--; ++ break; ++ } ++ nr_swaps_freed++; + continue; + } + +@@ -571,6 +572,11 @@ static void shmem_undo_range(struct inod + if (page->mapping == mapping) { + VM_BUG_ON(PageWriteback(page)); + truncate_inode_page(mapping, page); ++ } else { ++ /* Page was replaced by swap: retry */ ++ unlock_page(page); ++ index--; ++ break; + } + } + unlock_page(page); -- 2.47.3