>From 7020933156ac2a8a7386314933e49948bf0438f7 Mon Sep 17 00:00:00 2001
From: Russell Cattelan <[EMAIL PROTECTED]>
Date: Thu, 9 Nov 2006 11:28:08 -0500
Subject: [PATCH] [GFS2] Fix race in logging code

The log lock is dropped prior to io submittion, but
this exposes a hole in which the log data structures
may be going away due to a truncate.
Store the buffer head in a local pointer prior to
dropping the lock and relay on the buffer_head lock
for consitency on the buffer head.

Signed-Off-By: Russell Cattelan <[EMAIL PROTECTED]>
Signed-off-by: Steven Whitehouse <[EMAIL PROTECTED]>
---
 fs/gfs2/lops.c |   36 +++++++++++++++++++++---------------
 1 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 8a654cd..4d7f94d 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -509,7 +509,7 @@ static void databuf_lo_before_commit(str
 {
        LIST_HEAD(started);
        struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
-       struct buffer_head *bh = NULL;
+       struct buffer_head *bh = NULL,*bh1 = NULL;
        unsigned int offset = sizeof(struct gfs2_log_descriptor);
        struct gfs2_log_descriptor *ld;
        unsigned int limit;
@@ -537,8 +537,13 @@ static void databuf_lo_before_commit(str
                list_for_each_entry_safe_continue(bd1, bdt,
                                                  &sdp->sd_log_le_databuf,
                                                  bd_le.le_list) {
+                       /* store off the buffer head in a local ptr since
+                        * gfs2_bufdata might change when we drop the log lock
+                        */
+                       bh1 = bd1->bd_bh;
+
                        /* An ordered write buffer */
-                       if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) {
+                       if (bh1 && !buffer_pinned(bh1)) {
                                list_move(&bd1->bd_le.le_list, &started);
                                if (bd1 == bd2) {
                                        bd2 = NULL;
@@ -547,20 +552,21 @@ static void databuf_lo_before_commit(str
                                                        bd_le.le_list);
                                }
                                total_dbuf--;
-                               if (bd1->bd_bh) {
-                                       get_bh(bd1->bd_bh);
-                                       if (buffer_dirty(bd1->bd_bh)) {
+                               if (bh1) {
+                                       if (buffer_dirty(bh1)) {
+                                               get_bh(bh1);
+
                                                gfs2_log_unlock(sdp);
-                                               wait_on_buffer(bd1->bd_bh);
-                                               ll_rw_block(WRITE, 1,
-                                                           &bd1->bd_bh);
+
+                                               ll_rw_block(SWRITE, 1, &bh1);
+                                               brelse(bh1);
+
                                                gfs2_log_lock(sdp);
                                        }
-                                       brelse(bd1->bd_bh);
                                        continue;
                                }
                                continue;
-                       } else if (bd1->bd_bh) { /* A journaled buffer */
+                       } else if (bh1) { /* A journaled buffer */
                                int magic;
                                gfs2_log_unlock(sdp);
                                if (!bh) {
@@ -582,16 +588,16 @@ static void databuf_lo_before_commit(str
                                        ld->ld_data2 = cpu_to_be32(0);
                                        memset(ld->ld_reserved, 0, 
sizeof(ld->ld_reserved));
                                }
-                               magic = gfs2_check_magic(bd1->bd_bh);
-                               *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
+                               magic = gfs2_check_magic(bh1);
+                               *ptr++ = cpu_to_be64(bh1->b_blocknr);
                                *ptr++ = cpu_to_be64((__u64)magic);
-                               clear_buffer_escaped(bd1->bd_bh);
+                               clear_buffer_escaped(bh1);
                                if (unlikely(magic != 0))
-                                       set_buffer_escaped(bd1->bd_bh);
+                                       set_buffer_escaped(bh1);
                                gfs2_log_lock(sdp);
                                if (n++ > num)
                                        break;
-                       } else if (!bd1->bd_bh) {
+                       } else if (!bh1) {
                                total_dbuf--;
                                sdp->sd_log_num_databuf--;
                                list_del_init(&bd1->bd_le.le_list);
-- 
1.4.1



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to