aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/file.c19
-rw-r--r--fs/ext4/inode.c61
3 files changed, 80 insertions, 1 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 64edb09c481e..98760d14e2cd 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1068,6 +1068,7 @@ extern void ext4_set_aops(struct inode *inode);
1068extern int ext4_writepage_trans_blocks(struct inode *); 1068extern int ext4_writepage_trans_blocks(struct inode *);
1069extern int ext4_block_truncate_page(handle_t *handle, struct page *page, 1069extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
1070 struct address_space *mapping, loff_t from); 1070 struct address_space *mapping, loff_t from);
1071extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
1071 1072
1072/* ioctl.c */ 1073/* ioctl.c */
1073extern long ext4_ioctl(struct file *, unsigned int, unsigned long); 1074extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 4159be6366ab..b9510ba66a2d 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -123,6 +123,23 @@ force_commit:
123 return ret; 123 return ret;
124} 124}
125 125
126static struct vm_operations_struct ext4_file_vm_ops = {
127 .fault = filemap_fault,
128 .page_mkwrite = ext4_page_mkwrite,
129};
130
131static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
132{
133 struct address_space *mapping = file->f_mapping;
134
135 if (!mapping->a_ops->readpage)
136 return -ENOEXEC;
137 file_accessed(file);
138 vma->vm_ops = &ext4_file_vm_ops;
139 vma->vm_flags |= VM_CAN_NONLINEAR;
140 return 0;
141}
142
126const struct file_operations ext4_file_operations = { 143const struct file_operations ext4_file_operations = {
127 .llseek = generic_file_llseek, 144 .llseek = generic_file_llseek,
128 .read = do_sync_read, 145 .read = do_sync_read,
@@ -133,7 +150,7 @@ const struct file_operations ext4_file_operations = {
133#ifdef CONFIG_COMPAT 150#ifdef CONFIG_COMPAT
134 .compat_ioctl = ext4_compat_ioctl, 151 .compat_ioctl = ext4_compat_ioctl,
135#endif 152#endif
136 .mmap = generic_file_mmap, 153 .mmap = ext4_file_mmap,
137 .open = generic_file_open, 154 .open = generic_file_open,
138 .release = ext4_release_file, 155 .release = ext4_release_file,
139 .fsync = ext4_sync_file, 156 .fsync = ext4_sync_file,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c5d506dce8c5..034fc544aa66 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3564,3 +3564,64 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
3564 3564
3565 return err; 3565 return err;
3566} 3566}
3567
3568static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh)
3569{
3570 return !buffer_mapped(bh);
3571}
3572
3573int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
3574{
3575 loff_t size;
3576 unsigned long len;
3577 int ret = -EINVAL;
3578 struct file *file = vma->vm_file;
3579 struct inode *inode = file->f_path.dentry->d_inode;
3580 struct address_space *mapping = inode->i_mapping;
3581
3582 /*
3583 * Get i_alloc_sem to stop truncates messing with the inode. We cannot
3584 * get i_mutex because we are already holding mmap_sem.
3585 */
3586 down_read(&inode->i_alloc_sem);
3587 size = i_size_read(inode);
3588 if (page->mapping != mapping || size <= page_offset(page)
3589 || !PageUptodate(page)) {
3590 /* page got truncated from under us? */
3591 goto out_unlock;
3592 }
3593 ret = 0;
3594 if (PageMappedToDisk(page))
3595 goto out_unlock;
3596
3597 if (page->index == size >> PAGE_CACHE_SHIFT)
3598 len = size & ~PAGE_CACHE_MASK;
3599 else
3600 len = PAGE_CACHE_SIZE;
3601
3602 if (page_has_buffers(page)) {
3603 /* return if we have all the buffers mapped */
3604 if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
3605 ext4_bh_unmapped))
3606 goto out_unlock;
3607 }
3608 /*
3609 * OK, we need to fill the hole... Do write_begin write_end
3610 * to do block allocation/reservation.We are not holding
3611 * inode.i__mutex here. That allow * parallel write_begin,
3612 * write_end call. lock_page prevent this from happening
3613 * on the same page though
3614 */
3615 ret = mapping->a_ops->write_begin(file, mapping, page_offset(page),
3616 len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
3617 if (ret < 0)
3618 goto out_unlock;
3619 ret = mapping->a_ops->write_end(file, mapping, page_offset(page),
3620 len, len, page, NULL);
3621 if (ret < 0)
3622 goto out_unlock;
3623 ret = 0;
3624out_unlock:
3625 up_read(&inode->i_alloc_sem);
3626 return ret;
3627}