diff options
author | Xue jiufei <xuejiufei@huawei.com> | 2014-06-04 19:06:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 19:53:54 -0400 |
commit | 6718cb5e0e75faa2b938dc1ee247fbd70136ccd7 (patch) | |
tree | 3d277329a463a886ba04faae47b0bb1794efa580 /fs/ocfs2 | |
parent | 55b465b66809368b459674b9d205010730953c2e (diff) |
ocfs2/dlm: fix possible convert=sion deadlock
We found there is a conversion deadlock when the owner of lockres
happened to crash before send DLM_PROXY_AST_MSG for a downconverting
lock. The situation is as follows:
Node1 Node2 Node3
the owner of lockresA
lock_1 granted at EX mode
and call ocfs2_cluster_unlock
to decrease ex_holders.
converting lock_3 from
NL to EX
send DLM_PROXY_AST_MSG
to Node1, asking Node 1
to downconvert.
receiving DLM_PROXY_AST_MSG,
thread ocfs2dc send
DLM_CONVERT_LOCK_MSG
to Node2 to downconvert
lock_1(EX->NL).
lock_1 can be granted and
put it into pending_asts
list, return DLM_NORMAL.
then something happened
and Node2 crashed.
received DLM_NORMAL, waiting
for DLM_PROXY_AST_MSG.
selected as the recovery
master, receving migrate
lock from Node1, queue
lock_1 to the tail of
converting list.
After dlm recovery, converting list in the master of lockresA(Node3)
will be: converting list head <-> lock_3(NL->EX) <->lock_1(EX<->NL).
Requested mode of lock_3 is not compatible with the granted mode of
lock_1, so it can not be granted. and lock_1 can not downconvert
because covnerting queue is strictly FIFO. So a deadlock is created.
We think function dlm_process_recovery_data() should queue_ast for
lock_1 or alter the order of lock_1 and lock_3, so dlm_thread can
process lock_1 first. And if there are multiple downconverting locks,
they must convert form PR to NL, so no need to sort them.
Signed-off-by: joyce.xue <xuejiufei@huawei.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/dlm/dlmrecovery.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index fe29f7978f81..5de019437ea5 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c | |||
@@ -1986,7 +1986,15 @@ skip_lvb: | |||
1986 | } | 1986 | } |
1987 | if (!bad) { | 1987 | if (!bad) { |
1988 | dlm_lock_get(newlock); | 1988 | dlm_lock_get(newlock); |
1989 | list_add_tail(&newlock->list, queue); | 1989 | if (mres->flags & DLM_MRES_RECOVERY && |
1990 | ml->list == DLM_CONVERTING_LIST && | ||
1991 | newlock->ml.type > | ||
1992 | newlock->ml.convert_type) { | ||
1993 | /* newlock is doing downconvert, add it to the | ||
1994 | * head of converting list */ | ||
1995 | list_add(&newlock->list, queue); | ||
1996 | } else | ||
1997 | list_add_tail(&newlock->list, queue); | ||
1990 | mlog(0, "%s:%.*s: added lock for node %u, " | 1998 | mlog(0, "%s:%.*s: added lock for node %u, " |
1991 | "setting refmap bit\n", dlm->name, | 1999 | "setting refmap bit\n", dlm->name, |
1992 | res->lockname.len, res->lockname.name, ml->node); | 2000 | res->lockname.len, res->lockname.name, ml->node); |