dax: Implement dax_finish_sync_fault()
Implement a function that filesystems can call to finish handling of synchronous page faults. It takes care of syncing appropriare file range and insertion of page table entry. Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
caa51d26f8
commit
71eab6dfd9
83
fs/dax.c
83
fs/dax.c
@ -1492,3 +1492,86 @@ int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dax_iomap_fault);
|
EXPORT_SYMBOL_GPL(dax_iomap_fault);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dax_insert_pfn_mkwrite - insert PTE or PMD entry into page tables
|
||||||
|
* @vmf: The description of the fault
|
||||||
|
* @pe_size: Size of entry to be inserted
|
||||||
|
* @pfn: PFN to insert
|
||||||
|
*
|
||||||
|
* This function inserts writeable PTE or PMD entry into page tables for mmaped
|
||||||
|
* DAX file. It takes care of marking corresponding radix tree entry as dirty
|
||||||
|
* as well.
|
||||||
|
*/
|
||||||
|
static int dax_insert_pfn_mkwrite(struct vm_fault *vmf,
|
||||||
|
enum page_entry_size pe_size,
|
||||||
|
pfn_t pfn)
|
||||||
|
{
|
||||||
|
struct address_space *mapping = vmf->vma->vm_file->f_mapping;
|
||||||
|
void *entry, **slot;
|
||||||
|
pgoff_t index = vmf->pgoff;
|
||||||
|
int vmf_ret, error;
|
||||||
|
|
||||||
|
spin_lock_irq(&mapping->tree_lock);
|
||||||
|
entry = get_unlocked_mapping_entry(mapping, index, &slot);
|
||||||
|
/* Did we race with someone splitting entry or so? */
|
||||||
|
if (!entry ||
|
||||||
|
(pe_size == PE_SIZE_PTE && !dax_is_pte_entry(entry)) ||
|
||||||
|
(pe_size == PE_SIZE_PMD && !dax_is_pmd_entry(entry))) {
|
||||||
|
put_unlocked_mapping_entry(mapping, index, entry);
|
||||||
|
spin_unlock_irq(&mapping->tree_lock);
|
||||||
|
trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
|
||||||
|
VM_FAULT_NOPAGE);
|
||||||
|
return VM_FAULT_NOPAGE;
|
||||||
|
}
|
||||||
|
radix_tree_tag_set(&mapping->page_tree, index, PAGECACHE_TAG_DIRTY);
|
||||||
|
entry = lock_slot(mapping, slot);
|
||||||
|
spin_unlock_irq(&mapping->tree_lock);
|
||||||
|
switch (pe_size) {
|
||||||
|
case PE_SIZE_PTE:
|
||||||
|
error = vm_insert_mixed_mkwrite(vmf->vma, vmf->address, pfn);
|
||||||
|
vmf_ret = dax_fault_return(error);
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_FS_DAX_PMD
|
||||||
|
case PE_SIZE_PMD:
|
||||||
|
vmf_ret = vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd,
|
||||||
|
pfn, true);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
vmf_ret = VM_FAULT_FALLBACK;
|
||||||
|
}
|
||||||
|
put_locked_mapping_entry(mapping, index);
|
||||||
|
trace_dax_insert_pfn_mkwrite(mapping->host, vmf, vmf_ret);
|
||||||
|
return vmf_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dax_finish_sync_fault - finish synchronous page fault
|
||||||
|
* @vmf: The description of the fault
|
||||||
|
* @pe_size: Size of entry to be inserted
|
||||||
|
* @pfn: PFN to insert
|
||||||
|
*
|
||||||
|
* This function ensures that the file range touched by the page fault is
|
||||||
|
* stored persistently on the media and handles inserting of appropriate page
|
||||||
|
* table entry.
|
||||||
|
*/
|
||||||
|
int dax_finish_sync_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
|
||||||
|
pfn_t pfn)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
loff_t start = ((loff_t)vmf->pgoff) << PAGE_SHIFT;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (pe_size == PE_SIZE_PTE)
|
||||||
|
len = PAGE_SIZE;
|
||||||
|
else if (pe_size == PE_SIZE_PMD)
|
||||||
|
len = PMD_SIZE;
|
||||||
|
else
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
err = vfs_fsync_range(vmf->vma->vm_file, start, start + len - 1, 1);
|
||||||
|
if (err)
|
||||||
|
return VM_FAULT_SIGBUS;
|
||||||
|
return dax_insert_pfn_mkwrite(vmf, pe_size, pfn);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dax_finish_sync_fault);
|
||||||
|
@ -96,6 +96,8 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
|
|||||||
const struct iomap_ops *ops);
|
const struct iomap_ops *ops);
|
||||||
int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
|
int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
|
||||||
pfn_t *pfnp, const struct iomap_ops *ops);
|
pfn_t *pfnp, const struct iomap_ops *ops);
|
||||||
|
int dax_finish_sync_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
|
||||||
|
pfn_t pfn);
|
||||||
int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
|
int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
|
||||||
int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
|
int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
|
||||||
pgoff_t index);
|
pgoff_t index);
|
||||||
|
@ -190,6 +190,8 @@ DEFINE_EVENT(dax_pte_fault_class, name, \
|
|||||||
DEFINE_PTE_FAULT_EVENT(dax_pte_fault);
|
DEFINE_PTE_FAULT_EVENT(dax_pte_fault);
|
||||||
DEFINE_PTE_FAULT_EVENT(dax_pte_fault_done);
|
DEFINE_PTE_FAULT_EVENT(dax_pte_fault_done);
|
||||||
DEFINE_PTE_FAULT_EVENT(dax_load_hole);
|
DEFINE_PTE_FAULT_EVENT(dax_load_hole);
|
||||||
|
DEFINE_PTE_FAULT_EVENT(dax_insert_pfn_mkwrite_no_entry);
|
||||||
|
DEFINE_PTE_FAULT_EVENT(dax_insert_pfn_mkwrite);
|
||||||
|
|
||||||
TRACE_EVENT(dax_insert_mapping,
|
TRACE_EVENT(dax_insert_mapping,
|
||||||
TP_PROTO(struct inode *inode, struct vm_fault *vmf, void *radix_entry),
|
TP_PROTO(struct inode *inode, struct vm_fault *vmf, void *radix_entry),
|
||||||
|
Loading…
Reference in New Issue
Block a user