Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: fix ENOSPC handling in DAX page fault handler

When allocation of underlying block for a page fault fails, we fail the
fault with SIGBUS. However we may well hit ENOSPC just due to lots of
free blocks being held by the running / committing transaction. So
propagate the error from ext4_iomap_begin() and implement do standard
allocation retry loop in ext4_dax_huge_fault().

Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Jan Kara and committed by
Theodore Ts'o
22446423 c0b24625

+8 -2
+8 -2
fs/ext4/file.c
··· 280 280 static int ext4_dax_huge_fault(struct vm_fault *vmf, 281 281 enum page_entry_size pe_size) 282 282 { 283 - int result; 283 + int result, error = 0; 284 + int retries = 0; 284 285 handle_t *handle = NULL; 285 286 struct inode *inode = file_inode(vmf->vma->vm_file); 286 287 struct super_block *sb = inode->i_sb; ··· 305 304 sb_start_pagefault(sb); 306 305 file_update_time(vmf->vma->vm_file); 307 306 down_read(&EXT4_I(inode)->i_mmap_sem); 307 + retry: 308 308 handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, 309 309 EXT4_DATA_TRANS_BLOCKS(sb)); 310 310 if (IS_ERR(handle)) { ··· 316 314 } else { 317 315 down_read(&EXT4_I(inode)->i_mmap_sem); 318 316 } 319 - result = dax_iomap_fault(vmf, pe_size, &pfn, NULL, &ext4_iomap_ops); 317 + result = dax_iomap_fault(vmf, pe_size, &pfn, &error, &ext4_iomap_ops); 320 318 if (write) { 321 319 ext4_journal_stop(handle); 320 + 321 + if ((result & VM_FAULT_ERROR) && error == -ENOSPC && 322 + ext4_should_retry_alloc(sb, &retries)) 323 + goto retry; 322 324 /* Handling synchronous page fault? */ 323 325 if (result & VM_FAULT_NEEDDSYNC) 324 326 result = dax_finish_sync_fault(vmf, pe_size, pfn);