All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: Greg Kroah-Hartman <gregkh@suse.de>,
	Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, Amit Shah <amit.shah@redhat.com>,
	linuxppc-dev@ozlabs.org, Rusty Russell <rusty@rustcorp.com.au>,
	Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: Re: [PATCH 4/7] hvc_console: Fix race between hvc_close and hvc_remove
Date: Sun, 21 Mar 2010 08:04:39 +1100	[thread overview]
Message-ID: <1269119079.8599.65.camel@pasglop> (raw)
In-Reply-To: <1269011916-8836-4-git-send-email-gregkh@suse.de>

On Fri, 2010-03-19 at 08:18 -0700, Greg Kroah-Hartman wrote:
> From: Amit Shah <amit.shah@redhat.com>
> 
> Alan pointed out a race in the code where hvc_remove is invoked. The
> recent virtio_console work is the first user of hvc_remove().

This causes hangs during boot on pseries machines. Haven't had a chance
to track that down yet, but please revert
e74d098c66543d0731de62eb747ccd5b636a6f4c for now.

Cheers,
Ben.


> Alan describes it thus:
> 
> The hvc_console assumes that a close and remove call can't occur at the
> same time.
> 
> In addition tty_hangup(tty) is problematic as tty_hangup is asynchronous
> itself....
> 
> So this can happen
> 
>         hvc_close                               hvc_remove
>         hung up ? - no
>                                                 lock
>                                                 tty = hp->tty
>                                                 unlock
>         lock
>         hp->tty = NULL
>         unlock
>         notify del
>         kref_put the hvc struct
>         close completes
>         tty is destroyed
>                                                 tty_hangup dead tty
>                                                 tty->ops will be NULL
>                                                 NULL->...
> 
> This patch adds some tty krefs and also converts to using tty_vhangup().
> 
> Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
> Signed-off-by: Amit Shah <amit.shah@redhat.com>
> CC: Alan Cox <alan@lxorguk.ukuu.org.uk>
> CC: linuxppc-dev@ozlabs.org
> CC: Rusty Russell <rusty@rustcorp.com.au>
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> ---
>  drivers/char/hvc_console.c |   31 +++++++++++++++++++++----------
>  1 files changed, 21 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
> index 465185f..ba55bba 100644
> --- a/drivers/char/hvc_console.c
> +++ b/drivers/char/hvc_console.c
> @@ -312,6 +312,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  	spin_lock_irqsave(&hp->lock, flags);
>  	/* Check and then increment for fast path open. */
>  	if (hp->count++ > 0) {
> +		tty_kref_get(tty);
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  		hvc_kick();
>  		return 0;
> @@ -319,7 +320,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  
>  	tty->driver_data = hp;
>  
> -	hp->tty = tty;
> +	hp->tty = tty_kref_get(tty);
>  
>  	spin_unlock_irqrestore(&hp->lock, flags);
>  
> @@ -336,6 +337,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  		spin_lock_irqsave(&hp->lock, flags);
>  		hp->tty = NULL;
>  		spin_unlock_irqrestore(&hp->lock, flags);
> +		tty_kref_put(tty);
>  		tty->driver_data = NULL;
>  		kref_put(&hp->kref, destroy_hvc_struct);
>  		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
> @@ -363,13 +365,18 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
>  		return;
>  
>  	hp = tty->driver_data;
> +
>  	spin_lock_irqsave(&hp->lock, flags);
> +	tty_kref_get(tty);
>  
>  	if (--hp->count == 0) {
>  		/* We are done with the tty pointer now. */
>  		hp->tty = NULL;
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  
> +		/* Put the ref obtained in hvc_open() */
> +		tty_kref_put(tty);
> +
>  		if (hp->ops->notifier_del)
>  			hp->ops->notifier_del(hp, hp->data);
>  
> @@ -389,6 +396,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  	}
>  
> +	tty_kref_put(tty);
>  	kref_put(&hp->kref, destroy_hvc_struct);
>  }
>  
> @@ -424,10 +432,11 @@ static void hvc_hangup(struct tty_struct *tty)
>  	spin_unlock_irqrestore(&hp->lock, flags);
>  
>  	if (hp->ops->notifier_hangup)
> -			hp->ops->notifier_hangup(hp, hp->data);
> +		hp->ops->notifier_hangup(hp, hp->data);
>  
>  	while(temp_open_count) {
>  		--temp_open_count;
> +		tty_kref_put(tty);
>  		kref_put(&hp->kref, destroy_hvc_struct);
>  	}
>  }
> @@ -592,7 +601,7 @@ int hvc_poll(struct hvc_struct *hp)
>  	}
>  
>  	/* No tty attached, just skip */
> -	tty = hp->tty;
> +	tty = tty_kref_get(hp->tty);
>  	if (tty == NULL)
>  		goto bail;
>  
> @@ -672,6 +681,8 @@ int hvc_poll(struct hvc_struct *hp)
>  
>  		tty_flip_buffer_push(tty);
>  	}
> +	if (tty)
> +		tty_kref_put(tty);
>  
>  	return poll_mask;
>  }
> @@ -807,7 +818,7 @@ int hvc_remove(struct hvc_struct *hp)
>  	struct tty_struct *tty;
>  
>  	spin_lock_irqsave(&hp->lock, flags);
> -	tty = hp->tty;
> +	tty = tty_kref_get(hp->tty);
>  
>  	if (hp->index < MAX_NR_HVC_CONSOLES)
>  		vtermnos[hp->index] = -1;
> @@ -819,18 +830,18 @@ int hvc_remove(struct hvc_struct *hp)
>  	/*
>  	 * We 'put' the instance that was grabbed when the kref instance
>  	 * was initialized using kref_init().  Let the last holder of this
> -	 * kref cause it to be removed, which will probably be the tty_hangup
> +	 * kref cause it to be removed, which will probably be the tty_vhangup
>  	 * below.
>  	 */
>  	kref_put(&hp->kref, destroy_hvc_struct);
>  
>  	/*
> -	 * This function call will auto chain call hvc_hangup.  The tty should
> -	 * always be valid at this time unless a simultaneous tty close already
> -	 * cleaned up the hvc_struct.
> +	 * This function call will auto chain call hvc_hangup.
>  	 */
> -	if (tty)
> -		tty_hangup(tty);
> +	if (tty) {
> +		tty_vhangup(tty);
> +		tty_kref_put(tty);
> +	}
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(hvc_remove);



