lkml.org 
[lkml]   [1999]   [Jan]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subjectvfork & co bugfix
    From
    Date

    Looking at vfork in 2.2.0-pre6 I was struck by how badly
    looking at current, (to release a process) hacks up mmput.

    It took a little while but eventually a case where
    this really goes wrong.

    In:
    kernel/fork.c:copy_mm
    fs/exec.c/exec_mmap

    If the we can't allocate page tables, we currently erroneously
    wake up a vfork waiter, and clear our segments, and set the ldt
    to that of init.

    To correct this I've added a companion function mm_release
    that we call to remove any dangling references to the old
    mm_struct of the current process.

    This also ensures that segment and ldt clearing happen for every x86
    process. Not just when the previous memory area was totally freed.

    Eric

    diff -uNrX linux-ignore-files linux-2.2.0-pre6/arch/i386/kernel/process.c linux-2.2.0-pre6.eb1/arch/i386/kernel/process.c
    --- linux-2.2.0-pre6/arch/i386/kernel/process.c Sat Jan 9 13:33:02 1999
    +++ linux-2.2.0-pre6.eb1/arch/i386/kernel/process.c Sun Jan 10 01:26:17 1999
    @@ -475,22 +475,25 @@

    void release_segments(struct mm_struct *mm)
    {
    - /* forget local segments */
    - __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
    - : /* no outputs */
    - : "r" (0));
    if (mm->segments) {
    void * ldt = mm->segments;
    -
    - /*
    - * Get the LDT entry from init_task.
    - */
    - current->tss.ldt = _LDT(0);
    - load_ldt(0);
    -
    mm->segments = NULL;
    vfree(ldt);
    }
    +}
    +
    +void forget_segments(struct task_struct *tsk)
    +{
    + /* forget local segments */
    + __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
    + : /* no outputs */
    + : "r" (0));
    +
    + /*
    + * Get the LDT entry from init_task.
    + */
    + tsk->tss.ldt = _LDT(0);
    + load_ldt(0);
    }

    /*
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/fs/exec.c linux-2.2.0-pre6.eb1/fs/exec.c
    --- linux-2.2.0-pre6/fs/exec.c Fri Dec 25 17:43:18 1998
    +++ linux-2.2.0-pre6.eb1/fs/exec.c Sun Jan 10 01:41:20 1999
    @@ -383,6 +383,7 @@
    exit_mmap(current->mm);
    clear_page_tables(current);
    flush_tlb_mm(current->mm);
    + mm_release(current);
    return 0;
    }

    @@ -413,6 +414,7 @@
    activate_context(current);
    up(&mm->mmap_sem);
    mmput(old_mm);
    + mm_release(current);
    return 0;

    /*
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-alpha/processor.h linux-2.2.0-pre6.eb1/include/asm-alpha/processor.h
    --- linux-2.2.0-pre6/include/asm-alpha/processor.h Fri Dec 25 17:41:47 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-alpha/processor.h Sun Jan 10 00:38:50 1999
    @@ -113,6 +113,7 @@

    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    /* NOTE: The task struct and the stack go together! */
    #define alloc_task_struct() \
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-arm/processor.h linux-2.2.0-pre6.eb1/include/asm-arm/processor.h
    --- linux-2.2.0-pre6/include/asm-arm/processor.h Sun Oct 11 14:16:42 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-arm/processor.h Sun Jan 10 01:15:50 1999
    @@ -53,11 +53,9 @@
    extern void release_thread(struct task_struct *);

    /* Copy and release all segment info associated with a VM */
    -extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
    -extern void release_segments(struct mm_struct * mm);
    -
    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    #define init_task (init_task_union.task)
    #define init_stack (init_task_union.stack)
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-i386/processor.h linux-2.2.0-pre6.eb1/include/asm-i386/processor.h
    --- linux-2.2.0-pre6/include/asm-i386/processor.h Wed Jan 6 23:51:10 1999
    +++ linux-2.2.0-pre6.eb1/include/asm-i386/processor.h Sun Jan 10 01:16:30 1999
    @@ -281,6 +281,7 @@
    /* Copy and release all segment info associated with a VM */
    extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
    extern void release_segments(struct mm_struct * mm);
    +extern void forget_segments(struct task_struct * tsk);

    /*
    * FPU lazy state save handling..
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-m68k/processor.h linux-2.2.0-pre6.eb1/include/asm-m68k/processor.h
    --- linux-2.2.0-pre6/include/asm-m68k/processor.h Sun Oct 11 14:09:34 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-m68k/processor.h Sun Jan 10 00:41:10 1999
    @@ -74,6 +74,7 @@

    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    /*
    * Free current thread data structures etc..
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-mips/processor.h linux-2.2.0-pre6.eb1/include/asm-mips/processor.h
    --- linux-2.2.0-pre6/include/asm-mips/processor.h Fri Dec 25 17:41:48 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-mips/processor.h Sun Jan 10 00:42:10 1999
    @@ -178,6 +178,7 @@
    /* Copy and release all segment info associated with a VM */
    #define copy_segments(nr, p, mm) do { } while(0)
    #define release_segments(mm) do { } while(0)
    +#define forget_segments(tsk) do { } while (0)

    /*
    * Return saved PC of a blocked thread.
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-ppc/processor.h linux-2.2.0-pre6.eb1/include/asm-ppc/processor.h
    --- linux-2.2.0-pre6/include/asm-ppc/processor.h Sun Oct 11 14:18:12 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-ppc/processor.h Sun Jan 10 00:42:32 1999
    @@ -299,6 +299,7 @@

    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    /*
    * NOTE! The task struct and the stack go together
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-sparc/processor.h linux-2.2.0-pre6.eb1/include/asm-sparc/processor.h
    --- linux-2.2.0-pre6/include/asm-sparc/processor.h Sun Oct 11 14:13:51 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-sparc/processor.h Sun Jan 10 00:43:45 1999
    @@ -148,6 +148,7 @@

    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    #ifdef __KERNEL__

    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/asm-sparc64/processor.h linux-2.2.0-pre6.eb1/include/asm-sparc64/processor.h
    --- linux-2.2.0-pre6/include/asm-sparc64/processor.h Fri Dec 25 17:42:26 1998
    +++ linux-2.2.0-pre6.eb1/include/asm-sparc64/processor.h Sun Jan 10 00:44:37 1999
    @@ -208,6 +208,7 @@

    #define copy_segments(nr, tsk, mm) do { } while (0)
    #define release_segments(mm) do { } while (0)
    +#define forget_segments(tsk) do { } while (0)

    #ifdef __KERNEL__
    /* Allocation and freeing of task_struct and kernel stack. */
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/include/linux/sched.h linux-2.2.0-pre6.eb1/include/linux/sched.h
    --- linux-2.2.0-pre6/include/linux/sched.h Sat Jan 9 13:33:21 1999
    +++ linux-2.2.0-pre6.eb1/include/linux/sched.h Sun Jan 10 01:16:53 1999
    @@ -609,6 +609,8 @@
    atomic_inc(&mm->count);
    }
    extern void mmput(struct mm_struct *);
    +/* Remove the current tasks stale references to the old mm_struct */
    +extern void mm_release(struct task_struct *);

    extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
    extern void flush_thread(void);
    diff -uNrX linux-ignore-files linux-2.2.0-pre6/kernel/exit.c linux-2.2.0-pre6.eb1/kernel/exit.c
    --- linux-2.2.0-pre6/kernel/exit.c Sat Jan 9 13:33:22 1999
    +++ linux-2.2.0-pre6.eb1/kernel/exit.c Sun Jan 10 00:19:03 1999
    @@ -259,6 +259,7 @@
    tsk->swappable = 0;
    SET_PAGE_DIR(tsk, swapper_pg_dir);
    mmput(mm);
    + mm_release(tsk);
    }
    }

    diff -uNrX linux-ignore-files linux-2.2.0-pre6/kernel/fork.c linux-2.2.0-pre6.eb1/kernel/fork.c
    --- linux-2.2.0-pre6/kernel/fork.c Sat Jan 9 13:33:22 1999
    +++ linux-2.2.0-pre6.eb1/kernel/fork.c Sun Jan 10 01:20:06 1999
    @@ -278,14 +278,19 @@
    return mm;
    }

    +void mm_release(struct task_struct *tsk)
    +{
    + forget_segments(tsk);
    + /* Notify parent sleeping on vfork().
    + */
    + wake_up(&tsk->p_opptr->vfork_sleep);
    +}
    +
    /*
    * Decrement the use count and release all resources for an mm.
    */
    void mmput(struct mm_struct *mm)
    {
    - /* notify parent sleeping on vfork() */
    - wake_up(&current->p_opptr->vfork_sleep);
    -
    if (atomic_dec_and_test(&mm->count)) {
    release_segments(mm);
    exit_mmap(mm);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.rutgers.edu
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 13:49    [W:3.699 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site