Jan Kara ef57d1
From 71eab6dfd91eabf06fe782a590c07e8a0795f5ea Mon Sep 17 00:00:00 2001
Jan Kara ef57d1
From: Jan Kara <jack@suse.cz>
Jan Kara ef57d1
Date: Wed, 1 Nov 2017 16:36:43 +0100
Jan Kara ef57d1
Subject: [PATCH 15/20] dax: Implement dax_finish_sync_fault()
Jan Kara ef57d1
Git-commit: 71eab6dfd91eabf06fe782a590c07e8a0795f5ea
Jan Kara ef57d1
Patch-mainline: v4.15-rc1
Jan Kara ef57d1
References: fate#322879
Jan Kara ef57d1
Jan Kara ef57d1
Implement a function that filesystems can call to finish handling of
Jan Kara ef57d1
synchronous page faults. It takes care of syncing appropriare file range
Jan Kara ef57d1
and insertion of page table entry.
Jan Kara ef57d1
Jan Kara ef57d1
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Jan Kara ef57d1
Reviewed-by: Christoph Hellwig <hch@lst.de>
Jan Kara ef57d1
Signed-off-by: Jan Kara <jack@suse.cz>
Jan Kara ef57d1
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Jan Kara ef57d1
Acked-by: Jan Kara <jack@suse.cz>
Jan Kara ef57d1
Jan Kara ef57d1
---
Jan Kara ef57d1
 fs/dax.c                      | 83 +++++++++++++++++++++++++++++++++++++++++++
Jan Kara ef57d1
 include/linux/dax.h           |  2 ++
Jan Kara ef57d1
 include/trace/events/fs_dax.h |  2 ++
Jan Kara ef57d1
 3 files changed, 87 insertions(+)
Jan Kara ef57d1
Jan Kara ef57d1
diff --git a/fs/dax.c b/fs/dax.c
Jan Kara ef57d1
index bb9ff907738c..78233c716757 100644
Jan Kara ef57d1
--- a/fs/dax.c
Jan Kara ef57d1
+++ b/fs/dax.c
Jan Kara ef57d1
@@ -1492,3 +1492,86 @@ int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
Jan Kara ef57d1
 	}
Jan Kara ef57d1
 }
Jan Kara ef57d1
 EXPORT_SYMBOL_GPL(dax_iomap_fault);
