From: Ryan Arnold <rsa@us.ibm.com>

This patch prevents execution of hvc_write() and hvc_hangup() after the tty
layer has executed a final hvc_close() against a device.  This patch
provides a better method than was previously used.  tty->driver_data is no
longer invalidated so we'll no longer get oopses when the tty layer allows
late hangup() and write() operations.

- Removed silly tty->driver_data = NULL; from hvc_close which prevents
  possible oops in hvc_write() and hvc_hangup() due to improperly acting
  ldisc close ordering.

- Added hp->count <= 0 check to hvc_write() and hvc_hangup() to prevent
  execution of these function after hvc_close() has been invoked by the tty
  layer.  Same tty ldisc issues as above are the reason.

- Added some comments to clarify the situation.

- Awaiting a forth coming patch from Alan Cox which should clean up the
  close ordering and prevent the late hangup and write ops from happening.

Signed-off-by: Ryan S. Arnold <rsa@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/char/hvc_console.c |   27 +++++++++++++++++++--------
 1 files changed, 19 insertions(+), 8 deletions(-)

diff -puN drivers/char/hvc_console.c~hvc_console-fix-to-prevent-oops-and-late-hangup-and-write drivers/char/hvc_console.c
--- 25/drivers/char/hvc_console.c~hvc_console-fix-to-prevent-oops-and-late-hangup-and-write	2004-10-04 20:21:53.175988840 -0700
+++ 25-akpm/drivers/char/hvc_console.c	2004-10-04 20:21:53.180988080 -0700
@@ -221,6 +221,7 @@ static int hvc_open(struct tty_struct *t
 		spin_unlock_irqrestore(&hp->lock, flags);
 		tty->driver_data = NULL;
 		kobject_put(kobjp);
+		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
 	}
 	/* Force wakeup of the polling thread */
 	hvc_kick();
@@ -240,7 +241,7 @@ static void hvc_close(struct tty_struct 
 
 	/*
 	 * No driver_data means that this close was issued after a failed
-	 * hvcs_open by the tty layer's release_dev() function and we can just
+	 * hvc_open by the tty layer's release_dev() function and we can just
 	 * exit cleanly because the kobject reference wasn't made.
 	 */
 	if (!tty->driver_data)
@@ -266,13 +267,6 @@ static void hvc_close(struct tty_struct 
 		 */
 		tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
 
-		/*
-		 * Since the line disc doesn't block writes during tty close
-		 * operations we'll set driver_data to NULL and then make sure
-		 * to check tty->driver_data for NULL in hvc_write().
-		 */
-		tty->driver_data = NULL;
-
 		if (irq != NO_IRQ)
 			free_irq(irq, hp);
 
@@ -294,7 +288,21 @@ static void hvc_hangup(struct tty_struct
 	int temp_open_count;
 	struct kobject *kobjp;
 
+	if (!hp)
+		return;
+
 	spin_lock_irqsave(&hp->lock, flags);
+
+	/*
+	 * The N_TTY line discipline has problems such that in a close vs
+	 * open->hangup case this can be called after the final close so prevent
+	 * that from happening for now.
+	 */
+	if (hp->count <= 0) {
+		spin_unlock_irqrestore(&hp->lock, flags);
+		return;
+	}
+
 	kobjp = &hp->kobj;
 	temp_open_count = hp->count;
 	hp->count = 0;
@@ -428,6 +436,9 @@ static int hvc_write(struct tty_struct *
 	if (!hp)
 		return -EPIPE;
 
+	if (hp->count <= 0)
+		return -EIO;
+
 	if (from_user)
 		written = __hvc_write_user(hp, buf, count);
 	else
_