linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/12 v2] Revert "ext4: remove no longer used functions in inode.c"
@ 2012-07-13 13:19 Lukas Czerner
  2012-07-13 13:19 ` [PATCH 02/12 v2] Revert "ext4: fix fsx truncate failure" Lukas Czerner
                   ` (10 more replies)
  0 siblings, 11 replies; 31+ messages in thread
From: Lukas Czerner @ 2012-07-13 13:19 UTC (permalink / raw)
  To: linux-ext4; +Cc: linux-fsdevel, tytso, achender, Lukas Czerner

This reverts commit ccb4d7af914e0fe9b2f1022f8ea6c300463fd5e6.

This commit reintroduces functions ext4_block_truncate_page() and
ext4_block_zero_page_range() which has been previously removed in favour
of ext4_discard_partial_page_buffers().

In future commits we want to reintroduce those function and remove
ext4_discard_partial_page_buffers() since it is duplicating some code
and also partially duplicating work of truncate_pagecache_range(),
moreover the old implementation was much clearer.

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
---
 fs/ext4/ext4.h  |    4 ++
 fs/ext4/inode.c |  120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index cfc4e01..439af1e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1995,6 +1995,10 @@ extern int ext4_alloc_da_blocks(struct inode *inode);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
+extern int ext4_block_truncate_page(handle_t *handle,
+		struct address_space *mapping, loff_t from);
+extern int ext4_block_zero_page_range(handle_t *handle,
+		struct address_space *mapping, loff_t from, loff_t length);
 extern int ext4_discard_partial_page_buffers(handle_t *handle,
 		struct address_space *mapping, loff_t from,
 		loff_t length, int flags);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 02bc8cb..588f9fa 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3381,6 +3381,126 @@ next:
 	return err;
 }
 
+/*
+ * ext4_block_truncate_page() zeroes out a mapping from file offset `from'
+ * up to the end of the block which corresponds to `from'.
+ * This required during truncate. We need to physically zero the tail end
+ * of that block so it doesn't yield old data if the file is later grown.
+ */
+int ext4_block_truncate_page(handle_t *handle,
+		struct address_space *mapping, loff_t from)
+{
+	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	unsigned length;
+	unsigned blocksize;
+	struct inode *inode = mapping->host;
+
+	blocksize = inode->i_sb->s_blocksize;
+	length = blocksize - (offset & (blocksize - 1));
+
+	return ext4_block_zero_page_range(handle, mapping, from, length);
+}
+
+/*
+ * ext4_block_zero_page_range() zeros out a mapping of length 'length'
+ * starting from file offset 'from'.  The range to be zero'd must
+ * be contained with in one block.  If the specified range exceeds
+ * the end of the block it will be shortened to end of the block
+ * that cooresponds to 'from'
+ */
+int ext4_block_zero_page_range(handle_t *handle,
+		struct address_space *mapping, loff_t from, loff_t length)
+{
+	ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
+	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	unsigned blocksize, max, pos;
+	ext4_lblk_t iblock;
+	struct inode *inode = mapping->host;
+	struct buffer_head *bh;
+	struct page *page;
+	int err = 0;
+
+	page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT,
+				   mapping_gfp_mask(mapping) & ~__GFP_FS);
+	if (!page)
+		return -ENOMEM;
+
+	blocksize = inode->i_sb->s_blocksize;
+	max = blocksize - (offset & (blocksize - 1));
+
+	/*
+	 * correct length if it does not fall between
+	 * 'from' and the end of the block
+	 */
+	if (length > max || length < 0)
+		length = max;
+
+	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, blocksize, 0);
+
+	/* Find the buffer that contains "offset" */
+	bh = page_buffers(page);
+	pos = blocksize;
+	while (offset >= pos) {
+		bh = bh->b_this_page;
+		iblock++;
+		pos += blocksize;
+	}
+
+	err = 0;
+	if (buffer_freed(bh)) {
+		BUFFER_TRACE(bh, "freed: skip");
+		goto unlock;
+	}
+
+	if (!buffer_mapped(bh)) {
+		BUFFER_TRACE(bh, "unmapped");
+		ext4_get_block(inode, iblock, bh, 0);
+		/* unmapped? It's a hole - nothing to do */
+		if (!buffer_mapped(bh)) {
+			BUFFER_TRACE(bh, "still unmapped");
+			goto unlock;
+		}
+	}
+
+	/* Ok, it's mapped. Make sure it's up-to-date */
+	if (PageUptodate(page))
+		set_buffer_uptodate(bh);
+
+	if (!buffer_uptodate(bh)) {
+		err = -EIO;
+		ll_rw_block(READ, 1, &bh);
+		wait_on_buffer(bh);
+		/* Uhhuh. Read error. Complain and punt. */
+		if (!buffer_uptodate(bh))
+			goto unlock;
+	}
+
+	if (ext4_should_journal_data(inode)) {
+		BUFFER_TRACE(bh, "get write access");
+		err = ext4_journal_get_write_access(handle, bh);
+		if (err)
+			goto unlock;
+	}
+
+	zero_user(page, offset, length);
+
+	BUFFER_TRACE(bh, "zeroed end of block");
+
+	err = 0;
+	if (ext4_should_journal_data(inode)) {
+		err = ext4_handle_dirty_metadata(handle, inode, bh);
+	} else
+		mark_buffer_dirty(bh);
+
+unlock:
+	unlock_page(page);
+	page_cache_release(page);
+	return err;
+}
+
 int ext4_can_truncate(struct inode *inode)
 {
 	if (S_ISREG(inode->i_mode))
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2012-07-19 23:07 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 06/12 v2] mm: teach truncate_inode_pages_range() to hadnle non page aligned ranges Lukas Czerner
2012-07-17  8:28   ` 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

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).