]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blobdiff - releases/3.6.7/gfs2-test-bufdata-with-buffer-locked-and-gfs2_log_lock-held.patch
Linux 3.6.7
[thirdparty/kernel/stable-queue.git] / releases / 3.6.7 / gfs2-test-bufdata-with-buffer-locked-and-gfs2_log_lock-held.patch
diff --git a/releases/3.6.7/gfs2-test-bufdata-with-buffer-locked-and-gfs2_log_lock-held.patch b/releases/3.6.7/gfs2-test-bufdata-with-buffer-locked-and-gfs2_log_lock-held.patch
new file mode 100644 (file)
index 0000000..abe5c50
--- /dev/null
@@ -0,0 +1,102 @@
+From 96e5d1d3adf56f1c7eeb07258f6a1a0a7ae9c489 Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <bmarzins@redhat.com>
+Date: Wed, 7 Nov 2012 00:38:06 -0600
+Subject: GFS2: Test bufdata with buffer locked and gfs2_log_lock held
+
+From: Benjamin Marzinski <bmarzins@redhat.com>
+
+commit 96e5d1d3adf56f1c7eeb07258f6a1a0a7ae9c489 upstream.
+
+In gfs2_trans_add_bh(), gfs2 was testing if a there was a bd attached to the
+buffer without having the gfs2_log_lock held. It was then assuming it would
+stay attached for the rest of the function. However, without either the log
+lock being held of the buffer locked, __gfs2_ail_flush() could detach bd at any
+time.  This patch moves the locking before the test.  If there isn't a bd
+already attached, gfs2 can safely allocate one and attach it before locking.
+There is no way that the newly allocated bd could be on the ail list,
+and thus no way for __gfs2_ail_flush() to detach it.
+
+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
+Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/gfs2/lops.c  |   14 ++------------
+ fs/gfs2/trans.c |    8 ++++++++
+ 2 files changed, 10 insertions(+), 12 deletions(-)
+
+--- a/fs/gfs2/lops.c
++++ b/fs/gfs2/lops.c
+@@ -393,12 +393,10 @@ static void buf_lo_add(struct gfs2_sbd *
+       struct gfs2_meta_header *mh;
+       struct gfs2_trans *tr;
+-      lock_buffer(bd->bd_bh);
+-      gfs2_log_lock(sdp);
+       tr = current->journal_info;
+       tr->tr_touched = 1;
+       if (!list_empty(&bd->bd_list))
+-              goto out;
++              return;
+       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
+       mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
+@@ -414,9 +412,6 @@ static void buf_lo_add(struct gfs2_sbd *
+       sdp->sd_log_num_buf++;
+       list_add(&bd->bd_list, &sdp->sd_log_le_buf);
+       tr->tr_num_buf_new++;
+-out:
+-      gfs2_log_unlock(sdp);
+-      unlock_buffer(bd->bd_bh);
+ }
+ static void gfs2_check_magic(struct buffer_head *bh)
+@@ -777,12 +772,10 @@ static void databuf_lo_add(struct gfs2_s
+       struct address_space *mapping = bd->bd_bh->b_page->mapping;
+       struct gfs2_inode *ip = GFS2_I(mapping->host);
+-      lock_buffer(bd->bd_bh);
+-      gfs2_log_lock(sdp);
+       if (tr)
+               tr->tr_touched = 1;
+       if (!list_empty(&bd->bd_list))
+-              goto out;
++              return;
+       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
+       if (gfs2_is_jdata(ip)) {
+@@ -793,9 +786,6 @@ static void databuf_lo_add(struct gfs2_s
+       } else {
+               list_add_tail(&bd->bd_list, &sdp->sd_log_le_ordered);
+       }
+-out:
+-      gfs2_log_unlock(sdp);
+-      unlock_buffer(bd->bd_bh);
+ }
+ /**
+--- a/fs/gfs2/trans.c
++++ b/fs/gfs2/trans.c
+@@ -155,14 +155,22 @@ void gfs2_trans_add_bh(struct gfs2_glock
+       struct gfs2_sbd *sdp = gl->gl_sbd;
+       struct gfs2_bufdata *bd;
++      lock_buffer(bh);
++      gfs2_log_lock(sdp);
+       bd = bh->b_private;
+       if (bd)
+               gfs2_assert(sdp, bd->bd_gl == gl);
+       else {
++              gfs2_log_unlock(sdp);
++              unlock_buffer(bh);
+               gfs2_attach_bufdata(gl, bh, meta);
+               bd = bh->b_private;
++              lock_buffer(bh);
++              gfs2_log_lock(sdp);
+       }
+       lops_add(sdp, bd);
++      gfs2_log_unlock(sdp);
++      unlock_buffer(bh);
+ }
+ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)