ocfs2/dlm: check dlm_state under spinlock
PATCH 1/1 ocfs2/dlm: check dlm_state under spinlock
We should check dlm->dlm_state under dlm->spinlock though maybe in this case it doesn't hurt.
--- fs/ocfs2/dlm/dlmdomain.c | 13 ++++++------- 1 files changed, 6 insertions(+), 7 deletions(-)
fs/ocfs2/dlm/dlmdomain.c +6 -7
@@ -796,7 +796,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,spin_lock (&dlm_domain_lock); dlm =__dlm_lookup_domain_full (query->domain, query->name_len);if (!dlm) - goto unlock_respond; + goto unlock_domain_respond;/* * There is a small window where the joining node may not see the
@@ -811,7 +811,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,"have node %u in its nodemap\n" , query->node_idx, nodenum); packet.code =JOIN_DISALLOW ; - goto unlock_respond; + goto unlock_domain_respond; } } nodenum++;
@@ -821,9 +821,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,* to be put in someone's domain map. * Also, explicitly disallow joining at certain troublesome * times (ie. during recovery). */ -if (dlm && dlm->dlm_state !=DLM_CTXT_LEAVING ) { +spin_lock (&dlm->spinlock); +if (dlm->dlm_state !=DLM_CTXT_LEAVING ) {int bit = query->node_idx; -spin_lock (&dlm->spinlock);if (dlm->dlm_state ==DLM_CTXT_NEW && dlm->joining_node ==DLM_LOCK_RES_OWNER_UNKNOWN ) {
@@ -869,10 +869,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,__dlm_set_joining_node (dlm, query->node_idx); } } - -spin_unlock (&dlm->spinlock); } -unlock_respond: +spin_unlock (&dlm->spinlock); +unlock_domain_respond:spin_unlock (&dlm_domain_lock); respond:
Signature · 1 line
1.6.6.1
PATCH 1/1 ocfs2/dlm: check dlm_state under spinlock
The lock order in this code causes dead lock, not caused by your patch. The lock order in dlm_query_join_handler is
dlm_domain_lock
->dlm->spinlock
dead locks with ..
dlm_lockres_put calls dlm_lockres_release while holding dlm->spinlock which calls dlm_put which gets dlm_domain_lock. So the spin lock order here isdlm->spinlock
-> dlm_domain_lock
Quoted 56 lines · Wengang Wang
We should check
dlm->dlm_stateunderdlm->spinlockthough maybe in this case it doesn't hurt.Signed-off-by Wengang Wang <[email protected]>--- fs/ocfs2/dlm/dlmdomain.c | 13 ++++++------- 1 files changed, 6 insertions(+), 7 deletions(-)fs/ocfs2/dlm/dlmdomain.c +6
-7@@ -796,7 +796,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,spin_lock (&dlm_domain_lock); dlm =__dlm_lookup_domain_full (query->domain, query->name_len);if (!dlm) - goto unlock_respond; + goto unlock_domain_respond;/* * There is a small window where the joining node may not see the @@ -811,7 +811,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,"have node %u in its nodemap\n" , query->node_idx, nodenum); packet.code =JOIN_DISALLOW ; - goto unlock_respond; + goto unlock_domain_respond; } } nodenum++;@@ -821,9 +821,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,* to be put in someone's domain map. * Also, explicitly disallow joining at certain troublesome * times (ie. during recovery). */ -if (dlm && dlm->dlm_state !=DLM_CTXT_LEAVING ) { +spin_lock (&dlm->spinlock); +if (dlm->dlm_state !=DLM_CTXT_LEAVING ) {int bit = query->node_idx; -spin_lock (&dlm->spinlock);if (dlm->dlm_state ==DLM_CTXT_NEW && dlm->joining_node ==DLM_LOCK_RES_OWNER_UNKNOWN ) {@@ -869,10 +869,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,__dlm_set_joining_node (dlm, query->node_idx); } } - -spin_unlock (&dlm->spinlock); } -unlock_respond: +spin_unlock (&dlm->spinlock); +unlock_domain_respond:spin_unlock (&dlm_domain_lock); respond:
PATCH 1/1 ocfs2/dlm: check dlm_state under spinlock
Thanks for review :)
The second path has problem. I think the correct order should be dlm_domain_lock and then dlm->spinlock.
I will try to fix it.
regards,
wengang.
Quoted 68 lines · Srinivas Eeda
The lock order in this code causes dead lock, not caused by your patch. The lock order in
dlm_query_join_handleris
dlm_domain_lock
->dlm->spinlockdead locks with ..
dlm_lockres_putcallsdlm_lockres_releasewhile holdingdlm->spinlockwhich callsdlm_putwhich getsdlm_domain_lock. So the spin lock order here isdlm->spinlock
->dlm_domain_lockQuoted 52 lines · Wengang Wang
We should check
dlm->dlm_stateunderdlm->spinlockthough maybe in this case it doesn't hurt.Signed-off-by Wengang Wang <[email protected]>---
fs/ocfs2/dlm/dlmdomain.c| 13 ++++++-------1 files changed, 6 insertions(+), 7 deletions(-)fs/ocfs2/dlm/dlmdomain.c +6
-7@@ -796,7 +796,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,spin_lock (&dlm_domain_lock); dlm =__dlm_lookup_domain_full (query->domain, query->name_len);if (!dlm) - goto unlock_respond; + goto unlock_domain_respond;/* * There is a small window where the joining node may not see the @@ -811,7 +811,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,"have node %u in its nodemap\n" , query->node_idx, nodenum); packet.code =JOIN_DISALLOW ; - goto unlock_respond; + goto unlock_domain_respond; } } nodenum++;@@ -821,9 +821,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,* to be put in someone's domain map. * Also, explicitly disallow joining at certain troublesome * times (ie. during recovery). */ -if (dlm && dlm->dlm_state !=DLM_CTXT_LEAVING ) { +spin_lock (&dlm->spinlock); +if (dlm->dlm_state !=DLM_CTXT_LEAVING ) {int bit = query->node_idx; -spin_lock (&dlm->spinlock);if (dlm->dlm_state ==DLM_CTXT_NEW && dlm->joining_node ==DLM_LOCK_RES_OWNER_UNKNOWN ) {@@ -869,10 +869,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,__dlm_set_joining_node (dlm, query->node_idx); } } - -spin_unlock (&dlm->spinlock); } -unlock_respond: +spin_unlock (&dlm->spinlock); +unlock_domain_respond:spin_unlock (&dlm_domain_lock);respond:
Sunil Mushran
NAKPATCH 1/1 ocfs2/dlm: check dlm_state under spinlock
In reply to Wengang WangQuoted 3 lines · Wengang Wang
We should check
dlm->dlm_stateunderdlm->spinlockthough maybe in this case it doesn't hurt.
NAK.
dlm->dlm_state is protected by dlm_domain_lock which is held at that time.
/* NOTE: Next three are protected by dlm_domain_lock */
struct kref dlm_refs;
enum dlm_ctxt_state dlm_state;
unsigned int num_joins;PATCH 1/1 ocfs2/dlm: check dlm_state under spinlock
Quoted 4 lines · Sunil Mushran
Quoted 2 lines · Wengang Wang
We should check
dlm->dlm_stateunderdlm->spinlockthough maybe in this case it doesn't hurt.
Quoted 8 lines
NAK.
dlm->dlm_stateis protected bydlm_domain_lockwhich is held at that time./* NOTE: Next three are protected by dlm_domain_lock */ struct kref dlm_refs; enum dlm_ctxt_state dlm_state; unsigned int num_joins;
Yes, that's ture. thanks.