All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Wilcox <willy@infradead.org>
To: linux-fsdevel@vger.kernel.org
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: [PATCH v6 42/51] mm: Handle truncates that split THPs
Date: Wed, 10 Jun 2020 13:13:36 -0700	[thread overview]
Message-ID: <20200610201345.13273-43-willy@infradead.org> (raw)
In-Reply-To: <20200610201345.13273-1-willy@infradead.org>

From: "Matthew Wilcox (Oracle)" <willy@infradead.org>

Move shmem_punch_compound() to truncate.c and rename it to punch_thp().
Change its arguments to loff_t to make calling do_invalidatepage()
easier.  Call it when we find a THP in the cache.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 mm/internal.h |  2 ++
 mm/shmem.c    | 30 ++-------------------------
 mm/truncate.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 59 insertions(+), 30 deletions(-)

diff --git a/mm/internal.h b/mm/internal.h
index ac3c79408045..cd7038a36354 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -613,4 +613,6 @@ static inline bool is_migrate_highatomic_page(struct page *page)
 
 void setup_zone_pageset(struct zone *zone);
 extern struct page *alloc_new_node_page(struct page *page, unsigned long node);
+
+bool punch_thp(struct page *page, loff_t start, loff_t end);
 #endif	/* __MM_INTERNAL_H */
diff --git a/mm/shmem.c b/mm/shmem.c
index 55405d811cfd..495b8684d94a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -804,32 +804,6 @@ void shmem_unlock_mapping(struct address_space *mapping)
 	}
 }
 
-/*
- * Check whether a hole-punch or truncation needs to split a huge page,
- * returning true if no split was required, or the split has been successful.
- *
- * Eviction (or truncation to 0 size) should never need to split a huge page;
- * but in rare cases might do so, if shmem_undo_range() failed to trylock on
- * head, and then succeeded to trylock on tail.
- *
- * A split can only succeed when there are no additional references on the
- * huge page: so the split below relies upon find_get_entries() having stopped
- * when it found a subpage of the huge page, without getting further references.
- */
-static bool shmem_punch_compound(struct page *page, pgoff_t start, pgoff_t end)
-{
-	if (!PageTransCompound(page))
-		return true;
-
-	/* Just proceed to delete a huge page wholly within the range punched */
-	if (PageHead(page) &&
-	    page->index >= start && page->index + HPAGE_PMD_NR <= end)
-		return true;
-
-	/* Try to split huge page, so we can truly punch the hole or truncate */
-	return split_huge_page(page) >= 0;
-}
-
 /*
  * Remove range of pages and swap entries from page cache, and free them.
  * If !unfalloc, truncate or punch hole; if unfalloc, undo failed fallocate.
@@ -883,7 +857,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
 			if ((!unfalloc || !PageUptodate(page)) &&
 			    page_mapping(page) == mapping) {
 				VM_BUG_ON_PAGE(PageWriteback(page), page);
-				if (shmem_punch_compound(page, start, end))
+				if (punch_thp(page, lstart, lend))
 					truncate_inode_page(mapping, page);
 			}
 			unlock_page(page);
@@ -973,7 +947,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
 					break;
 				}
 				VM_BUG_ON_PAGE(PageWriteback(page), page);
-				if (shmem_punch_compound(page, start, end))
+				if (punch_thp(page, lstart, lend))
 					truncate_inode_page(mapping, page);
 				else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 					/* Wipe the page and don't get stuck */
diff --git a/mm/truncate.c b/mm/truncate.c
index a9fde773179b..0ef2001c2f65 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -229,6 +229,55 @@ int truncate_inode_page(struct address_space *mapping, struct page *page)
 	return 0;
 }
 
+/*
+ * Check whether a hole-punch or truncation needs to split a huge page,
+ * returning true if no split was required, or the split has been
+ * successful.
+ *
+ * Eviction (or truncation to 0 size) should never need to split a huge
+ * page; but in rare cases might do so, if shmem_undo_range() failed to
+ * trylock on head, and then succeeded to trylock on tail.
+ *
+ * A split can only succeed when there are no additional references on
+ * the huge page: so the split below relies upon find_get_entries()
+ * having stopped when it found a subpage of the huge page, without
+ * getting further references.
+ */
+bool punch_thp(struct page *page, loff_t start, loff_t end)
+{
+	struct page *head = thp_head(page);
+	loff_t pos = page_offset(head);
+	unsigned int offset, length;
+
+	if (!PageTransCompound(page))
+		return true;
+
+	if (pos < start)
+		offset = start - pos;
+	else
+		offset = 0;
+	length = thp_size(head);
+	if (pos + length < end)
+		length = length - offset;
+	else
+		length = end - pos - offset;
+
+	/* Just proceed to delete a huge page wholly within the range punched */
+	if (length == thp_size(head))
+		return true;
+
+	/*
+	 * We're going to split the page into order-0 pages.  Tell the
+	 * filesystem which range of the page is going to be punched out
+	 * so it can discard unnecessary private data.
+	 */
+	if (page_has_private(head))
+		do_invalidatepage(head, offset, length);
+
+	/* Try to split huge page, so we can truly punch the hole or truncate */
+	return split_huge_page(page) >= 0;
+}
+
 /*
  * Used to get rid of pages on hardware memory corruption.
  */
