Re: [rfc][patch] Avoid taking global tasklist_lock for single threaded process at getrusage()

From: Oleg Nesterov
Date: Sat Dec 24 2005 - 11:36:28 EST


Ravikiran G Thirumalai wrote:
>
> +int getrusage_both(struct task_struct *p, struct rusage __user *ru)
> {
> + unsigned long flags;
> + int lockflag = 0;
> + cputime_t utime, stime;
> struct rusage r;
> - read_lock(&tasklist_lock);
> - k_getrusage(p, who, &r);
> - read_unlock(&tasklist_lock);
> + struct task_struct *t;
> + memset((char *) &r, 0, sizeof (r));
> +
> + if (unlikely(!p->signal))
> + return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
> +
> + if (!thread_group_empty(p)) {
> + read_lock(&tasklist_lock);
> + lockflag = 1;
> + }

I can't understand this. 'p' can do clone(CLONE_THREAD) immediately
after 'if (!thread_group_empty(p))' check.

> + spin_lock_irqsave(&p->sighand->siglock, flags);

It is unsafe to do (unless p == current or tasklist held) even if
'p' is the only one process in the thread group.

p->sighand can be changed (and even freed) if 'p' does exec, see
de_thread().

p->sighand may be NULL , nothing prevents 'p' from release_task(p).
This patch checks p->signal, but this is meaningless unless it was
done under tasklist_lock.

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