Jan Kara ef57d1
+
Jan Kara ef57d1
+/**
Jan Kara ef57d1
+ * dax_insert_pfn_mkwrite - insert PTE or PMD entry into page tables
Jan Kara ef57d1
+ * @vmf: The description of the fault
Jan Kara ef57d1
+ * @pe_size: Size of entry to be inserted
Jan Kara ef57d1
+ * @pfn: PFN to insert
Jan Kara ef57d1
+ *
Jan Kara ef57d1
+ * This function inserts writeable PTE or PMD entry into page tables for mmaped
Jan Kara ef57d1
+ * DAX file.  It takes care of marking corresponding radix tree entry as dirty
Jan Kara ef57d1
+ * as well.
Jan Kara ef57d1
+ */
Jan Kara ef57d1
+static int dax_insert_pfn_mkwrite(struct vm_fault *vmf,
Jan Kara ef57d1
+				  enum page_entry_size pe_size,
Jan Kara ef57d1
+				  pfn_t pfn)
Jan Kara ef57d1
+{
Jan Kara ef57d1
+	struct address_space *mapping = vmf->vma->vm_file->f_mapping;
Jan Kara ef57d1
+	void *entry, **slot;
Jan Kara ef57d1
+	pgoff_t index = vmf->pgoff;
Jan Kara ef57d1
+	int vmf_ret, error;
Jan Kara ef57d1
+
Jan Kara ef57d1
+	spin_lock_irq(&mapping->tree_lock);
Jan Kara ef57d1
+	entry = get_unlocked_mapping_entry(mapping, index, &slot);
Jan Kara ef57d1
+	/* Did we race with someone splitting entry or so? */
Jan Kara ef57d1
+	if (!entry ||
Jan Kara ef57d1
+	    (pe_size == PE_SIZE_PTE && !dax_is_pte_entry(entry)) ||
Jan Kara ef57d1
+	    (pe_size == PE_SIZE_PMD && !dax_is_pmd_entry(entry))) {
Jan Kara ef57d1
+		put_unlocked_mapping_entry(mapping, index, entry);
Jan Kara ef57d1
+		spin_unlock_irq(&mapping->tree_lock);
Jan Kara ef57d1
+		trace_dax_insert_pfn_mkwrite_no_entry(mapping->host, vmf,
Jan Kara ef57d1
+						      VM_FAULT_NOPAGE);
Jan Kara ef57d1
+		return VM_FAULT_NOPAGE;
Jan Kara ef57d1
+	}
Jan Kara ef57d1
+	radix_tree_tag_set(&mapping->page_tree, index, PAGECACHE_TAG_DIRTY);
Jan Kara ef57d1
+	entry = lock_slot(mapping, slot);
Jan Kara ef57d1
+	spin_unlock_irq(&mapping->tree_lock);
Jan Kara ef57d1
+	switch (pe_size) {
Jan Kara ef57d1
+	case PE_SIZE_PTE:
Jan Kara ef57d1
+		error = vm_insert_mixed_mkwrite(vmf->vma, vmf->address, pfn);
Jan Kara ef57d1
+		vmf_ret = dax_fault_return(error);
Jan Kara ef57d1
+		break;
Jan Kara ef57d1
+#ifdef CONFIG_FS_DAX_PMD
Jan Kara ef57d1
+	case PE_SIZE_PMD:
Jan Kara ef57d1
+		vmf_ret = vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd,
Jan Kara ef57d1
+			pfn, true);
Jan Kara ef57d1
+		break;
Jan Kara ef57d1
+#endif
Jan Kara ef57d1
+	default:
Jan Kara ef57d1
+		vmf_ret = VM_FAULT_FALLBACK;
Jan Kara ef57d1
+	}
Jan Kara ef57d1
+	put_locked_mapping_entry(mapping, index);
Jan Kara ef57d1
+	trace_dax_insert_pfn_mkwrite(mapping->host, vmf, vmf_ret);
Jan Kara ef57d1
+	return vmf_ret;
Jan Kara ef57d1
+}
Jan Kara ef57d1
+
Jan Kara ef57d1
+/**
Jan Kara ef57d1
+ * dax_finish_sync_fault - finish synchronous page fault
Jan Kara ef57d1
+ * @vmf: The description of the fault
Jan Kara ef57d1
+ * @pe_size: Size of entry to be inserted
Jan Kara ef57d1
+ * @pfn: PFN to insert
Jan Kara ef57d1
+ *
Jan Kara ef57d1
+ * This function ensures that the file range touched by the page fault is
Jan Kara ef57d1
+ * stored persistently on the media and handles inserting of appropriate page
Jan Kara ef57d1
+ * table entry.
Jan Kara ef57d1
+ */
Jan Kara ef57d1
+int dax_finish_sync_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
Jan Kara ef57d1
+			  pfn_t pfn)
Jan Kara ef57d1
+{
Jan Kara ef57d1
+	int err;
Jan Kara ef57d1
+	loff_t start = ((loff_t)vmf->pgoff) << PAGE_SHIFT;
Jan Kara ef57d1
+	size_t len = 0;
Jan Kara ef57d1
+
Jan Kara ef57d1
+	if (pe_size == PE_SIZE_PTE)
Jan Kara ef57d1
+		len = PAGE_SIZE;
Jan Kara ef57d1
+	else if (pe_size == PE_SIZE_PMD)
Jan Kara ef57d1
+		len = PMD_SIZE;
Jan Kara ef57d1
+	else
Jan Kara ef57d1
+		WARN_ON_ONCE(1);
Jan Kara ef57d1
+	err = vfs_fsync_range(vmf->vma->vm_file, start, start + len - 1, 1);
Jan Kara ef57d1
+	if (err)
Jan Kara ef57d1
+		return VM_FAULT_SIGBUS;
Jan Kara ef57d1
+	return dax_insert_pfn_mkwrite(vmf, pe_size, pfn);
Jan Kara ef57d1
+}
Jan Kara ef57d1
+EXPORT_SYMBOL_GPL(dax_finish_sync_fault);
Jan Kara ef57d1
diff --git a/include/linux/dax.h b/include/linux/dax.h
Jan Kara ef57d1
index e7fa4b8f45bc..d403f78b706c 100644
Jan Kara ef57d1
--- a/include/linux/dax.h
Jan Kara ef57d1
+++ b/include/linux/dax.h
Jan Kara ef57d1
@@ -96,6 +96,8 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
Jan Kara ef57d1
 		const struct iomap_ops *ops);
Jan Kara ef57d1
 int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
Jan Kara ef57d1
 		    pfn_t *pfnp, const struct iomap_ops *ops);
Jan Kara ef57d1
+int dax_finish_sync_fault(struct vm_fault *vmf, enum page_entry_size pe_size,
Jan Kara ef57d1
+			  pfn_t pfn);
Jan Kara ef57d1
 int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
Jan Kara ef57d1
 int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
Jan Kara ef57d1
 				      pgoff_t index);
Jan Kara ef57d1
diff --git a/include/trace/events/fs_dax.h b/include/trace/events/fs_dax.h
Jan Kara ef57d1
index 88a9d19b8ff8..7725459fafef 100644
Jan Kara ef57d1
--- a/include/trace/events/fs_dax.h
Jan Kara ef57d1
+++ b/include/trace/events/fs_dax.h
Jan Kara ef57d1
@@ -190,6 +190,8 @@ DEFINE_EVENT(dax_pte_fault_class, name, \
Jan Kara ef57d1
 DEFINE_PTE_FAULT_EVENT(dax_pte_fault);
Jan Kara ef57d1
 DEFINE_PTE_FAULT_EVENT(dax_pte_fault_done);
Jan Kara ef57d1
 DEFINE_PTE_FAULT_EVENT(dax_load_hole);
Jan Kara ef57d1
+DEFINE_PTE_FAULT_EVENT(dax_insert_pfn_mkwrite_no_entry);
Jan Kara ef57d1
+DEFINE_PTE_FAULT_EVENT(dax_insert_pfn_mkwrite);
Jan Kara ef57d1
 
Jan Kara ef57d1
 TRACE_EVENT(dax_insert_mapping,
Jan Kara ef57d1
 	TP_PROTO(struct inode *inode, struct vm_fault *vmf, void *radix_entry),
Jan Kara ef57d1
-- 
Jan Kara ef57d1
2.12.3
Jan Kara ef57d1