From: Lukas Czerner <lczerner@redhat.com>
To: linux-fsdevel@vger.kernel.org
Cc: linux-ext4@vger.kernel.org, tytso@mit.edu, hughd@google.com,
linux-mmc@vger.kernel.org, Lukas Czerner <lczerner@redhat.com>,
Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH 01/15] mm: add invalidatepage_range address space operation
Date: Fri, 27 Jul 2012 10:01:00 +0200 [thread overview]
Message-ID: <1343376074-28034-2-git-send-email-lczerner@redhat.com> (raw)
In-Reply-To: <1343376074-28034-1-git-send-email-lczerner@redhat.com>
Currently there is no way to truncate partial page where the end
truncate point is not at the end of the page. This is because it was not
needed and the functionality was enough for file system truncate
operation to work properly. However more file systems now support punch
hole feature and it can benefit from mm supporting truncating page just
up to the certain point.
Specifically, with this functionality truncate_inode_pages_range() can
be changed so it supports truncating partial page at the end of the
range (currently it will BUG_ON() if 'end' is not at the end of the
page).
This commit add new address space operation invalidatepage_range which
allows specifying length of bytes to invalidate, rather than assuming
truncate to the end of the page. It also introduce
block_invalidatepage_range() and do_invalidatepage)range() functions for
exactly the same reason.
The caller does not have to implement both aops (invalidatepage and
invalidatepage_range) and the latter is preferred. The old method will be
used only if invalidatepage_range is not implemented by the caller.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Hugh Dickins <hughd@google.com>
---
fs/buffer.c | 23 ++++++++++++++++++++++-
include/linux/buffer_head.h | 2 ++
include/linux/fs.h | 2 ++
include/linux/mm.h | 2 ++
mm/truncate.c | 30 ++++++++++++++++++++++++++----
5 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index c7062c8..5937f30 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1457,13 +1457,27 @@ static void discard_buffer(struct buffer_head * bh)
*/
void block_invalidatepage(struct page *page, unsigned long offset)
{
+ block_invalidatepage_range(page, offset, PAGE_CACHE_SIZE);
+}
+EXPORT_SYMBOL(block_invalidatepage);
+
+void block_invalidatepage_range(struct page *page, unsigned long offset,
+ unsigned long length)
+{
struct buffer_head *head, *bh, *next;
unsigned int curr_off = 0;
+ unsigned long stop = length + offset;
BUG_ON(!PageLocked(page));
if (!page_has_buffers(page))
goto out;
+ /*
+ * Check for overflow
+ */
+ if (stop < length)
+ stop = PAGE_CACHE_SIZE;
+
head = page_buffers(page);
bh = head;
do {
@@ -1471,6 +1485,12 @@ void block_invalidatepage(struct page *page, unsigned long offset)
next = bh->b_this_page;
/*
+ * Are we still fully in range ?
+ */
+ if (next_off > stop)
+ goto out;
+
+ /*
* is this block fully invalidated?
*/
if (offset <= curr_off)
@@ -1489,7 +1509,8 @@ void block_invalidatepage(struct page *page, unsigned long offset)
out:
return;
}
-EXPORT_SYMBOL(block_invalidatepage);
+EXPORT_SYMBOL(block_invalidatepage_range);
+
/*
* We attach and possibly dirty the buffers atomically wrt
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 458f497..9d55645 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -194,6 +194,8 @@ extern int buffer_heads_over_limit;
* address_spaces.
*/
void block_invalidatepage(struct page *page, unsigned long offset);
+void block_invalidatepage_range(struct page *page, unsigned long offset,
+ unsigned long length);
int block_write_full_page(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
int block_write_full_page_endio(struct page *page, get_block_t *get_block,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8fabb03..b9eaf0c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -620,6 +620,8 @@ struct address_space_operations {
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
sector_t (*bmap)(struct address_space *, sector_t);
void (*invalidatepage) (struct page *, unsigned long);
+ void (*invalidatepage_range) (struct page *, unsigned long,
+ unsigned long);
int (*releasepage) (struct page *, gfp_t);
void (*freepage)(struct page *);
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f9f279c..2db6a29 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -998,6 +998,8 @@ struct page *get_dump_page(unsigned long addr);
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
extern void do_invalidatepage(struct page *page, unsigned long offset);
+extern void do_invalidatepage_range(struct page *page, unsigned long offset,
+ unsigned long length);
int __set_page_dirty_nobuffers(struct page *page);
int __set_page_dirty_no_writeback(struct page *page);
diff --git a/mm/truncate.c b/mm/truncate.c
index 75801ac..e29e5ea 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -39,14 +39,36 @@
*/
void do_invalidatepage(struct page *page, unsigned long offset)
{
+ do_invalidatepage_range(page, offset, PAGE_CACHE_SIZE);
+}
+
+void do_invalidatepage_range(struct page *page, unsigned long offset,
+ unsigned long length)
+{
+ void (*invalidatepage_range)(struct page *, unsigned long,
+ unsigned long);
void (*invalidatepage)(struct page *, unsigned long);
+
+ /*
+ * Try invalidatepage_range first
+ */
+ invalidatepage_range = page->mapping->a_ops->invalidatepage_range;
+ if (invalidatepage_range)
+ (*invalidatepage_range)(page, offset, length);
+
+ /*
+ * When only invalidatepage is registered length must be
+ * PAGE_CACHE_SIZE
+ */
invalidatepage = page->mapping->a_ops->invalidatepage;
+ if (invalidatepage) {
+ BUG_ON(length != PAGE_CACHE_SIZE);
+ (*invalidatepage)(page, offset);
+ }
#ifdef CONFIG_BLOCK
- if (!invalidatepage)
- invalidatepage = block_invalidatepage;
+ if (!invalidatepage_range && !invalidatepage)
+ block_invalidatepage_range(page, offset, length);
#endif
- if (invalidatepage)
- (*invalidatepage)(page, offset);
}
static inline void truncate_partial_page(struct page *page, unsigned partial)
--
1.7.7.6
next prev parent reply other threads:[~2012-07-27 8:01 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-27 8:00 Add invalidatepage_range address space operation Lukas Czerner
2012-07-27 8:01 ` Lukas Czerner [this message]
2012-08-20 5:24 ` [PATCH 01/15] mm: add " Hugh Dickins
[not found] ` <5033a999.0f403a0a.19c3.ffff95deSMTPIN_ADDED@mx.google.com>
2012-08-21 18:59 ` Hugh Dickins
2012-07-27 8:01 ` [PATCH 02/15] jbd2: implement jbd2_journal_invalidatepage_range Lukas Czerner
2012-07-27 8:01 ` [PATCH 03/15] ext4: implement invalidatepage_range aop Lukas Czerner
2012-07-27 8:01 ` [PATCH 04/15] xfs: " Lukas Czerner
2012-07-27 8:01 ` [PATCH 05/15] ocfs2: " Lukas Czerner
2012-07-27 8:01 ` [PATCH 06/15] mm: teach truncate_inode_pages_range() to handle non page aligned ranges Lukas Czerner
2012-08-20 4:52 ` Hugh Dickins
2012-08-20 10:26 ` Lukáš Czerner
2012-08-20 15:47 ` Hugh Dickins
[not found] ` <50339e0d.69b2340a.50ba.ffff92bcSMTPIN_ADDED@mx.google.com>
2012-08-21 18:44 ` Hugh Dickins
2012-08-20 15:53 ` Hugh Dickins
2012-07-27 8:01 ` [PATCH 07/15] ext4: Take i_mutex before punching hole Lukas Czerner
2012-07-27 9:04 ` Lukáš Czerner
2012-07-27 12:08 ` Zheng Liu
2012-08-20 5:45 ` Hugh Dickins
2012-07-27 8:01 ` [PATCH 08/15] Revert "ext4: remove no longer used functions in inode.c" Lukas Czerner
2012-07-27 8:01 ` [PATCH 09/15] Revert "ext4: fix fsx truncate failure" Lukas Czerner
2012-07-27 8:01 ` [PATCH 10/15] ext4: use ext4_zero_partial_blocks in punch_hole Lukas Czerner
2012-07-27 8:01 ` [PATCH 11/15] ext4: remove unused discard_partial_page_buffers Lukas Czerner
2012-07-27 8:01 ` [PATCH 12/15] ext4: remove unused code from ext4_remove_blocks() Lukas Czerner
2012-07-27 8:01 ` [PATCH 13/15] ext4: update ext4_ext_remove_space trace point Lukas Czerner
2012-07-27 8:01 ` [PATCH 14/15] ext4: make punch hole code path work with bigalloc Lukas Czerner
2012-07-27 8:01 ` [PATCH 15/15] ext4: Allow punch hole with bigalloc enabled Lukas Czerner
2012-08-19 0:57 ` Add invalidatepage_range address space operation Theodore Ts'o
2012-08-20 4:43 ` Hugh Dickins
2012-08-20 13:23 ` Theodore Ts'o
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=1343376074-28034-2-git-send-email-lczerner@redhat.com \
--to=lczerner@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=hughd@google.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mmc@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).