diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-10-16 15:03:50 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2019-11-04 15:56:31 -0500 |
commit | c787a79b049ed4c51fe69843b5ac3a5c75edcc02 (patch) | |
tree | 978d17e90897aa4d19b6a06400436b4eb5cbabf9 | |
parent | 58c0d788bd3fe954ba3c11f3dd9b924d9b10065e (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.h | 1 | ||||
-rw-r--r-- | init/init_task.c | 1 | ||||
-rw-r--r-- | mm/memory.c | 16 |
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 |