• Junxiao Bi's avatar
    ocfs2: dlm: fix recovery hung · ded2cf71
    Junxiao Bi authored
    There is a race window in dlm_do_recovery() between dlm_remaster_locks()
    and dlm_reset_recovery() when the recovery master nearly finish the
    recovery process for a dead node.  After the master sends FINALIZE_RECO
    message in dlm_remaster_locks(), another node may become the recovery
    master for another dead node, and then send the BEGIN_RECO message to
    all the nodes included the old master, in the handler of this message
    dlm_begin_reco_handler() of old master, dlm->reco.dead_node and
    dlm->reco.new_master will be set to the second dead node and the new
    master, then in dlm_reset_recovery(), these two variables will be reset
    to default value.  This will cause new recovery master can not finish
    the recovery process and hung, at last the whole cluster will hung for
    recovery.
    
    old recovery master:                                 new recovery master:
    dlm_remaster_locks()
                                                      become recovery master for
                                                      another dead node.
                                                      dlm_send_begin_reco_message()
    dlm_begin_reco_handler()
    {
     if (dlm->reco.state & DLM_RECO_STATE_FINALIZE) {
      return -EAGAIN;
     }
     dlm_set_reco_master(dlm, br->node_idx);
     dlm_set_reco_dead_node(dlm, br->dead_node);
    }
    dlm_reset_recovery()
    {
     dlm_set_reco_dead_node(dlm, O2NM_INVALID_NODE_NUM);
     dlm_set_reco_master(dlm, O2NM_INVALID_NODE_NUM);
    }
                                                      will hang in dlm_remaster_locks() for
                                                      request dlm locks info
    
    Before send FINALIZE_RECO message, recovery master should set
    DLM_RECO_STATE_FINALIZE for itself and clear it after the recovery done,
    this can break the race windows as the BEGIN_RECO messages will not be
    handled before DLM_RECO_STATE_FINALIZE flag is cleared.
    
    A similar race may happen between new recovery master and normal node
    which is in dlm_finalize_reco_handler(), also fix it.
    Signed-off-by: default avatarJunxiao Bi <junxiao.bi@oracle.com>
    Reviewed-by: default avatarSrinivas Eeda <srinivas.eeda@oracle.com>
    Reviewed-by: default avatarWengang Wang <wen.gang.wang@oracle.com>
    Cc: Joel Becker <jlbec@evilplan.org>
    Cc: Mark Fasheh <mfasheh@suse.com>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ded2cf71
dlmrecovery.c 85.9 KB