WARNING: multiple messages have this Message-ID (diff)
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: Greg Kroah-Hartman <gregkh@suse.de>,
	Linus Torvalds <torvalds@linux-foundation.org>
Cc: Amit Shah <amit.shah@redhat.com>,
	linuxppc-dev@ozlabs.org, Rusty Russell <rusty@rustcorp.com.au>,
	linux-kernel@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: Re: [PATCH 4/7] hvc_console: Fix race between hvc_close and hvc_remove
Date: Sun, 21 Mar 2010 08:04:39 +1100	[thread overview]
Message-ID: <1269119079.8599.65.camel@pasglop> (raw)
In-Reply-To: <1269011916-8836-4-git-send-email-gregkh@suse.de>

On Fri, 2010-03-19 at 08:18 -0700, Greg Kroah-Hartman wrote:
> From: Amit Shah <amit.shah@redhat.com>
> 
> Alan pointed out a race in the code where hvc_remove is invoked. The
> recent virtio_console work is the first user of hvc_remove().

This causes hangs during boot on pseries machines. Haven't had a chance
to track that down yet, but please revert
e74d098c66543d0731de62eb747ccd5b636a6f4c for now.

Cheers,
Ben.


> Alan describes it thus:
> 
> The hvc_console assumes that a close and remove call can't occur at the
> same time.
> 
> In addition tty_hangup(tty) is problematic as tty_hangup is asynchronous
> itself....
> 
> So this can happen
> 
>         hvc_close                               hvc_remove
>         hung up ? - no
>                                                 lock
>                                                 tty = hp->tty
>                                                 unlock
>         lock
>         hp->tty = NULL
>         unlock
>         notify del
>         kref_put the hvc struct
>         close completes
>         tty is destroyed
>                                                 tty_hangup dead tty
>                                                 tty->ops will be NULL
>                                                 NULL->...
> 
> This patch adds some tty krefs and also converts to using tty_vhangup().
> 
> Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
> Signed-off-by: Amit Shah <amit.shah@redhat.com>
> CC: Alan Cox <alan@lxorguk.ukuu.org.uk>
> CC: linuxppc-dev@ozlabs.org
> CC: Rusty Russell <rusty@rustcorp.com.au>
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> ---
>  drivers/char/hvc_console.c |   31 +++++++++++++++++++++----------
>  1 files changed, 21 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
> index 465185f..ba55bba 100644
> --- a/drivers/char/hvc_console.c
> +++ b/drivers/char/hvc_console.c
> @@ -312,6 +312,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  	spin_lock_irqsave(&hp->lock, flags);
>  	/* Check and then increment for fast path open. */
>  	if (hp->count++ > 0) {
> +		tty_kref_get(tty);
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  		hvc_kick();
>  		return 0;
> @@ -319,7 +320,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  
>  	tty->driver_data = hp;
>  
> -	hp->tty = tty;
> +	hp->tty = tty_kref_get(tty);
>  
>  	spin_unlock_irqrestore(&hp->lock, flags);
>  
> @@ -336,6 +337,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
>  		spin_lock_irqsave(&hp->lock, flags);
>  		hp->tty = NULL;
>  		spin_unlock_irqrestore(&hp->lock, flags);
> +		tty_kref_put(tty);
>  		tty->driver_data = NULL;
>  		kref_put(&hp->kref, destroy_hvc_struct);
>  		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
> @@ -363,13 +365,18 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
>  		return;
>  
>  	hp = tty->driver_data;
> +
>  	spin_lock_irqsave(&hp->lock, flags);
> +	tty_kref_get(tty);
>  
>  	if (--hp->count == 0) {
>  		/* We are done with the tty pointer now. */
>  		hp->tty = NULL;
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  
> +		/* Put the ref obtained in hvc_open() */
> +		tty_kref_put(tty);
> +
>  		if (hp->ops->notifier_del)
>  			hp->ops->notifier_del(hp, hp->data);
>  
> @@ -389,6 +396,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
>  		spin_unlock_irqrestore(&hp->lock, flags);
>  	}
>  
> +	tty_kref_put(tty);
>  	kref_put(&hp->kref, destroy_hvc_struct);
>  }
>  
> @@ -424,10 +432,11 @@ static void hvc_hangup(struct tty_struct *tty)
>  	spin_unlock_irqrestore(&hp->lock, flags);
>  
>  	if (hp->ops->notifier_hangup)
> -			hp->ops->notifier_hangup(hp, hp->data);
> +		hp->ops->notifier_hangup(hp, hp->data);
>  
>  	while(temp_open_count) {
>  		--temp_open_count;
> +		tty_kref_put(tty);
>  		kref_put(&hp->kref, destroy_hvc_struct);
>  	}
>  }
> @@ -592,7 +601,7 @@ int hvc_poll(struct hvc_struct *hp)
>  	}
>  
>  	/* No tty attached, just skip */
> -	tty = hp->tty;
> +	tty = tty_kref_get(hp->tty);
>  	if (tty == NULL)
>  		goto bail;
>  
> @@ -672,6 +681,8 @@ int hvc_poll(struct hvc_struct *hp)
>  
>  		tty_flip_buffer_push(tty);
>  	}
> +	if (tty)
> +		tty_kref_put(tty);
>  
>  	return poll_mask;
>  }
> @@ -807,7 +818,7 @@ int hvc_remove(struct hvc_struct *hp)
>  	struct tty_struct *tty;
>  
>  	spin_lock_irqsave(&hp->lock, flags);
> -	tty = hp->tty;
> +	tty = tty_kref_get(hp->tty);
>  
>  	if (hp->index < MAX_NR_HVC_CONSOLES)
>  		vtermnos[hp->index] = -1;
> @@ -819,18 +830,18 @@ int hvc_remove(struct hvc_struct *hp)
>  	/*
>  	 * We 'put' the instance that was grabbed when the kref instance
>  	 * was initialized using kref_init().  Let the last holder of this
> -	 * kref cause it to be removed, which will probably be the tty_hangup
> +	 * kref cause it to be removed, which will probably be the tty_vhangup
>  	 * below.
>  	 */
>  	kref_put(&hp->kref, destroy_hvc_struct);
>  
>  	/*
> -	 * This function call will auto chain call hvc_hangup.  The tty should
> -	 * always be valid at this time unless a simultaneous tty close already
> -	 * cleaned up the hvc_struct.
> +	 * This function call will auto chain call hvc_hangup.
>  	 */
> -	if (tty)
> -		tty_hangup(tty);
> +	if (tty) {
> +		tty_vhangup(tty);
> +		tty_kref_put(tty);
> +	}
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(hvc_remove);

  reply	other threads:[~2010-03-20 21:05 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-19 15:13 [GIT PATCH] TTY fixes for 2.6.34-git Greg KH
2010-03-19 15:18 ` [PATCH 1/7] Revert "tty: Add a new VT mode which is like VT_PROCESS but doesn't require a VT_RELDISP ioctl call" Greg Kroah-Hartman
2010-03-19 15:18 ` [PATCH 2/7] tty: Take a 256 byte padding into account when buffering below sub-page units Greg Kroah-Hartman
2010-03-19 15:18 ` [PATCH 3/7] uartlite: Fix build on sparc Greg Kroah-Hartman
2010-03-19 16:15   ` Grant Likely
2010-03-19 16:26     ` Grant Likely
2010-03-26 14:31   ` Michal Simek
2010-03-19 15:18 ` [PATCH 4/7] hvc_console: Fix race between hvc_close and hvc_remove Greg Kroah-Hartman
2010-03-19 15:18   ` Greg Kroah-Hartman
2010-03-20 21:04   ` Benjamin Herrenschmidt [this message]
2010-03-20 21:04     ` Benjamin Herrenschmidt
2010-03-21  4:37     ` Amit Shah
2010-03-21  4:37       ` Amit Shah
2010-03-24 12:19       ` Amit Shah
2010-03-24 12:19         ` Amit Shah
2010-03-25 23:30         ` Anton Blanchard
2010-03-25 23:30           ` Anton Blanchard
2010-03-26  2:01           ` Amit Shah
2010-03-26  2:01             ` Amit Shah
2010-03-26  9:13         ` Sachin Sant
2010-03-26  9:13           ` Sachin Sant
2010-03-26  9:58           ` Amit Shah
2010-03-26  9:58             ` Amit Shah
2010-03-26 10:54             ` Stephen Rothwell
2010-03-26 10:54               ` Stephen Rothwell
2010-03-26 11:42             ` Sachin Sant
2010-03-26 11:42               ` Sachin Sant
2010-03-26 11:52               ` Alan Cox
2010-03-26 11:52                 ` Alan Cox
2010-03-26 12:49                 ` Amit Shah
2010-03-26 12:49                   ` Amit Shah
2010-03-26 12:43               ` Amit Shah
2010-03-26 12:43                 ` Amit Shah
2010-04-06 11:42                 ` Anton Blanchard
2010-04-06 11:42                   ` Anton Blanchard
2010-04-06 12:09                   ` Amit Shah
2010-04-06 12:09                     ` Amit Shah
2010-04-06 12:27                   ` Sachin Sant
2010-04-06 12:27                     ` Sachin Sant
2010-04-06 12:32                   ` Alan Cox
2010-04-06 12:32                     ` Alan Cox
2010-04-08  0:26                   ` Rusty Russell
2010-04-08  0:26                     ` Rusty Russell
2010-03-24 10:45     ` Benjamin Herrenschmidt
2010-03-24 10:45       ` Benjamin Herrenschmidt
2010-03-24 10:57       ` Amit Shah
2010-03-24 10:57         ` Amit Shah
2010-03-24 11:37     ` Alan Cox
2010-03-24 11:37       ` Alan Cox
2010-03-24 15:05       ` Amit Shah
2010-03-24 15:05         ` Amit Shah
2010-03-19 15:18 ` [PATCH 5/7] tty_buffer: Fix distinct type warning Greg Kroah-Hartman
2010-03-19 15:18 ` [PATCH 6/7] tty: cpm_uart: use resource_size() Greg Kroah-Hartman
2010-03-19 15:18 ` [PATCH 7/7] tty_port,usb-console: Fix usb serial console open/close regression Greg Kroah-Hartman

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=1269119079.8599.65.camel@pasglop \
    --to=benh@kernel.crashing.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=amit.shah@redhat.com \
    --cc=gregkh@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@ozlabs.org \
    --cc=rusty@rustcorp.com.au \
    --cc=torvalds@linux-foundation.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.