summaryrefslogtreecommitdiffstats
path: root/fs/ext4/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/file.c')
-rw-r--r--fs/ext4/file.c66
1 files changed, 57 insertions, 9 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 113837e7ba98..0d24ebcd7c9e 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -209,15 +209,18 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
209{ 209{
210 int result; 210 int result;
211 handle_t *handle = NULL; 211 handle_t *handle = NULL;
212 struct super_block *sb = file_inode(vma->vm_file)->i_sb; 212 struct inode *inode = file_inode(vma->vm_file);
213 struct super_block *sb = inode->i_sb;
213 bool write = vmf->flags & FAULT_FLAG_WRITE; 214 bool write = vmf->flags & FAULT_FLAG_WRITE;
214 215
215 if (write) { 216 if (write) {
216 sb_start_pagefault(sb); 217 sb_start_pagefault(sb);
217 file_update_time(vma->vm_file); 218 file_update_time(vma->vm_file);
219 down_read(&EXT4_I(inode)->i_mmap_sem);
218 handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, 220 handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
219 EXT4_DATA_TRANS_BLOCKS(sb)); 221 EXT4_DATA_TRANS_BLOCKS(sb));
220 } 222 } else
223 down_read(&EXT4_I(inode)->i_mmap_sem);
221 224
222 if (IS_ERR(handle)) 225 if (IS_ERR(handle))
223 result = VM_FAULT_SIGBUS; 226 result = VM_FAULT_SIGBUS;
@@ -228,8 +231,10 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
228 if (write) { 231 if (write) {
229 if (!IS_ERR(handle)) 232 if (!IS_ERR(handle))
230 ext4_journal_stop(handle); 233 ext4_journal_stop(handle);
234 up_read(&EXT4_I(inode)->i_mmap_sem);
231 sb_end_pagefault(sb); 235 sb_end_pagefault(sb);
232 } 236 } else
237 up_read(&EXT4_I(inode)->i_mmap_sem);
233 238
234 return result; 239 return result;
235} 240}
@@ -246,10 +251,12 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
246 if (write) { 251 if (write) {
247 sb_start_pagefault(sb); 252 sb_start_pagefault(sb);
248 file_update_time(vma->vm_file); 253 file_update_time(vma->vm_file);
254 down_read(&EXT4_I(inode)->i_mmap_sem);
249 handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, 255 handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
250 ext4_chunk_trans_blocks(inode, 256 ext4_chunk_trans_blocks(inode,
251 PMD_SIZE / PAGE_SIZE)); 257 PMD_SIZE / PAGE_SIZE));
252 } 258 } else
259 down_read(&EXT4_I(inode)->i_mmap_sem);
253 260
254 if (IS_ERR(handle)) 261 if (IS_ERR(handle))
255 result = VM_FAULT_SIGBUS; 262 result = VM_FAULT_SIGBUS;
@@ -260,30 +267,71 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
260 if (write) { 267 if (write) {
261 if (!IS_ERR(handle)) 268 if (!IS_ERR(handle))
262 ext4_journal_stop(handle); 269 ext4_journal_stop(handle);
270 up_read(&EXT4_I(inode)->i_mmap_sem);
263 sb_end_pagefault(sb); 271 sb_end_pagefault(sb);
264 } 272 } else
273 up_read(&EXT4_I(inode)->i_mmap_sem);
265 274
266 return result; 275 return result;
267} 276}
268 277
269static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) 278static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
270{ 279{
271 return dax_mkwrite(vma, vmf, ext4_get_block_dax, 280 int err;
272 ext4_end_io_unwritten); 281 struct inode *inode = file_inode(vma->vm_file);
282
283 sb_start_pagefault(inode->i_sb);
284 file_update_time(vma->vm_file);
285 down_read(&EXT4_I(inode)->i_mmap_sem);
286 err = __dax_mkwrite(vma, vmf, ext4_get_block_dax,
287 ext4_end_io_unwritten);
288 up_read(&EXT4_I(inode)->i_mmap_sem);
289 sb_end_pagefault(inode->i_sb);
290
291 return err;
292}
293
294/*
295 * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_mkwrite()
296 * handler we check for races agaist truncate. Note that since we cycle through
297 * i_mmap_sem, we are sure that also any hole punching that began before we
298 * were called is finished by now and so if it included part of the file we
299 * are working on, our pte will get unmapped and the check for pte_same() in
300 * wp_pfn_shared() fails. Thus fault gets retried and things work out as
301 * desired.
302 */
303static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma,
304 struct vm_fault *vmf)
305{
306 struct inode *inode = file_inode(vma->vm_file);
307 struct super_block *sb = inode->i_sb;
308 int ret = VM_FAULT_NOPAGE;
309 loff_t size;
310
311 sb_start_pagefault(sb);
312 file_update_time(vma->vm_file);
313 down_read(&EXT4_I(inode)->i_mmap_sem);
314 size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
315 if (vmf->pgoff >= size)
316 ret = VM_FAULT_SIGBUS;
317 up_read(&EXT4_I(inode)->i_mmap_sem);
318 sb_end_pagefault(sb);
319
320 return ret;
273} 321}
274 322
275static const struct vm_operations_struct ext4_dax_vm_ops = { 323static const struct vm_operations_struct ext4_dax_vm_ops = {
276 .fault = ext4_dax_fault, 324 .fault = ext4_dax_fault,
277 .pmd_fault = ext4_dax_pmd_fault, 325 .pmd_fault = ext4_dax_pmd_fault,
278 .page_mkwrite = ext4_dax_mkwrite, 326 .page_mkwrite = ext4_dax_mkwrite,
279 .pfn_mkwrite = dax_pfn_mkwrite, 327 .pfn_mkwrite = ext4_dax_pfn_mkwrite,
280}; 328};
281#else 329#else
282#define ext4_dax_vm_ops ext4_file_vm_ops 330#define ext4_dax_vm_ops ext4_file_vm_ops
283#endif 331#endif
284 332
285static const struct vm_operations_struct ext4_file_vm_ops = { 333static const struct vm_operations_struct ext4_file_vm_ops = {
286 .fault = filemap_fault, 334 .fault = ext4_filemap_fault,
287 .map_pages = filemap_map_pages, 335 .map_pages = filemap_map_pages,
288 .page_mkwrite = ext4_page_mkwrite, 336 .page_mkwrite = ext4_page_mkwrite,
289}; 337};