• K
    serial: change retry logic to avoid concurrency · f702e62a
    Kirill Batuzov 提交于
    Whenever serial_xmit fails to transmit a byte it adds a watch that would
    call it again when the "line" becomes ready. This results in a retry
    chain:
      serial_xmit -> add_watch -> serial_xmit
    Each chain is able to transmit one character, and for every character
    passed to serial by the guest driver a new chain is spawned.
    
    The problem lays with the fact that a new chain is spawned even when
    there is one already waiting on the watch. So there can be several retry
    chains waiting concurrently on one "line". Every chain tries to transmit
    current character, so character order is not messed up. But also every
    chain increases retry counter (tsr_retry). If there are enough
    concurrent chains this counter will hit MAX_XMIT_RETRY value and
    the character will be dropped.
    
    To reproduce this bug you need to feed serial output to some program
    consuming it slowly enough. A python script from bug #1335444
    description is an example of such program.
    
    This commit changes retry logic in the following way to avoid
    concurrency: instead of spawning a new chain for each character being
    transmitted spawn only one and make it transmit characters until FIFO is
    empty.
    
    The change consists of two parts:
     - add a do {} while () loop in serial_xmit (diff is a bit erratic
       for this part, diff -w will show actual change),
     - do not call serial_xmit from serial_ioport_write if there is one
       waiting on the watch already.
    
    This should fix another issue causing bug #1335444.
    Signed-off-by: NKirill Batuzov <batuzovk@ispras.ru>
    Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
    f702e62a
serial.c 24.0 KB