Skip to contentSkip to conversation

ocfs2/dlm: Do not purge lockres that is queued for assert master

PATCH New Xue jiufei 1 participant 1 message May 22, 2014 OCFS2

lore
Share & tools
lore

Xue jiufei

author
#0 lore raw

PATCH 1/1 ocfs2/dlm: Do not purge lockres that is queued for assert master

When workqueue is delayed, it may occured that a lockres is purged while it is still queued for master assert. it may trigger BUS() as follows.

N1 N2
dlm_get_lockres()
->dlm_do_master_requery
is the master of lockres, so queue assert_master work

dlm_thread() start running and purge the lockres

dlm_assert_master_worker() send assert master message to other nodes
receiving the assert_master
message, set master to N2

dlmlock_remote() send
create_lock message to N2,
but receive DLM_IVLOCKID,
if it is RECOVERY lockres,
it triggers the BUG().

Another BUG() is triggered when N3 become the new master and send assert_master to N1, N1 will trigger the BUG() because owner doesn't match. So we should not purge lockres when it is queued for assert master.

---
 fs/ocfs2/dlm/dlmcommon.h   |  4 ++++
 fs/ocfs2/dlm/dlmmaster.c   | 43 ++++++++++++++++++++++++++++++++++++++++++-
 fs/ocfs2/dlm/dlmrecovery.c |  3 ++-
 fs/ocfs2/dlm/dlmthread.c   | 11 +++++++----
 4 files changed, 55 insertions(+), 6 deletions(-)
fs/ocfs2/dlm/dlmcommon.h +4 -0
index e051776..fa2bd21 100644
@@ -332,6 +332,7 @@ struct dlm_lock_resource
 	u16 state;
 	char lvb[DLM_LVB_LEN];
 	unsigned int inflight_locks;
+	unsigned int inflight_assert_workers;
 	unsigned long refmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 };
 
@@ -911,6 +912,9 @@ void dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
 void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
 				   struct dlm_lock_resource *res);
 
+void __dlm_lockres_grab_inflight_worker(struct dlm_ctxt *dlm,
+		struct dlm_lock_resource *res);
+
 void dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
 void dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
 void __dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
fs/ocfs2/dlm/dlmmaster.c +42 -1

67 lines not on this page · raw message

fs/ocfs2/dlm/dlmrecovery.c +2 -1
index 5de0194..45067fa 100644
@@ -1708,7 +1708,8 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
 				mlog_errno(-ENOMEM);
 				/* retry!? */
 				BUG();
-			}
+			} else
+				__dlm_lockres_grab_inflight_worker(dlm, res);
 		} else /* put.. incase we are not the master */
 			dlm_lockres_put(res);
 		spin_unlock(&res->spinlock);
fs/ocfs2/dlm/dlmthread.c +7 -4
index 9db869d..f68bd4e 100644
@@ -259,11 +259,14 @@ static void dlm_run_purge_list(struct dlm_ctxt *dlm,
 		 * refs on it. */
 		unused = __dlm_lockres_unused(lockres);
 		if (!unused ||
-		    (lockres->state & DLM_LOCK_RES_MIGRATING)) {
+		    (lockres->state & DLM_LOCK_RES_MIGRATING) ||
+		    (lockres->inflight_assert_workers != 0)) {
 			mlog(0, "%s: res %.*s is in use or being remastered, "
-			     "used %d, state %d\n", dlm->name,
-			     lockres->lockname.len, lockres->lockname.name,
-			     !unused, lockres->state);
+			     "used %d, state %d, assert master workers %u\n",
+			     dlm->name, lockres->lockname.len,
+			     lockres->lockname.name,
+			     !unused, lockres->state,
+			     lockres->inflight_assert_workers);
 			list_move_tail(&dlm->purge_list, &lockres->purge);
 			spin_unlock(&lockres->spinlock);
 			continue;
Signature · 1 line
1.8.3.4