aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunxiao Bi <junxiao.bi@oracle.com>2014-04-03 17:46:51 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-06 10:55:32 -0400
commita093bceda6927de680e1c16793c5dfc4df3d236f (patch)
tree4a6da8b621c6e8bf5dc23ecd617a5c975b6dbc8b
parent261985c4398c6658e057842ba6c960c74f796d00 (diff)
ocfs2: dlm: fix recovery hung
commit ded2cf71419b9353060e633b59e446c42a6a2a09 upstream. 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: Junxiao Bi <junxiao.bi@oracle.com> Reviewed-by: Srinivas Eeda <srinivas.eeda@oracle.com> Reviewed-by: Wengang Wang <wen.gang.wang@oracle.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Mark Fasheh <mfasheh@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 5abbc73d1a77..9bd981cd3142 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -540,7 +540,10 @@ master_here:
540 /* success! see if any other nodes need recovery */ 540 /* success! see if any other nodes need recovery */
541 mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n", 541 mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n",
542 dlm->name, dlm->reco.dead_node, dlm->node_num); 542 dlm->name, dlm->reco.dead_node, dlm->node_num);
543 dlm_reset_recovery(dlm); 543 spin_lock(&dlm->spinlock);
544 __dlm_reset_recovery(dlm);
545 dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
546 spin_unlock(&dlm->spinlock);
544 } 547 }
545 dlm_end_recovery(dlm); 548 dlm_end_recovery(dlm);
546 549
@@ -698,6 +701,14 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
698 if (all_nodes_done) { 701 if (all_nodes_done) {
699 int ret; 702 int ret;
700 703
704 /* Set this flag on recovery master to avoid
705 * a new recovery for another dead node start
706 * before the recovery is not done. That may
707 * cause recovery hung.*/
708 spin_lock(&dlm->spinlock);
709 dlm->reco.state |= DLM_RECO_STATE_FINALIZE;
710 spin_unlock(&dlm->spinlock);
711
701 /* all nodes are now in DLM_RECO_NODE_DATA_DONE state 712 /* all nodes are now in DLM_RECO_NODE_DATA_DONE state
702 * just send a finalize message to everyone and 713 * just send a finalize message to everyone and
703 * clean up */ 714 * clean up */
@@ -2869,8 +2880,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
2869 BUG(); 2880 BUG();
2870 } 2881 }
2871 dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE; 2882 dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
2883 __dlm_reset_recovery(dlm);
2872 spin_unlock(&dlm->spinlock); 2884 spin_unlock(&dlm->spinlock);
2873 dlm_reset_recovery(dlm);
2874 dlm_kick_recovery_thread(dlm); 2885 dlm_kick_recovery_thread(dlm);
2875 break; 2886 break;
2876 default: 2887 default: