lkml.org 
[lkml]   [2021]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 294/917] gfs2: Fix glock_hash_walk bugs
    Date
    From: Andreas Gruenbacher <agruenba@redhat.com>

    [ Upstream commit 7427f3bb49d81525b7dd1d0f7c5f6bbc752e6f0e ]

    So far, glock_hash_walk took a reference on each glock it iterated over, and it
    was the examiner's responsibility to drop those references. Dropping the final
    reference to a glock can sleep and the examiners are called in a RCU critical
    section with spin locks held, so examiners that didn't need the extra reference
    had to drop it asynchronously via gfs2_glock_queue_put or similar. This wasn't
    done correctly in thaw_glock which did call gfs2_glock_put, and not at all in
    dump_glock_func.

    Change glock_hash_walk to not take glock references at all. That way, the
    examiners that don't need them won't have to bother with slow asynchronous
    puts, and the examiners that do need references can take them themselves.

    Reported-by: Alexander Aring <aahringo@redhat.com>
    Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/gfs2/glock.c | 22 ++++++++++++----------
    1 file changed, 12 insertions(+), 10 deletions(-)

    diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
    index 8ca89adf31a86..02cd0ae98208d 100644
    --- a/fs/gfs2/glock.c
    +++ b/fs/gfs2/glock.c
    @@ -1893,10 +1893,10 @@ static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
    do {
    rhashtable_walk_start(&iter);

    - while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl))
    - if (gl->gl_name.ln_sbd == sdp &&
    - lockref_get_not_dead(&gl->gl_lockref))
    + while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl)) {
    + if (gl->gl_name.ln_sbd == sdp)
    examiner(gl);
    + }

    rhashtable_walk_stop(&iter);
    } while (cond_resched(), gl == ERR_PTR(-EAGAIN));
    @@ -1938,7 +1938,6 @@ static void flush_delete_work(struct gfs2_glock *gl)
    &gl->gl_delete, 0);
    }
    }
    - gfs2_glock_queue_work(gl, 0);
    }

    void gfs2_flush_delete_work(struct gfs2_sbd *sdp)
    @@ -1955,10 +1954,10 @@ void gfs2_flush_delete_work(struct gfs2_sbd *sdp)

    static void thaw_glock(struct gfs2_glock *gl)
    {
    - if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags)) {
    - gfs2_glock_put(gl);
    + if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
    + return;
    + if (!lockref_get_not_dead(&gl->gl_lockref))
    return;
    - }
    set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
    gfs2_glock_queue_work(gl, 0);
    }
    @@ -1974,9 +1973,12 @@ static void clear_glock(struct gfs2_glock *gl)
    gfs2_glock_remove_from_lru(gl);

    spin_lock(&gl->gl_lockref.lock);
    - if (gl->gl_state != LM_ST_UNLOCKED)
    - handle_callback(gl, LM_ST_UNLOCKED, 0, false);
    - __gfs2_glock_queue_work(gl, 0);
    + if (!__lockref_is_dead(&gl->gl_lockref)) {
    + gl->gl_lockref.count++;
    + if (gl->gl_state != LM_ST_UNLOCKED)
    + handle_callback(gl, LM_ST_UNLOCKED, 0, false);
    + __gfs2_glock_queue_work(gl, 0);
    + }
    spin_unlock(&gl->gl_lockref.lock);
    }

    --
    2.33.0


    \
     
     \ /
      Last update: 2021-11-16 00:40    [W:4.110 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site