mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
dlm: fix missing lkb refcount handling
commit 1689c16913
upstream.
We always call hold_lkb(lkb) if we increment lkb->lkb_wait_count.
So, we always need to call unhold_lkb(lkb) if we decrement
lkb->lkb_wait_count. This patch will add missing unhold_lkb(lkb) if we
decrement lkb->lkb_wait_count. In case of setting lkb->lkb_wait_count to
zero we need to countdown until reaching zero and call unhold_lkb(lkb).
The waiters list unhold_lkb(lkb) can be removed because it's done for
the last lkb_wait_count decrement iteration as it's done in
_remove_from_waiters().
This issue was discovered by a dlm gfs2 test case which use excessively
dlm_unlock(LKF_CANCEL) feature. Probably the lkb->lkb_wait_count value
never reached above 1 if this feature isn't used and so it was not
discovered before.
The testcase ended in a rsb on the rsb keep data structure with a
refcount of 1 but no lkb was associated with it, which is itself
an invalid behaviour. A side effect of that was a condition in which
the dlm was sending remove messages in a looping behaviour. With this
patch that has not been reproduced.
Cc: stable@vger.kernel.org
Signed-off-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: David Teigland <teigland@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e18afaca6e
commit
12052dce77
1 changed files with 9 additions and 2 deletions
|
@ -1559,6 +1559,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
|
|||
lkb->lkb_wait_type = 0;
|
||||
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
|
||||
lkb->lkb_wait_count--;
|
||||
unhold_lkb(lkb);
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
|
@ -1585,6 +1586,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
|
|||
log_error(ls, "remwait error %x reply %d wait_type %d overlap",
|
||||
lkb->lkb_id, mstype, lkb->lkb_wait_type);
|
||||
lkb->lkb_wait_count--;
|
||||
unhold_lkb(lkb);
|
||||
lkb->lkb_wait_type = 0;
|
||||
}
|
||||
|
||||
|
@ -5331,11 +5333,16 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
|
|||
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
|
||||
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
|
||||
lkb->lkb_wait_type = 0;
|
||||
lkb->lkb_wait_count = 0;
|
||||
/* drop all wait_count references we still
|
||||
* hold a reference for this iteration.
|
||||
*/
|
||||
while (lkb->lkb_wait_count) {
|
||||
lkb->lkb_wait_count--;
|
||||
unhold_lkb(lkb);
|
||||
}
|
||||
mutex_lock(&ls->ls_waiters_mutex);
|
||||
list_del_init(&lkb->lkb_wait_reply);
|
||||
mutex_unlock(&ls->ls_waiters_mutex);
|
||||
unhold_lkb(lkb); /* for waiters list */
|
||||
|
||||
if (oc || ou) {
|
||||
/* do an unlock or cancel instead of resending */
|
||||
|
|
Loading…
Reference in a new issue