[Ocfs2-devel] [PATCH 1/1] Fix a potential piece of code that may induce kernel bug.
xiaowei.hu at oracle.com
xiaowei.hu at oracle.com
Mon Mar 7 21:32:07 PST 2011
From: XiaoweiHu <xiaowei.hu at oracle.com>
In function dlm_migrate_lockres, it calls dlm_add_migration_mle() before
the dlm_add_migration_mle() ,this dlm_add_migration_mle() should make sure
the lockres is not dirty ,if it is dirty wait until it becomes undirty,
and then mark this lockres as migrating. but the dlm_add_migration_mle()
doesn't check this dirty flag , it just adds the mle with migrate type,
this could have problem, if the migrate target dean at this point then
another node becames the recovery master, current node will migrate this
lockres to the recovery master ,no matter if it is in the dirty list.
So this makes the lockres in the dirty lists but this owner becomes the
recovery master, then panic.
Signed-off-by: XiaoweiHu <xiaowei.hu at oracle.com>
Reviewed-by: WengangWang <wen.gang.wang at oracle.com>
---
fs/ocfs2/dlm/dlmmaster.c | 62 +++++++++++++++++++++++-----------------------
1 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 59f0f6b..bdb2323 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -2402,6 +2402,16 @@ leave:
return ret;
}
+static int dlm_lockres_is_dirty(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res)
+{
+ int ret;
+ spin_lock(&res->spinlock);
+ ret = !!(res->state & DLM_LOCK_RES_DIRTY);
+ spin_unlock(&res->spinlock);
+ return ret;
+}
+
/*
* DLM_MIGRATE_LOCKRES
*/
@@ -2463,6 +2473,20 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
}
ret = 0;
+ /* moved this out from dlm_mark_lockres_migrating,
+ * to pervent the local recovery handler, migrate a dirty lockres.*/
+
+ /* now flush all the pending asts */
+ dlm_kick_thread(dlm, res);
+ /* before waiting on DIRTY, block processes which may
+ * try to dirty the lockres before MIGRATING is set */
+ spin_lock(&res->spinlock);
+ BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY);
+ res->state |= DLM_LOCK_RES_BLOCK_DIRTY;
+ spin_unlock(&res->spinlock);
+ /* now wait on any pending asts and the DIRTY state */
+ wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
+
/*
* find a node to migrate the lockres to
*/
@@ -2521,6 +2545,13 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
}
fail:
+ /* now no matter if it fails or not the block dirty state needs to
+ * be cleared.*/
+ spin_lock(&res->spinlock);
+ BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
+ res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
+ spin_unlock(&res->spinlock);
+
if (oldmle) {
/* master is known, detach if not already detached */
dlm_mle_detach_hb_events(dlm, oldmle);
@@ -2748,16 +2779,6 @@ static int dlm_migration_can_proceed(struct dlm_ctxt *dlm,
return can_proceed;
}
-static int dlm_lockres_is_dirty(struct dlm_ctxt *dlm,
- struct dlm_lock_resource *res)
-{
- int ret;
- spin_lock(&res->spinlock);
- ret = !!(res->state & DLM_LOCK_RES_DIRTY);
- spin_unlock(&res->spinlock);
- return ret;
-}
-
static int dlm_mark_lockres_migrating(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res,
@@ -2778,16 +2799,6 @@ static int dlm_mark_lockres_migrating(struct dlm_ctxt *dlm,
__dlm_lockres_reserve_ast(res);
spin_unlock(&res->spinlock);
- /* now flush all the pending asts */
- dlm_kick_thread(dlm, res);
- /* before waiting on DIRTY, block processes which may
- * try to dirty the lockres before MIGRATING is set */
- spin_lock(&res->spinlock);
- BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY);
- res->state |= DLM_LOCK_RES_BLOCK_DIRTY;
- spin_unlock(&res->spinlock);
- /* now wait on any pending asts and the DIRTY state */
- wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
dlm_lockres_release_ast(dlm, res);
mlog(0, "about to wait on migration_wq, dirty=%s\n",
@@ -2823,17 +2834,6 @@ again:
}
spin_unlock(&dlm->spinlock);
- /*
- * if target is down, we need to clear DLM_LOCK_RES_BLOCK_DIRTY for
- * another try; otherwise, we are sure the MIGRATING state is there,
- * drop the unneded state which blocked threads trying to DIRTY
- */
- spin_lock(&res->spinlock);
- BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
- res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
- if (!ret)
- BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
- spin_unlock(&res->spinlock);
/*
* at this point:
--
1.7.0.4
More information about the Ocfs2-devel
mailing list