diff options
author | Russell Cattelan <cattelan@redhat.com> | 2006-11-09 11:28:08 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-30 10:34:55 -0500 |
commit | 7020933156ac2a8a7386314933e49948bf0438f7 (patch) | |
tree | 2833fb3993762143b32696919342ab7e86c7d471 | |
parent | 9e2dbdac3df300516ffdd9a8631f23164d068a50 (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>
-rw-r--r-- | 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 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); |