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

Oleg Nesterov
2005-12-24T16:37:25Z

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.