• M
    block/io: Delay decrementing the quiesce_counter · 5cb2737e
    Max Reitz 提交于
    When ending a drained section, bdrv_do_drained_end() currently first
    decrements the quiesce_counter, and only then actually ends the drain.
    
    The bdrv_drain_invoke(bs, false) call may cause graph changes.  Say the
    graph change involves replacing an existing BB's ("blk") BDS
    (blk_bs(blk)) by @bs.  Let us introducing the following values:
    - bs_oqc = old_quiesce_counter
      (so bs->quiesce_counter == bs_oqc - 1)
    - obs_qc = blk_bs(blk)->quiesce_counter (before bdrv_drain_invoke())
    
    Let us assume there is no blk_pread_unthrottled() involved, so
    blk->quiesce_counter == obs_qc (before bdrv_drain_invoke()).
    
    Now replacing blk_bs(blk) by @bs will reduce blk->quiesce_counter by
    obs_qc (making it 0) and increase it by bs_oqc-1 (making it bs_oqc-1).
    
    bdrv_drain_invoke() returns and we invoke bdrv_parent_drained_end().
    This will decrement blk->quiesce_counter by one, so it would be -1 --
    were there not an assertion against that in blk_root_drained_end().
    
    We therefore have to keep the quiesce_counter up at least until
    bdrv_drain_invoke() returns, so that bdrv_parent_drained_end() does the
    right thing for the parents @bs got during bdrv_drain_invoke().
    
    But let us delay it even further, namely until bdrv_parent_drained_end()
    returns, because then it mirrors bdrv_do_drained_begin(): There, we
    first increment the quiesce_counter, then begin draining the parents,
    and then call bdrv_drain_invoke().  It makes sense to let
    bdrv_do_drained_end() unravel this exactly in reverse.
    Signed-off-by: NMax Reitz <mreitz@redhat.com>
    Signed-off-by: NKevin Wolf <kwolf@redhat.com>
    5cb2737e
io.c 95.5 KB