linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lukas Czerner <lczerner@redhat.com>
To: linux-ext4@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org, tytso@mit.edu,
	achender@linux.vnet.ibm.com, Lukas Czerner <lczerner@redhat.com>,
	Hugh Dickins <hughd@google.com>
Subject: [PATCH 06/12 v2] mm: teach truncate_inode_pages_range() to hadnle non page aligned ranges
Date: Fri, 13 Jul 2012 15:19:09 +0200	[thread overview]
Message-ID: <1342185555-21146-6-git-send-email-lczerner@redhat.com> (raw)
In-Reply-To: <1342185555-21146-1-git-send-email-lczerner@redhat.com>

This commit changes truncate_inode_pages_range() so it can handle non
page aligned regions of the truncate. Currently we can hit BUG_ON when
the end of the range is not page aligned, but he can handle unaligned
start of the range.

Being able to handle non page aligned regions of the page can help file
system punch_hole implementations and save some work, because once we're
holding the page we might as well deal with it right away.

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
---
 mm/truncate.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/mm/truncate.c b/mm/truncate.c
index 77a693e..92aa4ad 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -49,6 +49,16 @@ void do_invalidatepage(struct page *page, unsigned long offset)
 		(*invalidatepage)(page, offset);
 }
 
+static inline void punch_hole_into_page(struct page *page, unsigned start,
+					unsigned end)
+{
+	BUG_ON(end > PAGE_CACHE_SIZE);
+	zero_user_segment(page, start, end);
+	cleancache_invalidate_page(page->mapping, page);
+	if (page_has_private(page))
+		do_invalidatepage(page, start);
+}
+
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
 	zero_user_segment(page, partial, PAGE_CACHE_SIZE);
