diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-09-02 05:48:13 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-10 03:56:03 -0400 |
commit | d7b616e252b125f12b007c392f7644053bb6f140 (patch) | |
tree | 0794272905a1876ef74144a993f7a76400893813 /fs/gfs2/lops.c | |
parent | 9b9107a5a8b190e6cf09bbdf893869c6a9c482cc (diff) |
[GFS2] Clean up ordered write code
The following patch removes the ordered write processing from
databuf_lo_before_commit() and moves it to log.c. This has the effect of
greatly simplyfying databuf_lo_before_commit() and well as potentially
making the ordered write code more efficient.
As a side effect of this, its now possible to remove ordered buffers
from the ordered buffer list at any time, so we now make use of this in
invalidatepage and releasepage to ensure timely release of these
buffers.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/lops.c')
-rw-r--r-- | fs/gfs2/lops.c | 160 |
1 files changed, 40 insertions, 120 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3ec587135d46..7e2d4e692b50 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c | |||
@@ -555,10 +555,11 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
555 | if (gfs2_is_jdata(ip)) { | 555 | if (gfs2_is_jdata(ip)) { |
556 | gfs2_pin(sdp, bd->bd_bh); | 556 | gfs2_pin(sdp, bd->bd_bh); |
557 | tr->tr_num_databuf_new++; | 557 | tr->tr_num_databuf_new++; |
558 | sdp->sd_log_num_jdata++; | 558 | sdp->sd_log_num_databuf++; |
559 | list_add(&le->le_list, &sdp->sd_log_le_databuf); | ||
560 | } else { | ||
561 | list_add(&le->le_list, &sdp->sd_log_le_ordered); | ||
559 | } | 562 | } |
560 | sdp->sd_log_num_databuf++; | ||
561 | list_add(&le->le_list, &sdp->sd_log_le_databuf); | ||
562 | out: | 563 | out: |
563 | gfs2_log_unlock(sdp); | 564 | gfs2_log_unlock(sdp); |
564 | unlock_buffer(bd->bd_bh); | 565 | unlock_buffer(bd->bd_bh); |
@@ -583,114 +584,59 @@ static int gfs2_check_magic(struct buffer_head *bh) | |||
583 | /** | 584 | /** |
584 | * databuf_lo_before_commit - Scan the data buffers, writing as we go | 585 | * databuf_lo_before_commit - Scan the data buffers, writing as we go |
585 | * | 586 | * |
586 | * Here we scan through the lists of buffers and make the assumption | ||
587 | * that any buffer thats been pinned is being journaled, and that | ||
588 | * any unpinned buffer is an ordered write data buffer and therefore | ||
589 | * will be written back rather than journaled. | ||
590 | */ | 587 | */ |
588 | |||
591 | static void databuf_lo_before_commit(struct gfs2_sbd *sdp) | 589 | static void databuf_lo_before_commit(struct gfs2_sbd *sdp) |
592 | { | 590 | { |
593 | LIST_HEAD(started); | 591 | struct gfs2_bufdata *bd1 = NULL, *bd2; |
594 | struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; | ||
595 | struct buffer_head *bh = NULL,*bh1 = NULL; | 592 | struct buffer_head *bh = NULL,*bh1 = NULL; |
596 | struct gfs2_log_descriptor *ld; | 593 | struct gfs2_log_descriptor *ld; |
597 | unsigned int limit; | 594 | unsigned int limit; |
598 | unsigned int total_dbuf; | 595 | unsigned int total; |
599 | unsigned int total_jdata; | ||
600 | unsigned int num, n; | 596 | unsigned int num, n; |
601 | __be64 *ptr = NULL; | 597 | __be64 *ptr = NULL; |
598 | int magic; | ||
599 | |||
602 | 600 | ||
603 | limit = databuf_limit(sdp); | 601 | limit = databuf_limit(sdp); |
604 | 602 | ||
605 | /* | ||
606 | * Start writing ordered buffers, write journaled buffers | ||
607 | * into the log along with a header | ||
608 | */ | ||
609 | gfs2_log_lock(sdp); | 603 | gfs2_log_lock(sdp); |
610 | total_dbuf = sdp->sd_log_num_databuf; | 604 | total = sdp->sd_log_num_databuf; |
611 | total_jdata = sdp->sd_log_num_jdata; | ||
612 | bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, | 605 | bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, |
613 | bd_le.le_list); | 606 | bd_le.le_list); |
614 | while(total_dbuf) { | 607 | while(total) { |
615 | num = total_jdata; | 608 | num = total; |
616 | if (num > limit) | 609 | if (num > limit) |
617 | num = limit; | 610 | num = limit; |
611 | |||
612 | gfs2_log_unlock(sdp); | ||
613 | bh = gfs2_log_get_buf(sdp); | ||
614 | gfs2_log_lock(sdp); | ||
615 | |||
616 | ld = (struct gfs2_log_descriptor *)bh->b_data; | ||
617 | ptr = (__be64 *)(bh->b_data + DATABUF_OFFSET); | ||
618 | ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | ||
619 | ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); | ||
620 | ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); | ||
621 | ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_JDATA); | ||
622 | ld->ld_length = cpu_to_be32(num + 1); | ||
623 | ld->ld_data1 = cpu_to_be32(num); | ||
624 | ld->ld_data2 = cpu_to_be32(0); | ||
625 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
626 | |||
618 | n = 0; | 627 | n = 0; |
619 | list_for_each_entry_safe_continue(bd1, bdt, | 628 | list_for_each_entry_continue(bd1, &sdp->sd_log_le_databuf, |
620 | &sdp->sd_log_le_databuf, | 629 | bd_le.le_list) { |
621 | bd_le.le_list) { | ||
622 | /* store off the buffer head in a local ptr since | ||
623 | * gfs2_bufdata might change when we drop the log lock | ||
624 | */ | ||
625 | bh1 = bd1->bd_bh; | 630 | bh1 = bd1->bd_bh; |
626 | 631 | ||
627 | /* An ordered write buffer */ | 632 | magic = gfs2_check_magic(bh1); |
628 | if (bh1 && !buffer_pinned(bh1)) { | 633 | *ptr++ = cpu_to_be64(bh1->b_blocknr); |
629 | list_move(&bd1->bd_le.le_list, &started); | 634 | *ptr++ = cpu_to_be64((__u64)magic); |
630 | if (bd1 == bd2) { | 635 | clear_buffer_escaped(bh1); |
631 | bd2 = NULL; | 636 | if (unlikely(magic != 0)) |
632 | bd2 = list_prepare_entry(bd2, | 637 | set_buffer_escaped(bh1); |
633 | &sdp->sd_log_le_databuf, | 638 | if (++n >= num) |
634 | bd_le.le_list); | 639 | break; |
635 | } | ||
636 | total_dbuf--; | ||
637 | if (bh1) { | ||
638 | if (buffer_dirty(bh1)) { | ||
639 | get_bh(bh1); | ||
640 | |||
641 | gfs2_log_unlock(sdp); | ||
642 | |||
643 | ll_rw_block(SWRITE, 1, &bh1); | ||
644 | brelse(bh1); | ||
645 | |||
646 | gfs2_log_lock(sdp); | ||
647 | } | ||
648 | continue; | ||
649 | } | ||
650 | continue; | ||
651 | } else if (bh1) { /* A journaled buffer */ | ||
652 | int magic; | ||
653 | gfs2_log_unlock(sdp); | ||
654 | if (!bh) { | ||
655 | bh = gfs2_log_get_buf(sdp); | ||
656 | ld = (struct gfs2_log_descriptor *) | ||
657 | bh->b_data; | ||
658 | ptr = (__be64 *)(bh->b_data + | ||
659 | DATABUF_OFFSET); | ||
660 | ld->ld_header.mh_magic = | ||
661 | cpu_to_be32(GFS2_MAGIC); | ||
662 | ld->ld_header.mh_type = | ||
663 | cpu_to_be32(GFS2_METATYPE_LD); | ||
664 | ld->ld_header.mh_format = | ||
665 | cpu_to_be32(GFS2_FORMAT_LD); | ||
666 | ld->ld_type = | ||
667 | cpu_to_be32(GFS2_LOG_DESC_JDATA); | ||
668 | ld->ld_length = cpu_to_be32(num + 1); | ||
669 | ld->ld_data1 = cpu_to_be32(num); | ||
670 | ld->ld_data2 = cpu_to_be32(0); | ||
671 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
672 | } | ||
673 | magic = gfs2_check_magic(bh1); | ||
674 | *ptr++ = cpu_to_be64(bh1->b_blocknr); | ||
675 | *ptr++ = cpu_to_be64((__u64)magic); | ||
676 | clear_buffer_escaped(bh1); | ||
677 | if (unlikely(magic != 0)) | ||
678 | set_buffer_escaped(bh1); | ||
679 | gfs2_log_lock(sdp); | ||
680 | if (++n >= num) | ||
681 | break; | ||
682 | } else if (!bh1) { | ||
683 | total_dbuf--; | ||
684 | sdp->sd_log_num_databuf--; | ||
685 | list_del_init(&bd1->bd_le.le_list); | ||
686 | if (bd1 == bd2) { | ||
687 | bd2 = NULL; | ||
688 | bd2 = list_prepare_entry(bd2, | ||
689 | &sdp->sd_log_le_databuf, | ||
690 | bd_le.le_list); | ||
691 | } | ||
692 | kmem_cache_free(gfs2_bufdata_cachep, bd1); | ||
693 | } | ||
694 | } | 640 | } |
695 | gfs2_log_unlock(sdp); | 641 | gfs2_log_unlock(sdp); |
696 | if (bh) { | 642 | if (bh) { |
@@ -727,34 +673,10 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) | |||
727 | break; | 673 | break; |
728 | } | 674 | } |
729 | bh = NULL; | 675 | bh = NULL; |
730 | BUG_ON(total_dbuf < num); | 676 | BUG_ON(total < num); |
731 | total_dbuf -= num; | 677 | total -= num; |
732 | total_jdata -= num; | ||
733 | } | 678 | } |
734 | gfs2_log_unlock(sdp); | 679 | gfs2_log_unlock(sdp); |
735 | |||
736 | /* Wait on all ordered buffers */ | ||
737 | while (!list_empty(&started)) { | ||
738 | gfs2_log_lock(sdp); | ||
739 | bd1 = list_entry(started.next, struct gfs2_bufdata, | ||
740 | bd_le.le_list); | ||
741 | list_del_init(&bd1->bd_le.le_list); | ||
742 | sdp->sd_log_num_databuf--; | ||
743 | bh = bd1->bd_bh; | ||
744 | if (bh) { | ||
745 | bh->b_private = NULL; | ||
746 | get_bh(bh); | ||
747 | gfs2_log_unlock(sdp); | ||
748 | wait_on_buffer(bh); | ||
749 | brelse(bh); | ||
750 | } else | ||
751 | gfs2_log_unlock(sdp); | ||
752 | |||
753 | kmem_cache_free(gfs2_bufdata_cachep, bd1); | ||
754 | } | ||
755 | |||
756 | /* We've removed all the ordered write bufs here, so only jdata left */ | ||
757 | gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata); | ||
758 | } | 680 | } |
759 | 681 | ||
760 | static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, | 682 | static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, |
@@ -838,11 +760,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
838 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | 760 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); |
839 | list_del_init(&bd->bd_le.le_list); | 761 | list_del_init(&bd->bd_le.le_list); |
840 | sdp->sd_log_num_databuf--; | 762 | sdp->sd_log_num_databuf--; |
841 | sdp->sd_log_num_jdata--; | ||
842 | gfs2_unpin(sdp, bd->bd_bh, ai); | 763 | gfs2_unpin(sdp, bd->bd_bh, ai); |
843 | } | 764 | } |
844 | gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); | 765 | gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); |
845 | gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata); | ||
846 | } | 766 | } |
847 | 767 | ||
848 | 768 | ||