Further updates of Documentation/filesystem/ext4.txt
[ext4-patch-queue.git] / ext4-page-mkwrite.patch
blobf8269982ea6939206f915e113f3b118e6837d562
1 ext4: Use page_mkwrite vma_operations to get mmap write notification.
3 From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
5 We would like to get notified when we are doing a write on mmap section.
6 This is needed with respect to preallocated area. We split the preallocated
7 area into initialzed extent and uninitialzed extent in the call back. This
8 let us handle ENOSPC better. Otherwise we get ENOSPC in the writepage and
9 that would result in data loss. The changes are also needed to handle ENOSPC
10 when writing to an mmap section of files with holes.
12 Acked-by: Jan Kara <jack@suse.cz>
13 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
14 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
15 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
16 ---
18 fs/ext4/ext4.h | 1
19 fs/ext4/file.c | 19 ++++++++++++++++-
20 fs/ext4/inode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 3 files changed, 80 insertions(+), 1 deletion(-)
24 Index: linux-2.6.26-rc6/fs/ext4/ext4.h
25 ===================================================================
26 --- linux-2.6.26-rc6.orig/fs/ext4/ext4.h 2008-06-17 10:43:32.000000000 -0700
27 +++ linux-2.6.26-rc6/fs/ext4/ext4.h 2008-06-17 10:43:34.000000000 -0700
28 @@ -1063,6 +1063,7 @@ extern void ext4_set_aops(struct inode *
29 extern int ext4_writepage_trans_blocks(struct inode *);
30 extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
31 struct address_space *mapping, loff_t from);
32 +extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page);
34 /* ioctl.c */
35 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
36 Index: linux-2.6.26-rc6/fs/ext4/file.c
37 ===================================================================
38 --- linux-2.6.26-rc6.orig/fs/ext4/file.c 2008-06-17 10:43:18.000000000 -0700
39 +++ linux-2.6.26-rc6/fs/ext4/file.c 2008-06-17 10:43:34.000000000 -0700
40 @@ -123,6 +123,23 @@ force_commit:
41 return ret;
44 +static struct vm_operations_struct ext4_file_vm_ops = {
45 + .fault = filemap_fault,
46 + .page_mkwrite = ext4_page_mkwrite,
47 +};
49 +static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
51 + struct address_space *mapping = file->f_mapping;
53 + if (!mapping->a_ops->readpage)
54 + return -ENOEXEC;
55 + file_accessed(file);
56 + vma->vm_ops = &ext4_file_vm_ops;
57 + vma->vm_flags |= VM_CAN_NONLINEAR;
58 + return 0;
61 const struct file_operations ext4_file_operations = {
62 .llseek = generic_file_llseek,
63 .read = do_sync_read,
64 @@ -133,7 +150,7 @@ const struct file_operations ext4_file_o
65 #ifdef CONFIG_COMPAT
66 .compat_ioctl = ext4_compat_ioctl,
67 #endif
68 - .mmap = generic_file_mmap,
69 + .mmap = ext4_file_mmap,
70 .open = generic_file_open,
71 .release = ext4_release_file,
72 .fsync = ext4_sync_file,
73 Index: linux-2.6.26-rc6/fs/ext4/inode.c
74 ===================================================================
75 --- linux-2.6.26-rc6.orig/fs/ext4/inode.c 2008-06-17 10:43:31.000000000 -0700
76 +++ linux-2.6.26-rc6/fs/ext4/inode.c 2008-06-17 10:43:34.000000000 -0700
77 @@ -3542,3 +3542,64 @@ int ext4_change_inode_journal_flag(struc
79 return err;
82 +static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh)
84 + return !buffer_mapped(bh);
87 +int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page)
89 + loff_t size;
90 + unsigned long len;
91 + int ret = -EINVAL;
92 + struct file *file = vma->vm_file;
93 + struct inode *inode = file->f_path.dentry->d_inode;
94 + struct address_space *mapping = inode->i_mapping;
96 + /*
97 + * Get i_alloc_sem to stop truncates messing with the inode. We cannot
98 + * get i_mutex because we are already holding mmap_sem.
99 + */
100 + down_read(&inode->i_alloc_sem);
101 + size = i_size_read(inode);
102 + if (page->mapping != mapping || size <= page_offset(page)
103 + || !PageUptodate(page)) {
104 + /* page got truncated from under us? */
105 + goto out_unlock;
107 + ret = 0;
108 + if (PageMappedToDisk(page))
109 + goto out_unlock;
111 + if (page->index == size >> PAGE_CACHE_SHIFT)
112 + len = size & ~PAGE_CACHE_MASK;
113 + else
114 + len = PAGE_CACHE_SIZE;
116 + if (page_has_buffers(page)) {
117 + /* return if we have all the buffers mapped */
118 + if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
119 + ext4_bh_unmapped))
120 + goto out_unlock;
122 + /*
123 + * OK, we need to fill the hole... Do write_begin write_end
124 + * to do block allocation/reservation.We are not holding
125 + * inode.i__mutex here. That allow * parallel write_begin,
126 + * write_end call. lock_page prevent this from happening
127 + * on the same page though
128 + */
129 + ret = mapping->a_ops->write_begin(file, mapping, page_offset(page),
130 + len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
131 + if (ret < 0)
132 + goto out_unlock;
133 + ret = mapping->a_ops->write_end(file, mapping, page_offset(page),
134 + len, len, page, NULL);
135 + if (ret < 0)
136 + goto out_unlock;
137 + ret = 0;
138 +out_unlock:
139 + up_read(&inode->i_alloc_sem);
140 + return ret;