Commit 8bd95727 authored by Steven Whitehouse's avatar Steven Whitehouse

[GFS2] Fix list corruption in lops.c

The patch below appears to fix the list corruption that we are seeing on
occasion. Although the transaction structure is private to a single
thread, when the queued structures are dismantled during an in-core
commit, its possible for a different thread to be trying to add the same
structure to another, new, transaction at the same time.

To avoid this, this patch takes the log spinlock during this operation.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent d7c103d0
...@@ -69,13 +69,16 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -69,13 +69,16 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
struct gfs2_trans *tr; struct gfs2_trans *tr;
if (!list_empty(&bd->bd_list_tr)) gfs2_log_lock(sdp);
if (!list_empty(&bd->bd_list_tr)) {
gfs2_log_unlock(sdp);
return; return;
}
tr = current->journal_info; tr = current->journal_info;
tr->tr_touched = 1; tr->tr_touched = 1;
tr->tr_num_buf++; tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf); list_add(&bd->bd_list_tr, &tr->tr_list_buf);
gfs2_log_unlock(sdp);
if (!list_empty(&le->le_list)) if (!list_empty(&le->le_list))
return; return;
...@@ -84,7 +87,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -84,7 +87,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
gfs2_meta_check(sdp, bd->bd_bh); gfs2_meta_check(sdp, bd->bd_bh);
gfs2_pin(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh);
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
sdp->sd_log_num_buf++; sdp->sd_log_num_buf++;
list_add(&le->le_list, &sdp->sd_log_le_buf); list_add(&le->le_list, &sdp->sd_log_le_buf);
...@@ -98,11 +100,13 @@ static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -98,11 +100,13 @@ static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
struct list_head *head = &tr->tr_list_buf; struct list_head *head = &tr->tr_list_buf;
struct gfs2_bufdata *bd; struct gfs2_bufdata *bd;
gfs2_log_lock(sdp);
while (!list_empty(head)) { while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr); bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
list_del_init(&bd->bd_list_tr); list_del_init(&bd->bd_list_tr);
tr->tr_num_buf--; tr->tr_num_buf--;
} }
gfs2_log_unlock(sdp);
gfs2_assert_warn(sdp, !tr->tr_num_buf); gfs2_assert_warn(sdp, !tr->tr_num_buf);
} }
...@@ -462,13 +466,17 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -462,13 +466,17 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
struct address_space *mapping = bd->bd_bh->b_page->mapping; struct address_space *mapping = bd->bd_bh->b_page->mapping;
struct gfs2_inode *ip = GFS2_I(mapping->host); struct gfs2_inode *ip = GFS2_I(mapping->host);
gfs2_log_lock(sdp);
tr->tr_touched = 1; tr->tr_touched = 1;
if (list_empty(&bd->bd_list_tr) && if (list_empty(&bd->bd_list_tr) &&
(ip->i_di.di_flags & GFS2_DIF_JDATA)) { (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
tr->tr_num_buf++; tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf); list_add(&bd->bd_list_tr, &tr->tr_list_buf);
gfs2_log_unlock(sdp);
gfs2_pin(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh);
tr->tr_num_buf_new++; tr->tr_num_buf_new++;
} else {
gfs2_log_unlock(sdp);
} }
gfs2_trans_add_gl(bd->bd_gl); gfs2_trans_add_gl(bd->bd_gl);
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment