summaryrefslogtreecommitdiff
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2020-01-06 08:58:23 -0800
committerDarrick J. Wong <darrick.wong@oracle.com>2020-01-06 08:58:23 -0800
commit62e298db3fc3ebf41d996f3c86b44cbbdd3286bc (patch)
treee517d8f0d87dc0e9f953aa943a3b6dab0a5e365a /fs/ext4/inode.c
parentfd6988496e79a6a4bdb514a4655d2920209eb85d (diff)
fs: Fix page_mkwrite off-by-one errorsiomap-5.6-merge-2
The check in block_page_mkwrite that is meant to determine whether an offset is within the inode size is off by one. This bug has been copied into iomap_page_mkwrite and several filesystems (ubifs, ext4, f2fs, ceph). Fix that by introducing a new page_mkwrite_check_truncate helper that checks for truncate and computes the bytes in the page up to EOF. Use the helper in the above mentioned filesystems. In addition, use the new helper in btrfs as well. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Acked-by: David Sterba <dsterba@suse.com> (btrfs part) Acked-by: Richard Weinberger <richard@nod.at> (ubifs part) Acked-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> [darrick: drop the f2fs part (no ack) and fix build warning] Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c15
1 files changed, 4 insertions, 11 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 629a25d999f0..3244803df30a 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5871,13 +5871,11 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct page *page = vmf->page;
- loff_t size;
unsigned long len;
int err;
vm_fault_t ret;
struct file *file = vma->vm_file;
struct inode *inode = file_inode(file);
- struct address_space *mapping = inode->i_mapping;
handle_t *handle;
get_block_t *get_block;
int retries = 0;
@@ -5907,18 +5905,13 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf)
}
lock_page(page);
- size = i_size_read(inode);
- /* Page got truncated from under us? */
- if (page->mapping != mapping || page_offset(page) > size) {
+ err = page_mkwrite_check_truncate(page, inode);
+ if (err < 0) {
unlock_page(page);
- ret = VM_FAULT_NOPAGE;
- goto out;
+ goto out_ret;
}
+ len = err;
- if (page->index == size >> PAGE_SHIFT)
- len = size & ~PAGE_MASK;
- else
- len = PAGE_SIZE;
/*
* Return if we have all the buffers mapped. This avoids the need to do
* journal_start/journal_stop which can block and take a long time