Commit 03a85f8e authored by Linus Torvalds's avatar Linus Torvalds Committed by Linus Torvalds

Fix exec_mmap() to release the MM while we still have it active,

to properly de-activate it and make the child_tid logic work
correctly.

Clear %fs/%gs in deactivate_mm() on x86, since our LDT will no
longer be valid after this.

Update mm_release() to deactivate MM state before releasing,
and avoid the expensive child_tid FUTEX if we're the last user
of the MM.
parent 60e7fd5e
...@@ -497,6 +497,7 @@ int kernel_read(struct file *file, unsigned long offset, ...@@ -497,6 +497,7 @@ int kernel_read(struct file *file, unsigned long offset,
static int exec_mmap(struct mm_struct *mm) static int exec_mmap(struct mm_struct *mm)
{ {
struct task_struct *tsk;
struct mm_struct * old_mm, *active_mm; struct mm_struct * old_mm, *active_mm;
/* Add it to the list of mm's */ /* Add it to the list of mm's */
...@@ -505,14 +506,17 @@ static int exec_mmap(struct mm_struct *mm) ...@@ -505,14 +506,17 @@ static int exec_mmap(struct mm_struct *mm)
mmlist_nr++; mmlist_nr++;
spin_unlock(&mmlist_lock); spin_unlock(&mmlist_lock);
task_lock(current); /* Notify parent that we're no longer interested in the old VM */
tsk = current;
old_mm = current->mm; old_mm = current->mm;
active_mm = current->active_mm; mm_release(tsk, old_mm);
current->mm = mm;
current->active_mm = mm; task_lock(tsk);
active_mm = tsk->active_mm;
tsk->mm = mm;
tsk->active_mm = mm;
activate_mm(active_mm, mm); activate_mm(active_mm, mm);
task_unlock(current); task_unlock(tsk);
mm_release();
if (old_mm) { if (old_mm) {
if (active_mm != old_mm) BUG(); if (active_mm != old_mm) BUG();
mmput(old_mm); mmput(old_mm);
......
...@@ -209,6 +209,8 @@ ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm) ...@@ -209,6 +209,8 @@ ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
tbiap(); tbiap();
} }
#define deactivate_mm(tsk,mm) do { } while (0)
#ifdef CONFIG_ALPHA_GENERIC #ifdef CONFIG_ALPHA_GENERIC
# define switch_mm(a,b,c,d) alpha_mv.mv_switch_mm((a),(b),(c),(d)) # define switch_mm(a,b,c,d) alpha_mv.mv_switch_mm((a),(b),(c),(d))
# define activate_mm(x,y) alpha_mv.mv_activate_mm((x),(y)) # define activate_mm(x,y) alpha_mv.mv_activate_mm((x),(y))
......
...@@ -47,6 +47,8 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -47,6 +47,8 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
} }
} }
#define deactivate_mm(tsk,mm) do { } while (0)
static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
{ {
cpu_switch_mm(next->pgd, next); cpu_switch_mm(next->pgd, next);
......
...@@ -7,6 +7,8 @@ extern void destroy_context(struct mm_struct *mm); ...@@ -7,6 +7,8 @@ extern void destroy_context(struct mm_struct *mm);
extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, int cpu); struct task_struct *tsk, int cpu);
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev,next) switch_mm((prev),(next),NULL,smp_processor_id()) #define activate_mm(prev,next) switch_mm((prev),(next),NULL,smp_processor_id())
/* current active pgd - this is similar to other processors pgd /* current active pgd - this is similar to other processors pgd
......
...@@ -62,6 +62,9 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str ...@@ -62,6 +62,9 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
#endif #endif
} }
#define deactivate_mm(tsk, mm) \
asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
#define activate_mm(prev, next) \ #define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id()) switch_mm((prev),(next),NULL,smp_processor_id())
......
...@@ -143,6 +143,8 @@ activate_context (struct mm_struct *mm) ...@@ -143,6 +143,8 @@ activate_context (struct mm_struct *mm)
} while (unlikely(context != mm->context)); } while (unlikely(context != mm->context));
} }
#define deactivate_mm(tsk,mm) do { } while (0)
/* /*
* Switch from address space PREV to address space NEXT. * Switch from address space PREV to address space NEXT.
*/ */
......
...@@ -89,6 +89,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str ...@@ -89,6 +89,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
} }
} }
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev_mm, extern inline void activate_mm(struct mm_struct *prev_mm,
struct mm_struct *next_mm) struct mm_struct *next_mm)
{ {
......
...@@ -23,6 +23,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str ...@@ -23,6 +23,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
{ {
} }
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev_mm, extern inline void activate_mm(struct mm_struct *prev_mm,
struct mm_struct *next_mm) struct mm_struct *next_mm)
{ {
......
...@@ -98,6 +98,8 @@ extern inline void destroy_context(struct mm_struct *mm) ...@@ -98,6 +98,8 @@ extern inline void destroy_context(struct mm_struct *mm)
/* Nothing to do. */ /* Nothing to do. */
} }
#define deactivate_mm(tsk,mm) do { } while (0)
/* /*
* After we have set current->mm to a new value, this activates * After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings. * the context for the new mm so we see the new mappings.
......
...@@ -111,6 +111,8 @@ extern inline void destroy_context(struct mm_struct *mm) ...@@ -111,6 +111,8 @@ extern inline void destroy_context(struct mm_struct *mm)
#endif #endif
} }
#define deactivate_mm(tsk,mm) do { } while (0)
/* /*
* After we have set current->mm to a new value, this activates * After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings. * the context for the new mm so we see the new mappings.
......
...@@ -52,6 +52,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str ...@@ -52,6 +52,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
} }
} }
#define deactivate_mm(tsk,mm) do { } while (0)
static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
{ {
/* /*
......
...@@ -160,6 +160,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -160,6 +160,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
set_context(next->context, next->pgd); set_context(next->context, next->pgd);
} }
#define deactivate_mm(tsk,mm) do { } while (0)
/* /*
* After we have set current->mm to a new value, this activates * After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings. * the context for the new mm so we see the new mappings.
......
...@@ -146,6 +146,8 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -146,6 +146,8 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
set_bit(cpu, &next->cpu_vm_mask); set_bit(cpu, &next->cpu_vm_mask);
} }
#define deactivate_mm(tsk,mm) do { } while (0)
/* /*
* After we have set current->mm to a new value, this activates * After we have set current->mm to a new value, this activates
* the context for the new mm so we see the new mappings. * the context for the new mm so we see the new mappings.
......
...@@ -37,6 +37,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -37,6 +37,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
set_bit(cpu, &next->cpu_vm_mask); set_bit(cpu, &next->cpu_vm_mask);
} }
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev, extern inline void activate_mm(struct mm_struct *prev,
struct mm_struct *next) struct mm_struct *next)
{ {
......
...@@ -36,6 +36,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -36,6 +36,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
set_bit(cpu, &next->cpu_vm_mask); set_bit(cpu, &next->cpu_vm_mask);
} }
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev, extern inline void activate_mm(struct mm_struct *prev,
struct mm_struct *next) struct mm_struct *next)
{ {
......
...@@ -178,6 +178,8 @@ static __inline__ void switch_mm(struct mm_struct *prev, ...@@ -178,6 +178,8 @@ static __inline__ void switch_mm(struct mm_struct *prev,
} }
} }
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev, next) \ #define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id()) switch_mm((prev),(next),NULL,smp_processor_id())
......
...@@ -30,6 +30,8 @@ BTFIXUPDEF_CALL(void, switch_mm, struct mm_struct *, struct mm_struct *, struct ...@@ -30,6 +30,8 @@ BTFIXUPDEF_CALL(void, switch_mm, struct mm_struct *, struct mm_struct *, struct
#define switch_mm(old_mm, mm, tsk, cpu) BTFIXUP_CALL(switch_mm)(old_mm, mm, tsk, cpu) #define switch_mm(old_mm, mm, tsk, cpu) BTFIXUP_CALL(switch_mm)(old_mm, mm, tsk, cpu)
#define deactivate_mm(tsk,mm) do { } while (0)
/* Activate a new MM instance for the current task. */ /* Activate a new MM instance for the current task. */
#define activate_mm(active_mm, mm) switch_mm((active_mm), (mm), NULL, smp_processor_id()) #define activate_mm(active_mm, mm) switch_mm((active_mm), (mm), NULL, smp_processor_id())
......
...@@ -143,6 +143,8 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str ...@@ -143,6 +143,8 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
extern void __flush_tlb_mm(unsigned long, unsigned long); extern void __flush_tlb_mm(unsigned long, unsigned long);
#define deactivate_mm(tsk,mm) do { } while (0)
/* Activate a new MM instance for the current task. */ /* Activate a new MM instance for the current task. */
static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
{ {
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#define get_mmu_context(task) do ; while(0) #define get_mmu_context(task) do ; while(0)
#define activate_context(tsk) do ; while(0) #define activate_context(tsk) do ; while(0)
#define deactivate_mm(tsk,mm) do { } while (0)
static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
{ {
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define destroy_context(mm) ((void)0) #define destroy_context(mm) ((void)0)
#define init_new_context(tsk,mm) 0 #define init_new_context(tsk,mm) 0
#define switch_mm(prev,next,tsk,cpu) ((void)0) #define switch_mm(prev,next,tsk,cpu) ((void)0)
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev,next) ((void)0) #define activate_mm(prev,next) ((void)0)
#define enter_lazy_tlb(mm,tsk,cpu) ((void)0) #define enter_lazy_tlb(mm,tsk,cpu) ((void)0)
......
...@@ -62,6 +62,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ...@@ -62,6 +62,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
#endif #endif
} }
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev, next) \ #define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id()) switch_mm((prev),(next),NULL,smp_processor_id())
......
...@@ -566,7 +566,7 @@ static inline void mmdrop(struct mm_struct * mm) ...@@ -566,7 +566,7 @@ static inline void mmdrop(struct mm_struct * mm)
/* mmput gets rid of the mappings and all user-space */ /* mmput gets rid of the mappings and all user-space */
extern void mmput(struct mm_struct *); extern void mmput(struct mm_struct *);
/* Remove the current tasks stale references to the old mm_struct */ /* Remove the current tasks stale references to the old mm_struct */
extern void mm_release(void); extern void mm_release(struct task_struct *, struct mm_struct *);
extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
extern void flush_thread(void); extern void flush_thread(void);
......
...@@ -419,7 +419,7 @@ static inline void __exit_mm(struct task_struct * tsk) ...@@ -419,7 +419,7 @@ static inline void __exit_mm(struct task_struct * tsk)
{ {
struct mm_struct *mm = tsk->mm; struct mm_struct *mm = tsk->mm;
mm_release(); mm_release(tsk, mm);
if (!mm) if (!mm)
return; return;
/* /*
......
...@@ -399,17 +399,19 @@ void mmput(struct mm_struct *mm) ...@@ -399,17 +399,19 @@ void mmput(struct mm_struct *mm)
* restoring the old one. . . * restoring the old one. . .
* Eric Biederman 10 January 1998 * Eric Biederman 10 January 1998
*/ */
void mm_release(void) void mm_release(struct task_struct *tsk, struct mm_struct *mm)
{ {
struct task_struct *tsk = current;
struct completion *vfork_done = tsk->vfork_done; struct completion *vfork_done = tsk->vfork_done;
/* Get rid of any cached register state */
deactivate_mm(tsk, mm);
/* notify parent sleeping on vfork() */ /* notify parent sleeping on vfork() */
if (vfork_done) { if (vfork_done) {
tsk->vfork_done = NULL; tsk->vfork_done = NULL;
complete(vfork_done); complete(vfork_done);
} }
if (tsk->clear_child_tid) { if (tsk->clear_child_tid && atomic_read(&mm->mm_users) > 1) {
int * tidptr = tsk->clear_child_tid; int * tidptr = tsk->clear_child_tid;
tsk->clear_child_tid = NULL; tsk->clear_child_tid = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment