Bug in serial line hangup code ?

Peter Fox (fox@roestock.demon.co.uk)
Sun, 5 May 1996 13:45:11 GMT


I've continued my line monitoring program, and found the following
problem:

My program opens the line, and ignores HUP. info.count is 1.

ppp (for example) opens the line, does its stuff etc, info.count is 2.

ppp enables hangup, and on hangup closes the port. The serial driver
sets info.count to 0 on hangup, even though my program still has the
port open. As my program watches info.count to determine if another
process has the line is open, this is a bit of a problem.

Here are my patches to fix this, (and also add data transfer counters
to the async_struct, and allow ioctls on a line that has received
a hangup).

The fix involves doing not alot in the serial driver on hangup, but
wait for the port to be closed. If the process doesn't catch HUP,
then it will close the port just like before.

How about including this lot before 2.0 ?

Peter.

----------------------------
diff -P -r -u -X diffexcl linux.1.3.97/drivers/char/serial.c linux.1.3.97.pf/drivers/char/serial.c
--- linux.1.3.97/drivers/char/serial.c Tue Apr 30 21:55:44 1996
+++ linux.1.3.97.pf/drivers/char/serial.c Sun May 5 13:39:34 1996
@@ -396,6 +396,7 @@

do {
ch = serial_inp(info, UART_RX);
+ info->rx_char_count++;
if (*status & info->ignore_status_mask) {
if (++ignored > 100)
break;
@@ -433,6 +434,7 @@

if (info->x_char) {
serial_outp(info, UART_TX, info->x_char);
+ info->tx_char_count++;
info->x_char = 0;
if (intr_done)
*intr_done = 0;
@@ -448,6 +450,7 @@
count = info->xmit_fifo_size;
do {
serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
+ info->tx_char_count++;
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
if (--info->xmit_cnt <= 0)
break;
@@ -1002,6 +1005,11 @@
(void) serial_inp(info, UART_MSR);

/*
+ * Initialise the byte counters
+ */
+ info->rx_char_count = 0;
+ info->tx_char_count = 0;
+ /*
* Now, initialize the UART
*/
serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
@@ -1903,6 +1911,7 @@
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
(cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMGET) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -2110,12 +2119,14 @@

save_flags(flags); cli();

+#ifdef NOTACHANCE
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
+#endif

#ifdef SERIAL_DEBUG_OPEN
printk("rs_close ttys%d, count = %d\n", info->line, info->count);
@@ -2217,11 +2228,13 @@
return;

rs_flush_buffer(tty);
+#ifdef NOTACHANCE /* Close will do all this (when last process closes the line) */
shutdown(info);
info->event = 0;
info->count = 0;
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
info->tty = 0;
+#endif
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
wake_up_interruptible(&info->open_wait);
}

diff -P -r -u -X diffexcl linux.1.3.97/drivers/char/tty_io.c linux.1.3.97.pf/drivers/char/tty_io.c
--- linux.1.3.97/drivers/char/tty_io.c Sat Apr 27 00:02:00 1996
+++ linux.1.3.97.pf/drivers/char/tty_io.c Tue Apr 30 21:58:25 1996
@@ -358,7 +358,8 @@
hung_up_tty_write,
NULL, /* hung_up_tty_readdir */
hung_up_tty_select,
- hung_up_tty_ioctl,
+ tty_ioctl, /* Why shouldn't we do IOCTLs on hung up tty ? */
+ /* hung_up_tty_ioctl, */
NULL, /* hung_up_tty_mmap */
NULL, /* hung_up_tty_open */
tty_release, /* hung_up_tty_release */
diff -P -r -u -X diffexcl linux.1.3.97/include/linux/serial.h linux.1.3.97.pf/include/linux/serial.h
--- linux.1.3.97/include/linux/serial.h Thu Mar 21 08:05:06 1996
+++ linux.1.3.97.pf/include/linux/serial.h Tue Apr 30 22:02:20 1996
@@ -170,6 +170,8 @@
struct async_icount icount; /* kernel counters for the 4 input interrupts */
struct async_struct *next_port; /* For the linked list */
struct async_struct *prev_port;
+ unsigned long rx_char_count; /* Total no of chars received */
+ unsigned long tx_char_count; /* Total no of chars transmitted */
};

#define SERIAL_MAGIC 0x5301