aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/dlm
diff options
context:
space:
mode:
authorJoseph Qi <joseph.qi@huawei.com>2015-09-22 17:59:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-22 18:09:53 -0400
commit012572d4fc2e4ddd5c8ec8614d51414ec6cae02a (patch)
treece5b9dc95ea8f3e9ea4a84d6b87cce8d0777e94b /fs/ocfs2/dlm
parent7a07b503bf249986a1eeef0351d66cac0d8bf721 (diff)
ocfs2/dlm: fix deadlock when dispatch assert master
The order of the following three spinlocks should be: dlm_domain_lock < dlm_ctxt->spinlock < dlm_lock_resource->spinlock But dlm_dispatch_assert_master() is called while holding dlm_ctxt->spinlock and dlm_lock_resource->spinlock, and then it calls dlm_grab() which will take dlm_domain_lock. Once another thread (for example, dlm_query_join_handler) has already taken dlm_domain_lock, and tries to take dlm_ctxt->spinlock deadlock happens. Signed-off-by: Joseph Qi <joseph.qi@huawei.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Mark Fasheh <mfasheh@suse.com> Cc: "Junxiao Bi" <junxiao.bi@oracle.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ocfs2/dlm')
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c9
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c8
2 files changed, 12 insertions, 5 deletions
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 46b8b2bbc95a..ee5aa4daaea0 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -1439,6 +1439,7 @@ int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data,
1439 int found, ret; 1439 int found, ret;
1440 int set_maybe; 1440 int set_maybe;
1441 int dispatch_assert = 0; 1441 int dispatch_assert = 0;
1442 int dispatched = 0;
1442 1443
1443 if (!dlm_grab(dlm)) 1444 if (!dlm_grab(dlm))
1444 return DLM_MASTER_RESP_NO; 1445 return DLM_MASTER_RESP_NO;
@@ -1658,15 +1659,18 @@ send_response:
1658 mlog(ML_ERROR, "failed to dispatch assert master work\n"); 1659 mlog(ML_ERROR, "failed to dispatch assert master work\n");
1659 response = DLM_MASTER_RESP_ERROR; 1660 response = DLM_MASTER_RESP_ERROR;
1660 dlm_lockres_put(res); 1661 dlm_lockres_put(res);
1661 } else 1662 } else {
1663 dispatched = 1;
1662 __dlm_lockres_grab_inflight_worker(dlm, res); 1664 __dlm_lockres_grab_inflight_worker(dlm, res);
1665 }
1663 spin_unlock(&res->spinlock); 1666 spin_unlock(&res->spinlock);
1664 } else { 1667 } else {
1665 if (res) 1668 if (res)
1666 dlm_lockres_put(res); 1669 dlm_lockres_put(res);
1667 } 1670 }
1668 1671
1669 dlm_put(dlm); 1672 if (!dispatched)
1673 dlm_put(dlm);
1670 return response; 1674 return response;
1671} 1675}
1672 1676
@@ -2090,7 +2094,6 @@ int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
2090 2094
2091 2095
2092 /* queue up work for dlm_assert_master_worker */ 2096 /* queue up work for dlm_assert_master_worker */
2093 dlm_grab(dlm); /* get an extra ref for the work item */
2094 dlm_init_work_item(dlm, item, dlm_assert_master_worker, NULL); 2097 dlm_init_work_item(dlm, item, dlm_assert_master_worker, NULL);
2095 item->u.am.lockres = res; /* already have a ref */ 2098 item->u.am.lockres = res; /* already have a ref */
2096 /* can optionally ignore node numbers higher than this node */ 2099 /* can optionally ignore node numbers higher than this node */
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index ce12e0b1a31f..3d90ad7ff91f 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1694,6 +1694,7 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
1694 unsigned int hash; 1694 unsigned int hash;
1695 int master = DLM_LOCK_RES_OWNER_UNKNOWN; 1695 int master = DLM_LOCK_RES_OWNER_UNKNOWN;
1696 u32 flags = DLM_ASSERT_MASTER_REQUERY; 1696 u32 flags = DLM_ASSERT_MASTER_REQUERY;
1697 int dispatched = 0;
1697 1698
1698 if (!dlm_grab(dlm)) { 1699 if (!dlm_grab(dlm)) {
1699 /* since the domain has gone away on this 1700 /* since the domain has gone away on this
@@ -1719,8 +1720,10 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
1719 dlm_put(dlm); 1720 dlm_put(dlm);
1720 /* sender will take care of this and retry */ 1721 /* sender will take care of this and retry */
1721 return ret; 1722 return ret;
1722 } else 1723 } else {
1724 dispatched = 1;
1723 __dlm_lockres_grab_inflight_worker(dlm, res); 1725 __dlm_lockres_grab_inflight_worker(dlm, res);
1726 }
1724 spin_unlock(&res->spinlock); 1727 spin_unlock(&res->spinlock);
1725 } else { 1728 } else {
1726 /* put.. incase we are not the master */ 1729 /* put.. incase we are not the master */
@@ -1730,7 +1733,8 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
1730 } 1733 }
1731 spin_unlock(&dlm->spinlock); 1734 spin_unlock(&dlm->spinlock);
1732 1735
1733 dlm_put(dlm); 1736 if (!dispatched)
1737 dlm_put(dlm);
1734 return master; 1738 return master;
1735} 1739}
1736 1740