From: Peter Zijlstra <a.p.zijlstra@chello.nl>
To: Oleg Nesterov <oleg@tv-sign.ru>
Cc: linux-kernel <linux-kernel@vger.kernel.org>,
Prarit Bhargava <prarit@redhat.com>,
Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: Re: [RFC][PATCH] ->signal->tty locking
Date: Tue, 17 Oct 2006 12:17:01 +0200 [thread overview]
Message-ID: <1161080221.3036.38.camel@taijtu> (raw)
In-Reply-To: <20061017081018.GA115@oleg>
On Tue, 2006-10-17 at 12:10 +0400, Oleg Nesterov wrote:
> On 10/16, Peter Zijlstra wrote:
> >
> > Oleg wrote:
> > "Historically ->signal/->sighand (both ptrs and their contents) were globally
> > protected by tasklist_lock. 'current' can use these pointers lockless, they
> > can't be changed under him.
> >
> > Nowadays ->signal/->sighand are _also_ protected by ->sighand->siglock.
> > Unless you are current, you can't lock ->siglock directly (without holding
> > tasklist_lock), you should use lock_task_sighand()."
> >
> > Then, to be consistent with the rest of the kernel, ->signal->tty
> > locking should look like so:
> >
> > mutex_lock(&tty_mutex)
> > read_lock(&tasklist_lock)
> > lock_task_sighand(p, &flags)
>
> I've also started similar patches, but have no time to finish it.
>
> I don't think we need tasklist_lock. I think ->sighand->siglock is enough.
Right, sys_unshare() makes tasklist_lock meaningless wrt ->siglock.
> So do_task_stat() doesn't need to take tty_mutex at all.
>
> However, tty_mutex protects ->tty from release_dev(tty), so it is also
> possible to do:
>
> mutex_lock(&tty_mutex);
> tty = task->signal->tty;
> barrier();
> if (tty) {
> // ->tty could be changed/cleared from under us,
> // but it can't be released while we are holding
> // tty_mutex
> do_something(tty);
> }
> ...
Nice, I think we have to convert all those callers like sys_vhangup() to
this form.
> > @@ -1350,20 +1357,26 @@ static void do_tty_hangup(void *data)
> > This should get done automatically when the port closes and
> > tty_release is called */
> >
> > + mutex_lock(&tty_mutex);
>
> I am not sure it is needed.
Right, this would only be needed when using the tty, not when changing
signal->tty.
> > read_lock(&tasklist_lock);
> > if (tty->session > 0) {
> > do_each_task_pid(tty->session, PIDTYPE_SID, p) {
> > + lock_task_sighand(p, &flags);
> > if (p->signal->tty == tty)
> > p->signal->tty = NULL;
> > + unlock_task_sighand(p, &flags);
>
> We don't need lock_task_sighand() here, we can use spin_lock_irq(->siglock).
>
> We are holding tasklist_lock. This means that all tasks found by
> do_each_task_pid() have a valid ->signal/->sighand != NULL.
> tasklist_lock protects against release_task()->__exit_signal() and
> from changing ->sighand by de_thread().
I think sys_unshare() spoils the game here; it changes ->sighand in
midair without holding tasklist_lock. So any ->sighand but current's is
fair game.
Hmm, either sys_unshare() is broken in that it doesn't take the
tasklist_lock or a lot of other code is broken.
let us take send_sig_info() vs. sys_unshare()
1 2
read_lock(&tasklist_lock)
spin_lock_irqsave(&p->sighand->siglock, flags);
rcu_assign_pointer(current->sighand, new_sigh)
spin_unlock_irqsave(&p->sighand->siglock, flags);
read_unlock(&tasklist_lock);
what happens when 2's current is 1's p....
> > @@ -2910,20 +2953,23 @@ static int tiocsctty(struct tty_struct *
> >
> > read_lock(&tasklist_lock);
> > do_each_task_pid(tty->session, PIDTYPE_SID, p) {
> > + lock_task_sighand(p, &flags);
> > p->signal->tty = NULL;
> > + unlock_task_sighand(p, &flags);
> > } while_each_task_pid(tty->session, PIDTYPE_SID, p);
> > read_unlock(&tasklist_lock);
> > - } else
> > + } else {
> > + mutex_unlock(&tty_mutex);
> > return -EPERM;
> > + }
> > }
> > - mutex_lock(&tty_mutex);
> > - task_lock(current);
> > - current->signal->tty = tty;
> > - task_unlock(current);
> > - mutex_unlock(&tty_mutex);
> > - current->signal->tty_old_pgrp = 0;
> > tty->session = current->signal->session;
> > tty->pgrp = process_group(current);
> > + lock_task_sighand(current, &flags);
> > + current->signal->tty = tty;
> > + current->signal->tty_old_pgrp = 0;
> > + unlock_task_sighand(current, &flags);
> > + mutex_unlock(&tty_mutex);
> > return 0;
> > }
>
> There is a very similar code in tty_open(), probably we need another
> helper, proc_set_tty().
>
> But I am not sure about locking. I think we should check
> ->signal->leader/->signal->tty and set ->tty in proc_set_tty()
> under ->siglock, this way we can remove tty_mutex from sys_setsid().
Right, use tty_mutex when using the tty, use ->sighand when changing
signal->tty.
next prev parent reply other threads:[~2006-10-17 12:18 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-10-16 9:53 [RFC][PATCH] ->signal->tty locking Peter Zijlstra
2006-10-16 13:39 ` Prarit Bhargava
2006-10-17 8:10 ` Oleg Nesterov
2006-10-17 10:17 ` Peter Zijlstra [this message]
2006-10-17 12:33 ` Oleg Nesterov
2006-10-17 13:00 ` Peter Zijlstra
2006-10-17 14:08 ` Alan Cox
2006-10-18 16:55 ` Oleg Nesterov
2006-10-17 13:29 ` Alan Cox
2006-10-18 17:21 ` Oleg Nesterov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1161080221.3036.38.camel@taijtu \
--to=a.p.zijlstra@chello.nl \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=oleg@tv-sign.ru \
--cc=prarit@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox