|
@@ -3913,10 +3913,31 @@ void ext4_set_aops(struct inode *inode)
|
|
|
*/
|
|
|
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, length, pos;
|
|
|
+ unsigned blocksize, max, pos;
|
|
|
ext4_lblk_t iblock;
|
|
|
struct inode *inode = mapping->host;
|
|
|
struct buffer_head *bh;
|
|
@@ -3929,7 +3950,15 @@ int ext4_block_truncate_page(handle_t *handle,
|
|
|
return -EINVAL;
|
|
|
|
|
|
blocksize = inode->i_sb->s_blocksize;
|
|
|
- length = blocksize - (offset & (blocksize - 1));
|
|
|
+ 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))
|