Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d47992f8 authored by Lukas Czerner's avatar Lukas Czerner Committed by Theodore Ts'o
Browse files

mm: change invalidatepage prototype to accept length



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 changes the invalidatepage() address space operation
prototype to accept range to be invalidated and update all the instances
for it.

We also change the block_invalidatepage() in the same way and actually
make a use of the new length argument implementing range invalidation.

Actual file system implementations will follow except the file systems
where the changes are really simple and should not change the behaviour
in any way .Implementation for truncate_page_range() which will be able
to accept page unaligned ranges will follow as well.

Signed-off-by: default avatarLukas Czerner <lczerner@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Hugh Dickins <hughd@google.com>
parent c7788792
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ prototypes:
				loff_t pos, unsigned len, unsigned copied,
				struct page *page, void *fsdata);
	sector_t (*bmap)(struct address_space *, sector_t);
	int (*invalidatepage) (struct page *, unsigned long);
	void (*invalidatepage) (struct page *, unsigned int, unsigned int);
	int (*releasepage) (struct page *, int);
	void (*freepage)(struct page *);
	int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
+10 −10
Original line number Diff line number Diff line
@@ -549,7 +549,7 @@ struct address_space_operations
-------------------------------

This describes how the VFS can manipulate mapping of a file to page cache in
your filesystem. As of kernel 2.6.22, the following members are defined:
your filesystem. The following members are defined:

struct address_space_operations {
	int (*writepage)(struct page *page, struct writeback_control *wbc);
@@ -566,7 +566,7 @@ struct address_space_operations {
				loff_t pos, unsigned len, unsigned copied,
				struct page *page, void *fsdata);
	sector_t (*bmap)(struct address_space *, sector_t);
	int (*invalidatepage) (struct page *, unsigned long);
	void (*invalidatepage) (struct page *, unsigned int, unsigned int);
	int (*releasepage) (struct page *, int);
	void (*freepage)(struct page *);
	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
@@ -685,13 +685,13 @@ struct address_space_operations {
  invalidatepage: If a page has PagePrivate set, then invalidatepage
        will be called when part or all of the page is to be removed
	from the address space.  This generally corresponds to either a
	truncation or a complete invalidation of the address space
	(in the latter case 'offset' will always be 0).
	Any private data associated with the page should be updated
	to reflect this truncation.  If offset is 0, then
	the private data should be released, because the page
	must be able to be completely discarded.  This may be done by
        calling the ->releasepage function, but in this case the
	truncation, punch hole  or a complete invalidation of the address
	space (in the latter case 'offset' will always be 0 and 'length'
	will be PAGE_CACHE_SIZE). Any private data associated with the page
	should be updated to reflect this truncation.  If offset is 0 and
	length is PAGE_CACHE_SIZE, then the private data should be released,
	because the page must be able to be completely discarded.  This may
	be done by calling the ->releasepage function, but in this case the
	release MUST succeed.

  releasepage: releasepage is called on PagePrivate pages to indicate
+3 −2
Original line number Diff line number Diff line
@@ -148,13 +148,14 @@ static int v9fs_release_page(struct page *page, gfp_t gfp)
 * @offset: offset in the page
 */

static void v9fs_invalidate_page(struct page *page, unsigned long offset)
static void v9fs_invalidate_page(struct page *page, unsigned int offset,
				 unsigned int length)
{
	/*
	 * If called with zero offset, we should release
	 * the private state assocated with the page
	 */
	if (offset == 0)
	if (offset == 0 && length == PAGE_CACHE_SIZE)
		v9fs_fscache_invalidate_page(page);
}

+6 −4
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@
#include "internal.h"

static int afs_readpage(struct file *file, struct page *page);
static void afs_invalidatepage(struct page *page, unsigned long offset);
static void afs_invalidatepage(struct page *page, unsigned int offset,
			       unsigned int length);
static int afs_releasepage(struct page *page, gfp_t gfp_flags);
static int afs_launder_page(struct page *page);

@@ -310,16 +311,17 @@ static int afs_launder_page(struct page *page)
 * - release a page and clean up its private data if offset is 0 (indicating
 *   the entire page)
 */
static void afs_invalidatepage(struct page *page, unsigned long offset)
static void afs_invalidatepage(struct page *page, unsigned int offset,
			       unsigned int length)
{
	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);

	_enter("{%lu},%lu", page->index, offset);
	_enter("{%lu},%u,%u", page->index, offset, length);

	BUG_ON(!PageLocked(page));

	/* we clean up only if the entire page is being invalidated */
	if (offset == 0) {
	if (offset == 0 && length == PAGE_CACHE_SIZE) {
#ifdef CONFIG_AFS_FSCACHE
		if (PageFsCache(page)) {
			struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+2 −1
Original line number Diff line number Diff line
@@ -1013,7 +1013,8 @@ static int btree_releasepage(struct page *page, gfp_t gfp_flags)
	return try_release_extent_buffer(page);
}

static void btree_invalidatepage(struct page *page, unsigned long offset)
static void btree_invalidatepage(struct page *page, unsigned int offset,
				 unsigned int length)
{
	struct extent_io_tree *tree;
	tree = &BTRFS_I(page->mapping->host)->io_tree;
Loading