Skip to content

Commit 1689c16

Browse files
Alexander Aringteigland
authored andcommitted
dlm: fix missing lkb refcount handling
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: [email protected] Signed-off-by: Alexander Aring <[email protected]> Signed-off-by: David Teigland <[email protected]>
1 parent e425ac9 commit 1689c16

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

fs/dlm/lock.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
15781578
lkb->lkb_wait_type = 0;
15791579
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
15801580
lkb->lkb_wait_count--;
1581+
unhold_lkb(lkb);
15811582
goto out_del;
15821583
}
15831584

@@ -1604,6 +1605,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
16041605
log_error(ls, "remwait error %x reply %d wait_type %d overlap",
16051606
lkb->lkb_id, mstype, lkb->lkb_wait_type);
16061607
lkb->lkb_wait_count--;
1608+
unhold_lkb(lkb);
16071609
lkb->lkb_wait_type = 0;
16081610
}
16091611

@@ -5364,11 +5366,16 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
53645366
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
53655367
lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
53665368
lkb->lkb_wait_type = 0;
5367-
lkb->lkb_wait_count = 0;
5369+
/* drop all wait_count references we still
5370+
* hold a reference for this iteration.
5371+
*/
5372+
while (lkb->lkb_wait_count) {
5373+
lkb->lkb_wait_count--;
5374+
unhold_lkb(lkb);
5375+
}
53685376
mutex_lock(&ls->ls_waiters_mutex);
53695377
list_del_init(&lkb->lkb_wait_reply);
53705378
mutex_unlock(&ls->ls_waiters_mutex);
5371-
unhold_lkb(lkb); /* for waiters list */
53725379

53735380
if (oc || ou) {
53745381
/* do an unlock or cancel instead of resending */

0 commit comments

Comments
 (0)