Commit 7d3c1feb authored by David Teigland's avatar David Teigland Committed by Steven Whitehouse

[DLM] fix mode munging

There are flags to enable two specialized features in the dlm:
1. CONVDEADLK causes the dlm to resolve conversion deadlocks internally by
   changing the granted mode of locks to NL.
2. ALTPR/ALTCW cause the dlm to change the requested mode of locks to PR
   or CW to grant them if the normal requested mode can't be granted.

GFS direct i/o exercises both of these features, especially when mixed
with buffered i/o.  The dlm has problems with them.

The first problem is on the master node. If it demotes a lock as a part of
converting it, the actual step of converting the lock isn't being done
after the demotion, the lock is just left sitting on the granted queue
with a granted mode of NL.  I think the mistaken assumption was that the
call to grant_pending_locks() would grant it, but that function naturally
doesn't look at locks on the granted queue.

The second problem is on the process node.  If the master either demotes
or gives an altmode, the munging of the gr/rq modes is never done in the
process copy of the lock, leaving the master/process copies out of sync.
Signed-off-by: default avatarDavid Teigland <teigland@redhat.com>
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 5f882096
...@@ -224,6 +224,16 @@ static inline int is_demoted(struct dlm_lkb *lkb) ...@@ -224,6 +224,16 @@ static inline int is_demoted(struct dlm_lkb *lkb)
return (lkb->lkb_sbflags & DLM_SBF_DEMOTED); return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
} }
static inline int is_altmode(struct dlm_lkb *lkb)
{
return (lkb->lkb_sbflags & DLM_SBF_ALTMODE);
}
static inline int is_granted(struct dlm_lkb *lkb)
{
return (lkb->lkb_status == DLM_LKSTS_GRANTED);
}
static inline int is_remote(struct dlm_rsb *r) static inline int is_remote(struct dlm_rsb *r)
{ {
DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r);); DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
...@@ -1191,6 +1201,50 @@ static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb) ...@@ -1191,6 +1201,50 @@ static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
queue_cast(r, lkb, 0); queue_cast(r, lkb, 0);
} }
/* The special CONVDEADLK, ALTPR and ALTCW flags allow the master to
change the granted/requested modes. We're munging things accordingly in
the process copy.
CONVDEADLK: our grmode may have been forced down to NL to resolve a
conversion deadlock
ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
compatible with other granted locks */
static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)
{
if (ms->m_type != DLM_MSG_CONVERT_REPLY) {
log_print("munge_demoted %x invalid reply type %d",
lkb->lkb_id, ms->m_type);
return;
}
if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
log_print("munge_demoted %x invalid modes gr %d rq %d",
lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
return;
}
lkb->lkb_grmode = DLM_LOCK_NL;
}
static void munge_altmode(struct dlm_lkb *lkb, struct dlm_message *ms)
{
if (ms->m_type != DLM_MSG_REQUEST_REPLY &&
ms->m_type != DLM_MSG_GRANT) {
log_print("munge_altmode %x invalid reply type %d",
lkb->lkb_id, ms->m_type);
return;
}
if (lkb->lkb_exflags & DLM_LKF_ALTPR)
lkb->lkb_rqmode = DLM_LOCK_PR;
else if (lkb->lkb_exflags & DLM_LKF_ALTCW)
lkb->lkb_rqmode = DLM_LOCK_CW;
else {
log_print("munge_altmode invalid exflags %x", lkb->lkb_exflags);
dlm_print_lkb(lkb);
}
}
static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head) static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
{ {
struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb, struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
...@@ -1965,9 +2019,24 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) ...@@ -1965,9 +2019,24 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
goto out; goto out;
} }
if (can_be_queued(lkb)) { /* is_demoted() means the can_be_granted() above set the grmode
if (is_demoted(lkb)) to NL, and left us on the granted queue. This auto-demotion
(due to CONVDEADLK) might mean other locks, and/or this lock, are
now grantable. We have to try to grant other converting locks
before we try again to grant this one. */
if (is_demoted(lkb)) {
grant_pending_convert(r, DLM_LOCK_IV);
if (_can_be_granted(r, lkb, 1)) {
grant_lock(r, lkb);
queue_cast(r, lkb, 0);
grant_pending_locks(r); grant_pending_locks(r);
goto out;
}
/* else fall through and move to convert queue */
}
if (can_be_queued(lkb)) {
error = -EINPROGRESS; error = -EINPROGRESS;
del_lkb(r, lkb); del_lkb(r, lkb);
add_lkb(r, lkb, DLM_LKSTS_CONVERT); add_lkb(r, lkb, DLM_LKSTS_CONVERT);
...@@ -2908,6 +2977,8 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms) ...@@ -2908,6 +2977,8 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
lock_rsb(r); lock_rsb(r);
receive_flags_reply(lkb, ms); receive_flags_reply(lkb, ms);
if (is_altmode(lkb))
munge_altmode(lkb, ms);
grant_lock_pc(r, lkb, ms); grant_lock_pc(r, lkb, ms);
queue_cast(r, lkb, 0); queue_cast(r, lkb, 0);
...@@ -3038,6 +3109,8 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms) ...@@ -3038,6 +3109,8 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
/* request was queued or granted on remote master */ /* request was queued or granted on remote master */
receive_flags_reply(lkb, ms); receive_flags_reply(lkb, ms);
lkb->lkb_remid = ms->m_lkid; lkb->lkb_remid = ms->m_lkid;
if (is_altmode(lkb))
munge_altmode(lkb, ms);
if (result) if (result)
add_lkb(r, lkb, DLM_LKSTS_WAITING); add_lkb(r, lkb, DLM_LKSTS_WAITING);
else { else {
...@@ -3101,6 +3174,9 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, ...@@ -3101,6 +3174,9 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
case -EINPROGRESS: case -EINPROGRESS:
/* convert was queued on remote master */ /* convert was queued on remote master */
receive_flags_reply(lkb, ms);
if (is_demoted(lkb))
munge_demoted(lkb, ms);
del_lkb(r, lkb); del_lkb(r, lkb);
add_lkb(r, lkb, DLM_LKSTS_CONVERT); add_lkb(r, lkb, DLM_LKSTS_CONVERT);
break; break;
...@@ -3108,6 +3184,8 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, ...@@ -3108,6 +3184,8 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
case 0: case 0:
/* convert was granted on remote master */ /* convert was granted on remote master */
receive_flags_reply(lkb, ms); receive_flags_reply(lkb, ms);
if (is_demoted(lkb))
munge_demoted(lkb, ms);
grant_lock_pc(r, lkb, ms); grant_lock_pc(r, lkb, ms);
queue_cast(r, lkb, 0); queue_cast(r, lkb, 0);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment