| From 78178ca844f0eb88f21f31c7fde969384be4c901 Mon Sep 17 00:00:00 2001 |
| From: Bob Peterson <rpeterso@redhat.com> |
| Date: Fri, 5 Feb 2021 13:50:41 -0500 |
| Subject: gfs2: Don't skip dlm unlock if glock has an lvb |
| |
| From: Bob Peterson <rpeterso@redhat.com> |
| |
| commit 78178ca844f0eb88f21f31c7fde969384be4c901 upstream. |
| |
| Patch fb6791d100d1 was designed to allow gfs2 to unmount quicker by |
| skipping the step where it tells dlm to unlock glocks in EX with lvbs. |
| This was done because when gfs2 unmounts a file system, it destroys the |
| dlm lockspace shortly after it destroys the glocks so it doesn't need to |
| unlock them all: the unlock is implied when the lockspace is destroyed |
| by dlm. |
| |
| However, that patch introduced a use-after-free in dlm: as part of its |
| normal dlm_recoverd process, it can call ls_recovery to recover dead |
| locks. In so doing, it can call recover_rsbs which calls recover_lvb for |
| any mastered rsbs. Func recover_lvb runs through the list of lkbs queued |
| to the given rsb (if the glock is cached but unlocked, it will still be |
| queued to the lkb, but in NL--Unlocked--mode) and if it has an lvb, |
| copies it to the rsb, thus trying to preserve the lkb. However, when |
| gfs2 skips the dlm unlock step, it frees the glock and its lvb, which |
| means dlm's function recover_lvb references the now freed lvb pointer, |
| copying the freed lvb memory to the rsb. |
| |
| This patch changes the check in gdlm_put_lock so that it calls |
| dlm_unlock for all glocks that contain an lvb pointer. |
| |
| Fixes: fb6791d100d1 ("GFS2: skip dlm_unlock calls in unmount") |
| Cc: stable@vger.kernel.org # v3.8+ |
| Signed-off-by: Bob Peterson <rpeterso@redhat.com> |
| Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/gfs2/lock_dlm.c | 8 ++------ |
| 1 file changed, 2 insertions(+), 6 deletions(-) |
| |
| --- a/fs/gfs2/lock_dlm.c |
| +++ b/fs/gfs2/lock_dlm.c |
| @@ -284,7 +284,6 @@ static void gdlm_put_lock(struct gfs2_gl |
| { |
| struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; |
| struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
| - int lvb_needs_unlock = 0; |
| int error; |
| |
| if (gl->gl_lksb.sb_lkid == 0) { |
| @@ -297,13 +296,10 @@ static void gdlm_put_lock(struct gfs2_gl |
| gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); |
| gfs2_update_request_times(gl); |
| |
| - /* don't want to skip dlm_unlock writing the lvb when lock is ex */ |
| - |
| - if (gl->gl_lksb.sb_lvbptr && (gl->gl_state == LM_ST_EXCLUSIVE)) |
| - lvb_needs_unlock = 1; |
| + /* don't want to skip dlm_unlock writing the lvb when lock has one */ |
| |
| if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) && |
| - !lvb_needs_unlock) { |
| + !gl->gl_lksb.sb_lvbptr) { |
| gfs2_glock_free(gl); |
| return; |
| } |