aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/lops.c
diff options
context:
space:
mode:
authorRussell Cattelan <cattelan@redhat.com>2006-11-09 11:28:08 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-11-30 10:34:55 -0500
commit7020933156ac2a8a7386314933e49948bf0438f7 (patch)
tree2833fb3993762143b32696919342ab7e86c7d471 /fs/gfs2/lops.c
parent9e2dbdac3df300516ffdd9a8631f23164d068a50 (diff)
[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 <cattelan@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/lops.c')
-rw-r--r--fs/gfs2/lops.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 8a654cd253dd..4d7f94d8c7bd 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -509,7 +509,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
509{ 509{
510 LIST_HEAD(started); 510 LIST_HEAD(started);
511 struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; 511 struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
512 struct buffer_head *bh = NULL; 512 struct buffer_head *bh = NULL,*bh1 = NULL;
513 unsigned int offset = sizeof(struct gfs2_log_descriptor); 513 unsigned int offset = sizeof(struct gfs2_log_descriptor);
514 struct gfs2_log_descriptor *ld; 514 struct gfs2_log_descriptor *ld;
515 unsigned int limit; 515 unsigned int limit;
@@ -537,8 +537,13 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
537 list_for_each_entry_safe_continue(bd1, bdt, 537 list_for_each_entry_safe_continue(bd1, bdt,
538 &sdp->sd_log_le_databuf, 538 &sdp->sd_log_le_databuf,
539 bd_le.le_list) { 539 bd_le.le_list) {
540 /* store off the buffer head in a local ptr since
541 * gfs2_bufdata might change when we drop the log lock
542 */
543 bh1 = bd1->bd_bh;
544
540 /* An ordered write buffer */ 545 /* An ordered write buffer */
541 if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) { 546 if (bh1 && !buffer_pinned(bh1)) {
542 list_move(&bd1->bd_le.le_list, &started); 547 list_move(&bd1->bd_le.le_list, &started);
543 if (bd1 == bd2) { 548 if (bd1 == bd2) {
544 bd2 = NULL; 549 bd2 = NULL;
@@ -547,20 +552,21 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
547 bd_le.le_list); 552 bd_le.le_list);
548 } 553 }
549 total_dbuf--; 554 total_dbuf--;
550 if (bd1->bd_bh) { 555 if (bh1) {
551 get_bh(bd1->bd_bh); 556 if (buffer_dirty(bh1)) {
552 if (buffer_dirty(bd1->bd_bh)) { 557 get_bh(bh1);
558
553 gfs2_log_unlock(sdp); 559 gfs2_log_unlock(sdp);
554 wait_on_buffer(bd1->bd_bh); 560
555 ll_rw_block(WRITE, 1, 561 ll_rw_block(SWRITE, 1, &bh1);
556 &bd1->bd_bh); 562 brelse(bh1);
563
557 gfs2_log_lock(sdp); 564 gfs2_log_lock(sdp);
558 } 565 }
559 brelse(bd1->bd_bh);
560 continue; 566 continue;
561 } 567 }
562 continue; 568 continue;
563 } else if (bd1->bd_bh) { /* A journaled buffer */ 569 } else if (bh1) { /* A journaled buffer */
564 int magic; 570 int magic;
565 gfs2_log_unlock(sdp); 571 gfs2_log_unlock(sdp);
566 if (!bh) { 572 if (!bh) {
@@ -582,16 +588,16 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
582 ld->ld_data2 = cpu_to_be32(0); 588 ld->ld_data2 = cpu_to_be32(0);
583 memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); 589 memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
584 } 590 }
585 magic = gfs2_check_magic(bd1->bd_bh); 591 magic = gfs2_check_magic(bh1);
586 *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); 592 *ptr++ = cpu_to_be64(bh1->b_blocknr);
587 *ptr++ = cpu_to_be64((__u64)magic); 593 *ptr++ = cpu_to_be64((__u64)magic);
588 clear_buffer_escaped(bd1->bd_bh); 594 clear_buffer_escaped(bh1);
589 if (unlikely(magic != 0)) 595 if (unlikely(magic != 0))
590 set_buffer_escaped(bd1->bd_bh); 596 set_buffer_escaped(bh1);
591 gfs2_log_lock(sdp); 597 gfs2_log_lock(sdp);
592 if (n++ > num) 598 if (n++ > num)
593 break; 599 break;
594 } else if (!bd1->bd_bh) { 600 } else if (!bh1) {
595 total_dbuf--; 601 total_dbuf--;
596 sdp->sd_log_num_databuf--; 602 sdp->sd_log_num_databuf--;
597 list_del_init(&bd1->bd_le.le_list); 603 list_del_init(&bd1->bd_le.le_list);