lkml.org 
[lkml]   [2014]   [Nov]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 5/5] exit: ptrace: shift "reap dead" code from exit_ptrace() to forget_original_parent()
    Now that forget_original_parent() uses ->ptrace_entry for EXIT_DEAD
    tasks, we can simply pass "dead_children" list to exit_ptrace() and
    remove another release_task() loop. Plus this way we do not need to
    drop and reacquire tasklist_lock.

    Also shift the list_empty(ptraced) check, if we want this optimization
    it makes sense to eliminate the function call altogether.

    Signed-off-by: Oleg Nesterov <oleg@redhat.com>
    ---
    include/linux/ptrace.h | 2 +-
    kernel/exit.c | 10 ++++------
    kernel/ptrace.c | 23 +++--------------------
    3 files changed, 8 insertions(+), 27 deletions(-)

    diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
    index cc79eff..987a73a 100644
    --- a/include/linux/ptrace.h
    +++ b/include/linux/ptrace.h
    @@ -52,7 +52,7 @@ extern void ptrace_notify(int exit_code);
    extern void __ptrace_link(struct task_struct *child,
    struct task_struct *new_parent);
    extern void __ptrace_unlink(struct task_struct *child);
    -extern void exit_ptrace(struct task_struct *tracer);
    +extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
    #define PTRACE_MODE_READ 0x01
    #define PTRACE_MODE_ATTACH 0x02
    #define PTRACE_MODE_NOAUDIT 0x04
    diff --git a/kernel/exit.c b/kernel/exit.c
    index e3e7379..ee5399b 100644
    --- a/kernel/exit.c
    +++ b/kernel/exit.c
    @@ -553,13 +553,11 @@ static void forget_original_parent(struct task_struct *father)
    LIST_HEAD(dead_children);

    write_lock_irq(&tasklist_lock);
    - /*
    - * Note that exit_ptrace() and find_new_reaper() might
    - * drop tasklist_lock and reacquire it.
    - */
    - exit_ptrace(father);
    - reaper = find_new_reaper(father);
    + if (unlikely(!list_empty(&father->ptraced)))
    + exit_ptrace(father, &dead_children);

    + /* Can drop and reacquire tasklist_lock */
    + reaper = find_new_reaper(father);
    list_for_each_entry(p, &father->children, sibling) {
    for_each_thread(p, t) {
    t->real_parent = reaper;
    diff --git a/kernel/ptrace.c b/kernel/ptrace.c
    index 54e7522..1eb9d90 100644
    --- a/kernel/ptrace.c
    +++ b/kernel/ptrace.c
    @@ -485,36 +485,19 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)

    /*
    * Detach all tasks we were using ptrace on. Called with tasklist held
    - * for writing, and returns with it held too. But note it can release
    - * and reacquire the lock.
    + * for writing.
    */
    -void exit_ptrace(struct task_struct *tracer)
    - __releases(&tasklist_lock)
    - __acquires(&tasklist_lock)
    +void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
    {
    struct task_struct *p, *n;
    - LIST_HEAD(ptrace_dead);
    -
    - if (likely(list_empty(&tracer->ptraced)))
    - return;

    list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
    if (unlikely(p->ptrace & PT_EXITKILL))
    send_sig_info(SIGKILL, SEND_SIG_FORCED, p);

    if (__ptrace_detach(tracer, p))
    - list_add(&p->ptrace_entry, &ptrace_dead);
    - }
    -
    - write_unlock_irq(&tasklist_lock);
    - BUG_ON(!list_empty(&tracer->ptraced));
    -
    - list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
    - list_del_init(&p->ptrace_entry);
    - release_task(p);
    + list_add(&p->ptrace_entry, dead);
    }
    -
    - write_lock_irq(&tasklist_lock);
    }

    int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
    --
    1.5.5.1


    \
     
     \ /
      Last update: 2014-11-10 23:41    [W:4.911 / U:0.292 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site