diff options
author | Joseph Qi <joseph.qi@huawei.com> | 2015-09-22 17:59:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-22 18:09:53 -0400 |
commit | 012572d4fc2e4ddd5c8ec8614d51414ec6cae02a (patch) | |
tree | ce5b9dc95ea8f3e9ea4a84d6b87cce8d0777e94b /fs/ocfs2/dlm | |
parent | 7a07b503bf249986a1eeef0351d66cac0d8bf721 (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.c | 9 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmrecovery.c | 8 |
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 | ||