lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 563/667] dlm: fix missing lkb refcount handling
    Date
    From: Alexander Aring <aahringo@redhat.com>

    commit 1689c169134f4b5a39156122d799b7dca76d8ddb 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>
    ---
    fs/dlm/lock.c | 11 +++++++++--
    1 file changed, 9 insertions(+), 2 deletions(-)

    --- a/fs/dlm/lock.c
    +++ b/fs/dlm/lock.c
    @@ -1551,6 +1551,7 @@ static int _remove_from_waiters(struct d
    lkb->lkb_wait_type = 0;
    lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
    lkb->lkb_wait_count--;
    + unhold_lkb(lkb);
    goto out_del;
    }

    @@ -1577,6 +1578,7 @@ static int _remove_from_waiters(struct d
    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;
    }

    @@ -5310,11 +5312,16 @@ int dlm_recover_waiters_post(struct dlm_
    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 */

    \
     
     \ /
      Last update: 2022-06-07 22:04    [W:4.772 / U:0.272 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site