NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/46780: tty TIOCSQSIZE can free clist buffers which drivers are still using for output
On 12 Aug, 2012, at 08:25 , Christos Zoulas wrote:
> | While I still think it is possible to do a _flush() entry point I
> | think it is going to take more driver-specific code then you have.
> | The alternative of deferring the free of a non-empty output buffer's
> | memory (the bookkeeping needn't be kept, just the ring buffer memory
> | allocation) until the driver indicates that the hardware/interrupt
> | is inactive by calling ndqb() or ndflush() is probably easier even
> | if it does require some checks to be added to the 'normal' code
> | path.
>
> Well, we could always wait for ndflush() but I will need to verify that
> this happens. We could also make the drivers voluntarily call a function
> to get the new pointers once they consume all they bytes from the old ones.
> Or we can make the ioctl fail with ebysy if the buffer is not empty.
I only know this because I've been working on that driver, but the
protocol most drivers seem to follow works like this:
- call ndqb() to get the number of bytes available in the clist. If
there are some, start the tx interrupt/DMA to send those bytes.
- when the above completes, call ndflush() to remove the bytes sent
from the clist.
When the driver calls ndqb() or ndflush(), or when the clist byte
count is zero, it should be quite safe to assume there is no tx output
in progress.
Given this I'm pretty sure this might work:
(1) Change all drivers which call ndqb() to copy the tp->t_outq.c_cf
pointer only after the ndqb() call (or, better, make ndqb() return
the pointer as well as the count, or something). This avoids a
potential race when changing what tp->t_outq.c_cf points to.
(2) When replacing the output queue memory, if the byte count in the clist
is non-zero save a reference to the old buffer memory (no need to keep the
bookkeeping, just the buffer itself) rather than freeing it.
(3) If the driver calls ndqb() check to see if an old buffer is present and,
if it is, free it (before returning information from the current clist,
as normal). If the driver is calling ndqb() it is safe to dump the old
memory.
(4) If the driver calls ndflush() when an old buffer is present, free the old
buffer and do not flush anything from the current buffer (i.e. ignore the
byte count). If the driver is calling ndflush() whatever output it was
doing has completed, so it is safe to free the old buffer, but if the old
buffer is present the byte count it is giving you must be from the
previous buffer and shouldn't be subtracted from the current clist.
(5) While most drivers use the ndqb()/ndflush(), there may be a single
character _get() routine as well (I'm doing this from memory since
I'm traveling and away from my sources). Any code which reads bytes
from the outq should similarly check for and free the old buffer.
If that's too much work, however, returning EBUSY when the output queue
has bytes in it should also be safe.
Dennis Ferguson
Home |
Main Index |
Thread Index |
Old Index