[RFC PATCH 07/13] kernel/fork: Split and export 'mm_alloc' and 'mm_init'
From: Till Smejkal <hidden>
Date: 2017-03-13 22:14:09
Also in:
alsa-devel, linux-alpha, linux-arch, linux-fsdevel, linux-mips, linux-mm, linux-s390, linuxppc-dev
Subsystem:
arm port, arm/riscpc architecture, exec & binfmt api, elf, filesystems (vfs and infrastructure), memory management - core, scheduler, the rest · Maintainers:
Russell King, Kees Cook, Alexander Viro, Christian Brauner, Andrew Morton, David Hildenbrand, Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Linus Torvalds
The only way until now to create a new memory map was via the exported function 'mm_alloc'. Unfortunately, this function not only allocates a new memory map, but also completely initializes it. However, with the introduction of first class virtual address spaces, some initialization steps done in 'mm_alloc' are not applicable to the memory maps needed for this feature and hence would lead to errors in the kernel code. Instead of introducing a new function that can allocate and initialize memory maps for first class virtual address spaces and potentially duplicate some code, I decided to split the mm_alloc function as well as the 'mm_init' function that it uses. Now there are four functions exported instead of only one. The new 'mm_alloc' function only allocates a new mm_struct and zeros it out. If one want to have the old behavior of mm_alloc one can use the newly introduced function 'mm_alloc_and_setup' which not only allocates a new mm_struct but also fully initializes it. The old 'mm_init' function which fully initialized a mm_struct was split up into two separate functions. The first one - 'mm_setup' - does all the initialization of the mm_struct that is not related to the mm_struct belonging to a particular task. This part of the initialization is done in the 'mm_set_task' function. This way it is possible to create memory maps that don't have any task-specific information as needed by the first class virtual address space feature. Both functions, 'mm_setup' and 'mm_set_task' are also exported, so that they can be used in all files in the source tree. Signed-off-by: Till Smejkal <redacted> --- arch/arm/mach-rpc/ecard.c | 2 +- fs/exec.c | 2 +- include/linux/sched.h | 7 +++++- kernel/fork.c | 64 +++++++++++++++++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 16 deletions(-)
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
index dc67a7fb3831..15845e8abd7e 100644
--- a/arch/arm/mach-rpc/ecard.c
+++ b/arch/arm/mach-rpc/ecard.c@@ -245,7 +245,7 @@ static void ecard_init_pgtables(struct mm_struct *mm) static int ecard_init_mm(void) { - struct mm_struct * mm = mm_alloc(); + struct mm_struct *mm = mm_alloc_and_setup(); struct mm_struct *active_mm = current->active_mm; if (!mm)
diff --git a/fs/exec.c b/fs/exec.c
index e57946610733..68d7908a1e5a 100644
--- a/fs/exec.c
+++ b/fs/exec.c@@ -380,7 +380,7 @@ static int bprm_mm_init(struct linux_binprm *bprm) int err; struct mm_struct *mm = NULL; - bprm->mm = mm = mm_alloc(); + bprm->mm = mm = mm_alloc_and_setup(); err = -ENOMEM; if (!mm) goto err;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 42b9b93a50ac..7955adc00397 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h@@ -2922,7 +2922,12 @@ static inline unsigned long sigsp(unsigned long sp, struct ksignal *ksig) /* * Routines for handling mm_structs */ -extern struct mm_struct * mm_alloc(void); +extern struct mm_struct *mm_setup(struct mm_struct *mm); +extern struct mm_struct *mm_set_task(struct mm_struct *mm, + struct task_struct *p, + struct user_namespace *user_ns); +extern struct mm_struct *mm_alloc(void); +extern struct mm_struct *mm_alloc_and_setup(void); /* mmdrop drops the mm and the page tables */ extern void __mmdrop(struct mm_struct *);
diff --git a/kernel/fork.c b/kernel/fork.c
index 11c5c8ab827c..9209f6d5d7c0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c@@ -747,8 +747,10 @@ static void mm_init_owner(struct mm_struct *mm, struct task_struct *p) #endif } -static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, - struct user_namespace *user_ns) +/** + * Initialize all the task-unrelated fields of a mm_struct. + **/ +struct mm_struct *mm_setup(struct mm_struct *mm) { mm->mmap = NULL; mm->mm_rb = RB_ROOT;
@@ -767,24 +769,37 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, spin_lock_init(&mm->page_table_lock); mm_init_cpumask(mm); mm_init_aio(mm); - mm_init_owner(mm, p); mmu_notifier_mm_init(mm); clear_tlb_flush_pending(mm); #if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS mm->pmd_huge_pte = NULL; #endif + mm->flags = default_dump_filter; + mm->def_flags = 0; + + if (mm_alloc_pgd(mm)) + goto fail_nopgd; + + return mm; + +fail_nopgd: + free_mm(mm); + return NULL; +} + +/** + * Initialize all the task-related fields of a mm_struct. + **/ +struct mm_struct *mm_set_task(struct mm_struct *mm, struct task_struct *p, + struct user_namespace *user_ns) +{ if (current->mm) { mm->flags = current->mm->flags & MMF_INIT_MASK; mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK; - } else { - mm->flags = default_dump_filter; - mm->def_flags = 0; } - if (mm_alloc_pgd(mm)) - goto fail_nopgd; - + mm_init_owner(mm, p); if (init_new_context(p, mm)) goto fail_nocontext;
@@ -793,11 +808,21 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, fail_nocontext: mm_free_pgd(mm); -fail_nopgd: free_mm(mm); return NULL; } +static struct mm_struct *mm_setup_all(struct mm_struct *mm, + struct task_struct *p, + struct user_namespace *user_ns) +{ + mm = mm_setup(mm); + if (!mm) + return NULL; + + return mm_set_task(mm, p, user_ns); +} + static void check_mm(struct mm_struct *mm) { int i;
@@ -822,10 +847,22 @@ static void check_mm(struct mm_struct *mm) #endif } +struct mm_struct *mm_alloc(void) +{ + struct mm_struct *mm; + + mm = allocate_mm(); + if (!mm) + return NULL; + + memset(mm, 0, sizeof(*mm)); + return mm; +} + /* * Allocate and initialize an mm_struct. */ -struct mm_struct *mm_alloc(void) +struct mm_struct *mm_alloc_and_setup(void) { struct mm_struct *mm;
@@ -834,9 +871,10 @@ struct mm_struct *mm_alloc(void) return NULL; memset(mm, 0, sizeof(*mm)); - return mm_init(mm, current, current_user_ns()); + return mm_setup_all(mm, current, current_user_ns()); } + /* * Called when the last reference to the mm * is dropped: either by a lazy thread or by
@@ -1131,7 +1169,7 @@ static struct mm_struct *dup_mm(struct task_struct *tsk) memcpy(mm, oldmm, sizeof(*mm)); - if (!mm_init(mm, tsk, mm->user_ns)) + if (!mm_setup_all(mm, tsk, mm->user_ns)) goto fail_nomem; err = dup_mmap(mm, oldmm);
--
2.12.0
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>