summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-10-16 15:03:50 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2019-11-04 15:56:31 -0500
commitc787a79b049ed4c51fe69843b5ac3a5c75edcc02 (patch)
tree978d17e90897aa4d19b6a06400436b4eb5cbabf9
parent58c0d788bd3fe954ba3c11f3dd9b924d9b10065e (diff)
mm: Add a mechanism to disable faults for a specific mapping
This will be used to prevent a nasty cache coherency issue for O_DIRECT writes; O_DIRECT writes need to shoot down the range of the page cache corresponding to the part of the file being written to - but, if the file is mapped in, userspace can pass in an address in that mapping to pwrite(), causing those pages to be faulted back into the page cache in get_user_pages(). Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--include/linux/sched.h1
-rw-r--r--init/init_task.c1
-rw-r--r--mm/memory.c16
3 files changed, 14 insertions, 4 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 1db9042dede6..f3bbf171e97d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -679,6 +679,7 @@ struct task_struct {
struct mm_struct *mm;
struct mm_struct *active_mm;
+ struct address_space *faults_disabled_mapping;
/* Per-thread vma caching: */
struct vmacache vmacache;
diff --git a/init/init_task.c b/init/init_task.c
index 92bbb6e9094f..6c0f1257234b 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -76,6 +76,7 @@ struct task_struct init_task
.nr_cpus_allowed= NR_CPUS,
.mm = NULL,
.active_mm = &init_mm,
+ .faults_disabled_mapping = NULL,
.restart_block = {
.fn = do_no_restart_syscall,
},
diff --git a/mm/memory.c b/mm/memory.c
index ddf20bd0c317..c8d1e9419406 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3633,10 +3633,18 @@ static vm_fault_t do_fault(struct vm_fault *vmf)
struct mm_struct *vm_mm = vma->vm_mm;
vm_fault_t ret;
- /*
- * The VMA was not fully populated on mmap() or missing VM_DONTEXPAND
- */
- if (!vma->vm_ops->fault) {
+ if (vma->vm_file &&
+ vma->vm_file->f_mapping &&
+ unlikely(vma->vm_file->f_mapping ==
+ current->faults_disabled_mapping)) {
+ /* Faulting in pages for this mapping is currently disabled: */
+ ret = VM_FAULT_SIGBUS;
+ } else if (!vma->vm_ops->fault) {
+ /*
+ * The VMA was not fully populated on mmap() or missing
+ * VM_DONTEXPAND
+ */
+
/*
* If we find a migration pmd entry or a none pmd entry, which
* should never happen, return SIGBUS