diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-07-23 04:54:36 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-10 03:54:39 -0400 |
commit | 87124e581bfeaa5864662a435b6ee2a19e91b905 (patch) | |
tree | f9bc5d965834f1c7435123f26b9ab8f961c8848f | |
parent | bbf25010f1a6b761914430f5fca081ec8c7accd1 (diff) |
[GFS2] Fix two races relating to glock callbacks
One of the races relates to referencing a variable while not holding
its protecting spinlock. The patch simply moves the test inside the
spin lock. The other races occurs when a demote to unlocked request
occurs during the time a demote to shared request is already running.
This of course only happens in the case that the lock was in the
exclusive mode to start with. The patch adds a check to see if another
demote request has occurred in the mean time and if it has, then it
performs a second demote.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r-- | fs/gfs2/glock.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 3f0974e1afef..6a3eeba102f9 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -545,12 +545,14 @@ static int rq_demote(struct gfs2_glock *gl) | |||
545 | return 0; | 545 | return 0; |
546 | } | 546 | } |
547 | set_bit(GLF_LOCK, &gl->gl_flags); | 547 | set_bit(GLF_LOCK, &gl->gl_flags); |
548 | spin_unlock(&gl->gl_spin); | ||
549 | if (gl->gl_demote_state == LM_ST_UNLOCKED || | 548 | if (gl->gl_demote_state == LM_ST_UNLOCKED || |
550 | gl->gl_state != LM_ST_EXCLUSIVE) | 549 | gl->gl_state != LM_ST_EXCLUSIVE) { |
550 | spin_unlock(&gl->gl_spin); | ||
551 | gfs2_glock_drop_th(gl); | 551 | gfs2_glock_drop_th(gl); |
552 | else | 552 | } else { |
553 | spin_unlock(&gl->gl_spin); | ||
553 | gfs2_glock_xmote_th(gl, NULL); | 554 | gfs2_glock_xmote_th(gl, NULL); |
555 | } | ||
554 | spin_lock(&gl->gl_spin); | 556 | spin_lock(&gl->gl_spin); |
555 | 557 | ||
556 | return 0; | 558 | return 0; |
@@ -760,10 +762,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) | |||
760 | 762 | ||
761 | if (!gh) { | 763 | if (!gh) { |
762 | gl->gl_stamp = jiffies; | 764 | gl->gl_stamp = jiffies; |
763 | if (ret & LM_OUT_CANCELED) | 765 | if (ret & LM_OUT_CANCELED) { |
764 | op_done = 0; | 766 | op_done = 0; |
765 | else | 767 | } else { |
768 | spin_lock(&gl->gl_spin); | ||
769 | if (gl->gl_state != gl->gl_demote_state) { | ||
770 | gl->gl_req_bh = NULL; | ||
771 | spin_unlock(&gl->gl_spin); | ||
772 | gfs2_glock_drop_th(gl); | ||
773 | gfs2_glock_put(gl); | ||
774 | return; | ||
775 | } | ||
766 | gfs2_demote_wake(gl); | 776 | gfs2_demote_wake(gl); |
777 | spin_unlock(&gl->gl_spin); | ||
778 | } | ||
767 | } else { | 779 | } else { |
768 | spin_lock(&gl->gl_spin); | 780 | spin_lock(&gl->gl_spin); |
769 | list_del_init(&gh->gh_list); | 781 | list_del_init(&gh->gh_list); |
@@ -817,7 +829,7 @@ out: | |||
817 | * | 829 | * |
818 | */ | 830 | */ |
819 | 831 | ||
820 | void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) | 832 | static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) |
821 | { | 833 | { |
822 | struct gfs2_sbd *sdp = gl->gl_sbd; | 834 | struct gfs2_sbd *sdp = gl->gl_sbd; |
823 | int flags = gh ? gh->gh_flags : 0; | 835 | int flags = gh ? gh->gh_flags : 0; |