NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/46780: tty TIOCSQSIZE can free clist buffers which drivers are still using for output
>Number: 46780
>Category: kern
>Synopsis: tty TIOCSQSIZE can free clist buffers which drivers are still
>using for output
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Aug 07 17:15:00 +0000 2012
>Originator: Dennis Ferguson
>Release: 6.99.10
>Organization:
>Environment:
NetBSD ts1.to.mistimed.ca 6.99.10 NetBSD 6.99.10 (GENERIC) #0: Tue Jul 31
13:49:09 EDT 2012
dennis%ts1.to.mistimed.ca@localhost:/usr/obj/sys/arch/amd64/compile/GENERIC
amd64
>Description:
It is common for serial device drivers to cache a pointer into the tty clist
buffer along with a character count in their private softc structure for use in
the hardware transmit interrupt routine. Here is a typical example from
sys/dev/ic/com.c, in comstart():
{
u_char *tba;
int tbc;
tba = tp->t_outq.c_cf;
tbc = ndqb(&tp->t_outq, 0);
mutex_spin_enter(&sc->sc_lock);
sc->sc_tba = tba;
sc->sc_tbc = tbc;
}
Many other drivers have similar code.
The tty TIOCSQSIZE ioctl() allows the size of this clist buffer to be changed.
It does this, in sys/kern/tty.c, by calling tty_set_qsize(), which ultimately
kmem_zalloc()'s a buffer of the requested new size, points the tty outq at the
new buffer and then kmem_free()'s the old buffer.
The problem with this seems to be that if there is data present in old buffer
when it is freed it will often be the case that the device driver will still
have cached a pointer into the old buffer and will continue to transmit data
from the now-free buffer until it exhausts the character count. In addition,
when the operation does complete, drivers seem to signal that the characters
have now been consumed by calling ndflush() with a character count computed by
pointer math which is now going to be a bit off.
>How-To-Repeat:
Do an output-buffer-sized write() to a (slower-is-better) serial port, then
immediately make a TIOCSQSIZE call to change the buffer.
>Fix:
I don't think this can be fixed in the serial device drivers, they have good
reasons to work the way they do.
I think what TIOCSQSIZE does with the input clists is okay, only the output has
a problem. An approach to fixing this might be to wait until the character
count in the old output clist goes to zero before swapping in the new one.
Home |
Main Index |
Thread Index |
Old Index