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>2020-05-06 17:14:17 -0400
commit52cf809aa1394d759dfe4eb88290aa4d99f00647 (patch)
tree95accb66e1b2bb3a86c99494684a2ead78ca7f62
parenta94d2540036e2a9b6da593e497efaa64b08c3f54 (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/gup.c6
3 files changed, 8 insertions, 0 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c69f308f3a53..96e4152cc9bc 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -687,6 +687,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 5aebe3be4d7c..2a275774eb52 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -75,6 +75,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/gup.c b/mm/gup.c
index f3088d25bd92..c1603a71047c 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -724,6 +724,12 @@ retry:
if (unlikely(fatal_signal_pending(current)))
return i ? i : -ERESTARTSYS;
cond_resched();
+
+ if (current->faults_disabled_mapping &&
+ vma->vm_file &&
+ vma->vm_file->f_mapping == current->faults_disabled_mapping)
+ return -EFAULT;
+
page = follow_page_mask(vma, start, foll_flags, &page_mask);
if (!page) {
int ret;