aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dax.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-11-01 11:36:43 -0400
committerDan Williams <dan.j.williams@intel.com>2017-11-03 09:26:25 -0400
commit71eab6dfd91eabf06fe782a590c07e8a0795f5ea (patch)
treefc0c38518d74b25f9038e1c880a262a6366e768e /fs/dax.c
parentcaa51d26f85c248f1c4f43a870ad3ef84bf9eb8f (diff)
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>
Diffstat (limited to 'fs/dax.c')
-rw-r--r--fs/dax.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/fs/dax.c b/fs/dax.c
index bb9ff907738c..78233c716757 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1492,3 +1492,86 @@ int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
1492 } 1492 }
1493} 1493}
1494EXPORT_SYMBOL_GPL(dax_iomap_fault); 1494EXPORT_SYMBOL_GPL(dax_iomap_fault);
1495
1496/**
1497 * dax_insert_pfn_mkwrite - insert PTE or PMD entry into page tables
1498 * @vmf: The description of the fault
1499 * @pe_size: Size of entry to be inserted
1500 * @pfn: PFN to insert
1501 *
1502 * This function inserts writeable PTE or PMD entry into page tables for mmaped
1503 * DAX file. It takes care of marking corresponding radix tree entry as dirty
1504 * as well.
1505 */
1506static int dax_insert_pfn_mkwrite(struct vm_fault *vmf,
1507 enum page_entry_size pe_size,
1508 pfn_t pfn)
1509{
1510 struct address_space *mapping = vmf->vma->vm_file->f_mapping;
1511 void *entry, **slot;
1512 pgoff_t index = vmf->pgoff;
1513 int vmf_ret, error;
1514
1515 spin_lock_irq(&mapping->tree_lock);
1516 entry = get_unlocked_mapping_entry(mapping, index, &slot);
1517 /* Did we race with someone splitting entry or so? */
1518 if (!entry ||
1519 (pe_size == PE_SIZE_PTE && !dax_is_pte_entry(entry)) ||
1520 (pe_size == PE_SIZE_PMD && !dax_is_pmd_entry(entry))) {
1521 put_unlocked_mapping_entry(mapping, index, entry);
1522 spin_unlock_irq(&mapping->tree_lock);
1523 trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
1524 VM_FAULT_NOPAGE);
1525 return VM_FAULT_NOPAGE;
1526 }
1527 radix_tree_tag_set(&mapping->page_tree, index, PAGECACHE_TAG_DIRTY);
1528 entry = lock_slot(mapping, slot);
1529 spin_unlock_irq(&mapping->tree_lock);
1530 switch (pe_size) {
1531 case PE_SIZE_PTE:
1532 error = vm_insert_mixed_mkwrite(vmf->vma, vmf->address, pfn);
1533 vmf_ret = dax_fault_return(error);
1534 break;
1535#ifdef CONFIG_FS_DAX_PMD
1536 case PE_SIZE_PMD:
1537 vmf_ret = vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd,
1538 pfn, true);
1539 break;
1540#endif
1541 default:
1542 vmf_ret = VM_FAULT_FALLBACK;
1543 }
1544 put_locked_mapping_entry(mapping, index);
1545 trace_dax_insert_pfn_mkwrite(mapping->host, vmf, vmf_ret);
1546 return vmf_ret;
1547}
1548
1549/**
1550 * dax_finish_sync_fault - finish synchronous page fault
1551 * @vmf: The description of the fault
1552 * @pe_size: Size of entry to be inserted
1553 * @pfn: PFN to insert
1554 *
1555 * This function ensures that the file range touched by the page fault is
1556 * stored persistently on the media and handles inserting of appropriate page
1557 * table entry.
1558 */
1559int dax_finish_sync_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
1560 pfn_t pfn)
1561{
1562 int err;
1563 loff_t start = ((loff_t)vmf->pgoff) << PAGE_SHIFT;
1564 size_t len = 0;
1565
1566 if (pe_size == PE_SIZE_PTE)
1567 len = PAGE_SIZE;
1568 else if (pe_size == PE_SIZE_PMD)
1569 len = PMD_SIZE;
1570 else
1571 WARN_ON_ONCE(1);
1572 err = vfs_fsync_range(vmf->vma->vm_file, start, start + len - 1, 1);
1573 if (err)
1574 return VM_FAULT_SIGBUS;
1575 return dax_insert_pfn_mkwrite(vmf, pe_size, pfn);
1576}
1577EXPORT_SYMBOL_GPL(dax_finish_sync_fault);