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,
static int exec_mmap(struct mm_struct *mm)
{
struct task_struct *tsk;
struct mm_struct * old_mm, *active_mm;
/* Add it to the list of mm's */
......@@ -505,14 +506,17 @@ static int exec_mmap(struct mm_struct *mm)
mmlist_nr++;
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;
active_mm = current->active_mm;
current->mm = mm;
current->active_mm = mm;
mm_release(tsk, old_mm);
task_lock(tsk);
active_mm = tsk->active_mm;
tsk->mm = mm;
tsk->active_mm = mm;
activate_mm(active_mm, mm);
task_unlock(current);
mm_release();
task_unlock(tsk);
if (old_mm) {
if (active_mm != old_mm) BUG();
mmput(old_mm);
......
......@@ -209,6 +209,8 @@ ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
tbiap();
}
#define deactivate_mm(tsk,mm) do { } while (0)
#ifdef CONFIG_ALPHA_GENERIC
# 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))
......
......@@ -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)
{
cpu_switch_mm(next->pgd, next);
......
......@@ -7,6 +7,8 @@ extern void destroy_context(struct mm_struct *mm);
extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
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())
/* 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
#endif
}
#define deactivate_mm(tsk, mm) \
asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
#define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id())
......
......@@ -143,6 +143,8 @@ activate_context (struct mm_struct *mm)
} while (unlikely(context != mm->context));
}
#define deactivate_mm(tsk,mm) do { } while (0)
/*
* 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
}
}
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev_mm,
struct mm_struct *next_mm)
{
......
......@@ -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,
struct mm_struct *next_mm)
{
......
......@@ -98,6 +98,8 @@ extern inline void destroy_context(struct mm_struct *mm)
/* Nothing to do. */
}
#define deactivate_mm(tsk,mm) do { } while (0)
/*
* After we have set current->mm to a new value, this activates
* 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)
#endif
}
#define deactivate_mm(tsk,mm) do { } while (0)
/*
* After we have set current->mm to a new value, this activates
* 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
}
}
#define deactivate_mm(tsk,mm) do { } while (0)
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,
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
* 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,
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
* 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,
set_bit(cpu, &next->cpu_vm_mask);
}
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_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);
}
#define deactivate_mm(tsk,mm) do { } while (0)
extern inline void activate_mm(struct mm_struct *prev,
struct mm_struct *next)
{
......
......@@ -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) \
switch_mm((prev),(next),NULL,smp_processor_id())
......
......@@ -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 deactivate_mm(tsk,mm) do { } while (0)
/* Activate a new MM instance for the current task. */
#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
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. */
static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
{
......
......@@ -12,6 +12,8 @@
#define get_mmu_context(task) 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)
{
}
......
......@@ -4,6 +4,7 @@
#define destroy_context(mm) ((void)0)
#define init_new_context(tsk,mm) 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 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,
#endif
}
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev, next) \
switch_mm((prev),(next),NULL,smp_processor_id())
......
......@@ -566,7 +566,7 @@ static inline void mmdrop(struct mm_struct * mm)
/* mmput gets rid of the mappings and all user-space */
extern void mmput(struct 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 void flush_thread(void);
......
......@@ -419,7 +419,7 @@ static inline void __exit_mm(struct task_struct * tsk)
{
struct mm_struct *mm = tsk->mm;
mm_release();
mm_release(tsk, mm);
if (!mm)
return;
/*
......
......@@ -399,17 +399,19 @@ void mmput(struct mm_struct *mm)
* restoring the old one. . .
* 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;
/* Get rid of any cached register state */
deactivate_mm(tsk, mm);
/* notify parent sleeping on vfork() */
if (vfork_done) {
tsk->vfork_done = NULL;
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;
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