@@ -206,24 +216,30 @@ int invalidate_inode_page(struct page *page)
 void truncate_inode_pages_range(struct address_space *mapping,
 				loff_t lstart, loff_t lend)
 {
-	const pgoff_t start = (lstart + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
-	const unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
+	const unsigned partial_start = lstart & (PAGE_CACHE_SIZE - 1);
+	const unsigned partial_end = lend & (PAGE_CACHE_SIZE - 1);
+	loff_t start = lstart >> PAGE_CACHE_SHIFT;
+	loff_t end = lend >> PAGE_CACHE_SHIFT;
 	struct pagevec pvec;
-	pgoff_t index;
-	pgoff_t end;
+	loff_t index;
 	int i;
 
+	BUG_ON(lend < start || lend < 0);
+
 	cleancache_invalidate_inode(mapping);
 	if (mapping->nrpages == 0)
 		return;
 
-	BUG_ON((lend & (PAGE_CACHE_SIZE - 1)) != (PAGE_CACHE_SIZE - 1));
-	end = (lend >> PAGE_CACHE_SHIFT);
+	/* Adjust start and end so we cover only full pages */
+	if (partial_start)
+		start++;
+	if (partial_end < PAGE_CACHE_SIZE - 1)
+		end--;
 
 	pagevec_init(&pvec, 0);
 	index = start;
 	while (index <= end && pagevec_lookup(&pvec, mapping, index,
-			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
+			min(end - index, (loff_t)PAGEVEC_SIZE - 1) + 1)) {
 		mem_cgroup_uncharge_start();
 		for (i = 0; i < pagevec_count(&pvec); i++) {
 			struct page *page = pvec.pages[i];
@@ -249,21 +265,44 @@ void truncate_inode_pages_range(struct address_space *mapping,
 		index++;
 	}
 
-	if (partial) {
+	/* truncate happened within the page - punch hole */
+	if ((start > end) && (start - end > 1)) {
 		struct page *page = find_lock_page(mapping, start - 1);
 		if (page) {
 			wait_on_page_writeback(page);
-			truncate_partial_page(page, partial);
+			punch_hole_into_page(page, partial_start,
+					     partial_end + 1);
 			unlock_page(page);
 			page_cache_release(page);
 		}
+	} else {
+		/* Partial page truncate at the start of the region */
+		if (partial_start) {
+			struct page *page = find_lock_page(mapping, start - 1);
+			if (page) {
+				wait_on_page_writeback(page);
+				truncate_partial_page(page, partial_start);
+				unlock_page(page);
+				page_cache_release(page);
+			}
+		}
+		/* Partial page truncate at the end of the region */
+		if (partial_end < PAGE_CACHE_SIZE - 1) {
+			struct page *page = find_lock_page(mapping, end + 1);
+			if (page) {
+				wait_on_page_writeback(page);
+				punch_hole_into_page(page, 0, partial_end + 1);
+				unlock_page(page);
+				page_cache_release(page);
+			}
+		}
 	}
 
 	index = start;
-	for ( ; ; ) {
+	while (index <= end) {
 		cond_resched();
 		if (!pagevec_lookup(&pvec, mapping, index,
-			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
+			min(end - index, (loff_t)PAGEVEC_SIZE - 1) + 1)) {
 			if (index == start)
 				break;
 			index = start;
-- 
1.7.7.6


  parent reply	other threads:[~2012-07-13 13:19 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-13 13:19 [PATCH 01/12 v2] Revert "ext4: remove no longer used functions in inode.c" Lukas Czerner
2012-07-13 13:19 ` [PATCH 02/12 v2] Revert "ext4: fix fsx truncate failure" Lukas Czerner
2012-07-13 17:42   ` Theodore Ts'o
2012-07-14  7:45     ` Christoph Hellwig
2012-07-16  7:35     ` Lukáš Czerner
2012-07-16 21:41       ` Hugh Dickins
2012-07-17  7:53         ` Lukáš Czerner
2012-07-18 19:34   ` Eric Sandeen
2012-07-19  6:45     ` Lukáš Czerner
2012-07-13 13:19 ` [PATCH 03/12 v2] shmem: pass LLONG_MAX to shmem_truncate_range Lukas Czerner
2012-07-18 19:54   ` Eric Sandeen
2012-07-19  6:40     ` Lukáš Czerner
2012-07-13 13:19 ` [PATCH 04/12 v2] xfs: pass LLONG_MAX to truncate_inode_pages_range Lukas Czerner
2012-07-15 23:11   ` Dave Chinner
2012-07-16  7:13     ` Lukáš Czerner
2012-07-16 11:52       ` Lukáš Czerner
2012-07-13 13:19 ` [PATCH 05/12 v2] mm: " Lukas Czerner
2012-07-13 13:19 ` Lukas Czerner [this message]
2012-07-17  8:28   ` [PATCH 06/12 v2] mm: teach truncate_inode_pages_range() to hadnle non page aligned ranges Hugh Dickins
2012-07-17 11:57     ` Lukáš Czerner
2012-07-17 12:16       ` Lukáš Czerner
2012-07-18  8:18         ` Lukáš Czerner
2012-07-18 19:36           ` Hugh Dickins
2012-07-19  7:15             ` Lukáš Czerner
2012-07-19 23:07               ` Dave Chinner
2012-07-13 13:19 ` [PATCH 07/12 v2] ext4: use ext4_zero_partial_blocks in punch_hole Lukas Czerner
2012-07-13 13:19 ` [PATCH 08/12 v2] ext4: remove unused discard_partial_page_buffers Lukas Czerner
2012-07-13 13:19 ` [PATCH 09/12 v2] ext4: remove unused code from ext4_remove_blocks() Lukas Czerner
2012-07-13 13:19 ` [PATCH 10/12 v2] ext4: update ext4_ext_remove_space trace point Lukas Czerner
2012-07-13 13:19 ` [PATCH 11/12 v2] ext4: make punch hole code path work with bigalloc Lukas Czerner
2012-07-13 13:19 ` [PATCH 12/12 v2] ext4: Allow punch hole with bigalloc enabled Lukas Czerner

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=1342185555-21146-6-git-send-email-lczerner@redhat.com \
    --to=lczerner@redhat.com \
    --cc=achender@linux.vnet.ibm.com \
    --cc=hughd@google.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=tytso@mit.edu \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).