summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2020-10-27 15:30:33 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2020-10-27 15:30:33 +1100
commite4bc71ca7ad3dbd0aaf8ae08213e3878b6f8d555 (patch)
treeb5ac97ad7e29d7bf29d2f86e144ef661cc92a015
parentb94e1b51e54633f78ca0257c106cedd0a19d71af (diff)
parent046effab9e3ff6fb737167639088e4e873c8afbb (diff)
Merge branch 'akpm/master' into master
-rw-r--r--fs/exec.c8
-rw-r--r--include/linux/mm_types.h10
-rw-r--r--include/linux/mmap_lock.h16
-rw-r--r--mm/gup.c2
4 files changed, 32 insertions, 4 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 547a2390baf5..f7009df270aa 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1000,6 +1000,14 @@ static int exec_mmap(struct mm_struct *mm)
}
}
+#if defined(CONFIG_LOCKDEP) || defined(CONFIG_DEBUG_VM)
+ /*
+ * From here on, the mm may be accessed concurrently, and proper locking
+ * is required for things like get_user_pages_remote().
+ */
+ mm->mmap_lock_required = 1;
+#endif
+
task_lock(tsk);
membarrier_exec_mmap(mm);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 5a9238f6caad..ae891c0c55fc 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -556,6 +556,16 @@ struct mm_struct {
#ifdef CONFIG_IOMMU_SUPPORT
u32 pasid;
#endif
+
+#if defined(CONFIG_LOCKDEP) || defined(CONFIG_DEBUG_VM)
+ /*
+ * Notes whether this mm has been installed on a process yet.
+ * If not, only the task going through execve() can access this
+ * mm, and no locking is needed around get_user_pages_remote().
+ * This flag is only used for debug checks.
+ */
+ bool mmap_lock_required;
+#endif
} __randomize_layout;
/*
diff --git a/include/linux/mmap_lock.h b/include/linux/mmap_lock.h
index 18e7eae9b5ba..e1afb420fc94 100644
--- a/include/linux/mmap_lock.h
+++ b/include/linux/mmap_lock.h
@@ -77,14 +77,22 @@ static inline void mmap_read_unlock_non_owner(struct mm_struct *mm)
static inline void mmap_assert_locked(struct mm_struct *mm)
{
- lockdep_assert_held(&mm->mmap_lock);
- VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm);
+#if defined(CONFIG_LOCKDEP) || defined(CONFIG_DEBUG_VM)
+ if (mm->mmap_lock_required) {
+ lockdep_assert_held(&mm->mmap_lock);
+ VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm);
+ }
+#endif
}
static inline void mmap_assert_write_locked(struct mm_struct *mm)
{
- lockdep_assert_held_write(&mm->mmap_lock);
- VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm);
+#if defined(CONFIG_LOCKDEP) || defined(CONFIG_DEBUG_VM)
+ if (mm->mmap_lock_required) {
+ lockdep_assert_held_write(&mm->mmap_lock);
+ VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm);
+ }
+#endif
}
static inline int mmap_lock_is_contended(struct mm_struct *mm)
diff --git a/mm/gup.c b/mm/gup.c
index 102877ed77a4..04e184068ccb 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1027,6 +1027,8 @@ static long __get_user_pages(struct mm_struct *mm,
struct vm_area_struct *vma = NULL;
struct follow_page_context ctx = { NULL };
+ mmap_assert_locked(mm);
+
if (!nr_pages)
return 0;