[lkml]   [2009]   [Aug]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[PATCH 3/2] tty-ldisc: be more careful in 'put_ldisc' locking

    From: Linus Torvalds <>
    Date: Mon, 3 Aug 2009 14:55:24 -0700
    Subject: [PATCH 3/2] tty-ldisc: be more careful in 'put_ldisc' locking

    Use 'atomic_dec_and_lock()' to make sure that we always hold the
    tty_ldisc_lock when the ldisc count goes to zero. That way we can never
    race against 'tty_ldisc_try()' increasing the count again.

    Reported-by: OGAWA Hirofumi <>
    Signed-off-by: Linus Torvalds <>
    drivers/char/tty_ldisc.c | 17 ++++++++++++-----
    1 files changed, 12 insertions(+), 5 deletions(-)

    Ok, this is strictly speaking a bugfix, but the race is so unlikely that I
    doubt that you'll see it in testing.

    So testing just patches 1-2 is fine, but this is a good idea on top of

    I'll be sending out two further patches after this that are pure cleanups
    (numbered 4/2 and 5/2). Again, testing them would be wonderful, but not
    essential - they're not as interesting or important as 1-2 were.

    On Mon, 3 Aug 2009, Linus Torvalds wrote:
    > Ogawa found a race in my original 2/2, and Greg has a small fix pending,
    > but that almost certainly won't realistically matter for any real-life
    > testing, so you don't really need to worry about it.
    > But I'll forward that patch (and another couple cleanup patch) for you for
    > testing after I've verified it myself. But don't feel like you have to
    > worry about those extra patches - testing the initial refcount handling is
    > the thing that matters most, the thing I have pending really is just
    > details.
    > Linus

    diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
    index be55dfc..1733d34 100644
    --- a/drivers/char/tty_ldisc.c
    +++ b/drivers/char/tty_ldisc.c
    @@ -55,25 +55,32 @@ static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
    return ld;

    -static inline void put_ldisc(struct tty_ldisc *ld)
    +static void put_ldisc(struct tty_ldisc *ld)
    + unsigned long flags;
    if (WARN_ON_ONCE(!ld))

    * If this is the last user, free the ldisc, and
    * release the ldisc ops.
    + *
    + * We really want an "atomic_dec_and_lock_irqsave()",
    + * but we don't have it, so this does it by hand.
    - if (atomic_dec_and_test(&ld->users)) {
    - unsigned long flags;
    + local_irq_save(flags);
    + if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
    struct tty_ldisc_ops *ldo = ld->ops;

    - kfree(ld);
    - spin_lock_irqsave(&tty_ldisc_lock, flags);
    spin_unlock_irqrestore(&tty_ldisc_lock, flags);
    + kfree(ld);
    + return;
    + local_irq_restore(flags);


     \ /
      Last update: 2009-10-18 23:28    [W:0.253 / U:11.492 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site