summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-01-09 07:21:03 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2003-01-09 07:21:03 -0800
commit03a85f8e25d52e15112eb5e146e2766337217ed5 (patch)
tree1db25f2609646decf638d470b0b9e91dfb1ea5ff
parent60e7fd5ede56305f4f05d24c4ae2b5491767efe6 (diff)
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.
-rw-r--r--fs/exec.c16
-rw-r--r--include/asm-alpha/mmu_context.h2
-rw-r--r--include/asm-arm/mmu_context.h2
-rw-r--r--include/asm-cris/mmu_context.h2
-rw-r--r--include/asm-i386/mmu_context.h3
-rw-r--r--include/asm-ia64/mmu_context.h2
-rw-r--r--include/asm-m68k/mmu_context.h2
-rw-r--r--include/asm-m68knommu/mmu_context.h2
-rw-r--r--include/asm-mips/mmu_context.h2
-rw-r--r--include/asm-mips64/mmu_context.h2
-rw-r--r--include/asm-parisc/mmu_context.h2
-rw-r--r--include/asm-ppc/mmu_context.h2
-rw-r--r--include/asm-ppc64/mmu_context.h2
-rw-r--r--include/asm-s390/mmu_context.h2
-rw-r--r--include/asm-s390x/mmu_context.h2
-rw-r--r--include/asm-sh/mmu_context.h2
-rw-r--r--include/asm-sparc/mmu_context.h2
-rw-r--r--include/asm-sparc64/mmu_context.h2
-rw-r--r--include/asm-um/mmu_context.h2
-rw-r--r--include/asm-v850/mmu_context.h1
-rw-r--r--include/asm-x86_64/mmu_context.h2
-rw-r--r--include/linux/sched.h2
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c8
24 files changed, 57 insertions, 11 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 7f6f6a06fa0a..4bc2f4d75f25 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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);
diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
index 6b811d4f692b..5136e8a36329 100644
--- a/include/asm-alpha/mmu_context.h
+++ b/include/asm-alpha/mmu_context.h
@@ -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))
diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
index bb96efd98d00..3b3b473c668f 100644
--- a/include/asm-arm/mmu_context.h
+++ b/include/asm-arm/mmu_context.h
@@ -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);
diff --git a/include/asm-cris/mmu_context.h b/include/asm-cris/mmu_context.h
index d12f074c7cb2..6a6ea71a85cd 100644
--- a/include/asm-cris/mmu_context.h
+++ b/include/asm-cris/mmu_context.h
@@ -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
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index 1bacef727bba..2c561831e7c5 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -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())
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index 9316945bd04f..479d63d05ed9 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -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.
*/
diff --git a/include/asm-m68k/mmu_context.h b/include/asm-m68k/mmu_context.h
index 0e7dcd886560..43e01962d5d8 100644
--- a/include/asm-m68k/mmu_context.h
+++ b/include/asm-m68k/mmu_context.h
@@ -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)
{
diff --git a/include/asm-m68knommu/mmu_context.h b/include/asm-m68knommu/mmu_context.h
index 60a08a527e66..a4286176513c 100644
--- a/include/asm-m68knommu/mmu_context.h
+++ b/include/asm-m68knommu/mmu_context.h
@@ -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)
{
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index 1e8e9614a012..831ac14231f8 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -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.
diff --git a/include/asm-mips64/mmu_context.h b/include/asm-mips64/mmu_context.h
index f47979cb9725..8ce94726497c 100644
--- a/include/asm-mips64/mmu_context.h
+++ b/include/asm-mips64/mmu_context.h
@@ -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.
diff --git a/include/asm-parisc/mmu_context.h b/include/asm-parisc/mmu_context.h
index e9687b2f8f03..1ff9e5f0582c 100644
--- a/include/asm-parisc/mmu_context.h
+++ b/include/asm-parisc/mmu_context.h
@@ -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)
{
/*
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index e1bccc52fc3d..afed0d7151e5 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -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.
diff --git a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h
index 08d8bd20976a..1014f086e5e7 100644
--- a/include/asm-ppc64/mmu_context.h
+++ b/include/asm-ppc64/mmu_context.h
@@ -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.
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index d58b14cbbdb3..346228089825 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -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)
{
diff --git a/include/asm-s390x/mmu_context.h b/include/asm-s390x/mmu_context.h
index 2af3f46da94f..8d07debc3866 100644
--- a/include/asm-s390x/mmu_context.h
+++ b/include/asm-s390x/mmu_context.h
@@ -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)
{
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
index 47b497a7c77b..c0e1cb4309d7 100644
--- a/include/asm-sh/mmu_context.h
+++ b/include/asm-sh/mmu_context.h
@@ -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())
diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h
index 274707e2d288..f386a8f4bbe8 100644
--- a/include/asm-sparc/mmu_context.h
+++ b/include/asm-sparc/mmu_context.h
@@ -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())
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index 9aab3e4e9d20..ab9eedf22860 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -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)
{
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index e735fe0a95a9..14ca8b2a4628 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -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)
{
}
diff --git a/include/asm-v850/mmu_context.h b/include/asm-v850/mmu_context.h
index 2acc89920d05..24301a46a92e 100644
--- a/include/asm-v850/mmu_context.h
+++ b/include/asm-v850/mmu_context.h
@@ -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)
diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
index 3a0c29d2e02b..296390b6b5ad 100644
--- a/include/asm-x86_64/mmu_context.h
+++ b/include/asm-x86_64/mmu_context.h
@@ -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())
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9545a1957089..9916d377a74b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -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);
diff --git a/kernel/exit.c b/kernel/exit.c
index 6adea537242a..1841978bfa4c 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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;
/*
diff --git a/kernel/fork.c b/kernel/fork.c
index 1850fb64fd5d..b8fcbbc1862a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -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;