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 <till.smej...@gmail.com> --- 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