@@ -359,7 +408,10 @@ void truncate_inode_pages_range(struct address_space *mapping,
 				unlock_page(page);
 				continue;
 			}
-			pagevec_add(&locked_pvec, page);
+			if (punch_thp(page, lstart, lend))
+				pagevec_add(&locked_pvec, page);
+			else
+				unlock_page(page);
 		}
 		for (i = 0; i < pagevec_count(&locked_pvec); i++)
 			truncate_cleanup_page(mapping, locked_pvec.pages[i]);
@@ -453,7 +505,8 @@ void truncate_inode_pages_range(struct address_space *mapping,
 			lock_page(page);
 			WARN_ON(page_to_index(page) != index);
 			wait_on_page_writeback(page);
-			truncate_inode_page(mapping, page);
+			if (punch_thp(page, lstart, lend))
+				truncate_inode_page(mapping, page);
 			unlock_page(page);
 		}
 		truncate_exceptional_pvec_entries(mapping, &pvec, indices, end);
-- 
2.26.2


  parent reply	other threads:[~2020-06-10 20:15 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-10 20:12 [RFC v6 00/51] Large pages in the page cache Matthew Wilcox
2020-06-10 20:12 ` [PATCH v6 01/51] mm: Print head flags in dump_page Matthew Wilcox
2020-06-10 20:12 ` [PATCH v6 02/51] mm: Print the inode number " Matthew Wilcox
2020-06-10 20:12 ` [PATCH v6 03/51] mm: Print hashed address of struct page Matthew Wilcox
2020-06-10 20:12 ` [PATCH v6 04/51] mm: Move PageDoubleMap bit Matthew Wilcox
2020-06-11 15:03   ` Zi Yan
2020-06-10 20:12 ` [PATCH v6 05/51] mm: Simplify PageDoubleMap with PF_SECOND policy Matthew Wilcox
2020-06-11 15:14   ` Zi Yan
2020-06-10 20:13 ` [PATCH v6 06/51] mm: Store compound_nr as well as compound_order Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 07/51] mm: Move page-flags include to top of file Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 08/51] mm: Add thp_order Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 09/51] mm: Add thp_size Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 10/51] mm: Replace hpage_nr_pages with thp_nr_pages Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 11/51] mm: Add thp_head Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 12/51] mm: Introduce offset_in_thp Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 13/51] mm: Support arbitrary THP sizes Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 14/51] fs: Add a filesystem flag for THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 15/51] fs: Do not update nr_thps for mappings which support THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 16/51] fs: Introduce i_blocks_per_page Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 17/51] fs: Make page_mkwrite_check_truncate thp-aware Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 18/51] mm: Support THPs in zero_user_segments Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 19/51] mm: Zero the head page, not the tail page Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 20/51] block: Add bio_for_each_thp_segment_all Matthew Wilcox
2020-06-11 18:20   ` Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 21/51] block: Support THPs in page_is_mergeable Matthew Wilcox
2020-06-12 16:17   ` Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 22/51] iomap: Support arbitrarily many blocks per page Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 23/51] iomap: Support THPs in iomap_adjust_read_range Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 24/51] iomap: Support THPs in invalidatepage Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 25/51] iomap: Support THPs in read paths Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 26/51] iomap: Convert iomap_write_end types Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 27/51] iomap: Change calling convention for zeroing Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 28/51] iomap: Change iomap_write_begin calling convention Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 29/51] iomap: Support THPs in write paths Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 30/51] iomap: Inline data shouldn't see THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 31/51] iomap: Handle tail pages in iomap_page_mkwrite Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 32/51] xfs: Support THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 33/51] mm: Make prep_transhuge_page return its argument Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 34/51] mm: Add __page_cache_alloc_order Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 35/51] mm: Allow THPs to be added to the page cache Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 36/51] mm: Allow THPs to be removed from " Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 37/51] mm: Remove page fault assumption of compound page size Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 38/51] mm: Fix total_mapcount assumption of " Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 39/51] mm: Remove assumptions of THP size Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 40/51] mm: Avoid splitting THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 41/51] mm: Fix truncation for pages of arbitrary size Matthew Wilcox
2020-06-10 20:13 ` Matthew Wilcox [this message]
2020-06-10 20:13 ` [PATCH v6 43/51] mm: Support storing shadow entries for THPs Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 44/51] mm: Support retrieving tail pages from the page cache Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 45/51] mm: Support tail pages in wait_for_stable_page Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 46/51] mm: Add DEFINE_READAHEAD Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 47/51] mm: Make page_cache_readahead_unbounded take a readahead_control Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 48/51] mm: Make __do_page_cache_readahead " Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 49/51] mm: Allow PageReadahead to be set on head pages Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 50/51] mm: Add THP readahead Matthew Wilcox
2020-06-10 20:13 ` [PATCH v6 51/51] mm: Align THP mappings for non-DAX Matthew Wilcox
2020-06-11  6:59 ` [RFC v6 00/51] Large pages in the page cache Christoph Hellwig
2020-06-11 11:24   ` Matthew Wilcox
2020-06-15 13:32     ` Christoph Hellwig
2020-06-14 16:26 ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200610201345.13273-43-willy@infradead.org \
    --to=willy@infradead.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.