lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <4AC5B8C9.20507@rs.jp.nec.com>
Date:	Fri, 02 Oct 2009 17:24:41 +0900
From:	Akira Fujita <a-fujita@...jp.nec.com>
To:	Theodore Tso <tytso@....edu>, linux-ext4@...r.kernel.org
Subject: [PATCH 2/2]ext4: Invalidate donor file page not to refer old blocks

ext4: Invalidate donor file page not to refer old blocks

After exchanging blocks between original and donor files in mext_extent_per_page(),
the page cache of donor file still refers to old block(s) on memory.
Therefore we have to invalidate page cache of donor file to avoid wrong reference.
The patch fixes this issue.

Signed-off-by: Akira Fujita <a-fujita@...jp.nec.com>
---
 fs/ext4/move_extent.c |   60 ++++++++++++++++++++++++++++++------------------
 1 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 83f8c9e..6ce8764 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -813,14 +813,15 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
 	struct inode *orig_inode = o_filp->f_dentry->d_inode;
 	struct address_space *mapping = orig_inode->i_mapping;
 	struct buffer_head *bh;
-	struct page *page = NULL;
+	struct page *orig_page = NULL;
+	struct page *donor_page = NULL;
 	const struct address_space_operations *a_ops = mapping->a_ops;
 	handle_t *handle;
 	ext4_lblk_t orig_blk_offset;
-	long long offs = orig_page_offset << PAGE_CACHE_SHIFT;
+	long long o_pos;
+	pgoff_t donor_page_offset = orig_page_offset;
 	unsigned long blocksize = orig_inode->i_sb->s_blocksize;
-	unsigned int w_flags = 0;
-	unsigned int tmp_data_size, data_size, replaced_size;
+	unsigned int tmp_data_size, data_size, replaced_size, w_flags = 0;
 	void *fsdata;
 	int i, jblocks;
 	int err2 = 0;
@@ -861,7 +862,7 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
 		goto out2;
 	}

-	offs = (long long)orig_blk_offset << orig_inode->i_blkbits;
+	o_pos = (long long)orig_blk_offset << orig_inode->i_blkbits;

 	/* Calculate data_size */
 	if ((orig_blk_offset + block_len_in_page - 1) ==
@@ -882,14 +883,14 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,

 	replaced_size = data_size;

-	*err = a_ops->write_begin(o_filp, mapping, offs, data_size, w_flags,
-				 &page, &fsdata);
+	*err = a_ops->write_begin(o_filp, mapping, o_pos, data_size, w_flags,
+				 &orig_page, &fsdata);
 	if (unlikely(*err < 0))
 		goto out;

-	if (!PageUptodate(page)) {
-		mapping->a_ops->readpage(o_filp, page);
-		lock_page(page);
+	if (!PageUptodate(orig_page)) {
+		mapping->a_ops->readpage(o_filp, orig_page);
+		lock_page(orig_page);
 	}

 	/*
@@ -899,11 +900,11 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
 	 * It needs to call wait_on_page_writeback() to wait for the
 	 * writeback of the page.
 	 */
-	if (PageWriteback(page))
-		wait_on_page_writeback(page);
+	if (PageWriteback(orig_page))
+		wait_on_page_writeback(orig_page);

 	/* Release old bh and drop refs */
-	try_to_release_page(page, 0);
+	try_to_release_page(orig_page, 0);

 	replaced_count = mext_replace_branches(handle, orig_inode, donor_inode,
 					orig_blk_offset, block_len_in_page,
@@ -921,10 +922,23 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
 	ext4_ext_invalidate_cache(orig_inode);
 	ext4_ext_invalidate_cache(donor_inode);

-	if (!page_has_buffers(page))
-		create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0);
+	donor_page = grab_cache_page(donor_inode->i_mapping,
+						donor_page_offset);
+	if (!donor_page) {
+		*err = -ENOMEM;
+		goto out;
+	}
+	/* Invalidate donor page not to indicate old block on memory */
+	invalidate_mapping_pages(donor_inode->i_mapping, donor_page_offset,
+				donor_page_offset + 1);
+	unlock_page(donor_page);
+	page_cache_release(donor_page);
+	donor_page = NULL;
+
+	if (!page_has_buffers(orig_page))
+		create_empty_buffers(orig_page, 1 << orig_inode->i_blkbits, 0);

-	bh = page_buffers(page);
+	bh = page_buffers(orig_page);
 	for (i = 0; i < data_offset_in_page; i++)
 		bh = bh->b_this_page;

@@ -938,15 +952,15 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
 			bh = bh->b_this_page;
 	}

-	*err = a_ops->write_end(o_filp, mapping, offs, data_size, replaced_size,
-			       page, fsdata);
-	page = NULL;
+	*err = a_ops->write_end(o_filp, mapping, o_pos, data_size,
+			       replaced_size, orig_page, fsdata);
+	orig_page = NULL;

 out:
-	if (unlikely(page)) {
-		if (PageLocked(page))
-			unlock_page(page);
-		page_cache_release(page);
+	if (unlikely(orig_page)) {
+		if (PageLocked(orig_page))
+			unlock_page(orig_page);
+		page_cache_release(orig_page);
 		ext4_journal_stop(handle);
 	}
 out2:
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