aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2007-09-02 05:48:13 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-10-10 03:56:03 -0400
commitd7b616e252b125f12b007c392f7644053bb6f140 (patch)
tree0794272905a1876ef74144a993f7a76400893813 /fs/gfs2
parent9b9107a5a8b190e6cf09bbdf893869c6a9c482cc (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')
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/log.c57
-rw-r--r--fs/gfs2/lops.c160
-rw-r--r--fs/gfs2/ops_address.c50
-rw-r--r--fs/gfs2/ops_fstype.c1
5 files changed, 143 insertions, 127 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 23b611aa70d2..388dc1bd736f 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -612,13 +612,13 @@ struct gfs2_sbd {
612 unsigned int sd_log_num_revoke; 612 unsigned int sd_log_num_revoke;
613 unsigned int sd_log_num_rg; 613 unsigned int sd_log_num_rg;
614 unsigned int sd_log_num_databuf; 614 unsigned int sd_log_num_databuf;
615 unsigned int sd_log_num_jdata;
616 615
617 struct list_head sd_log_le_gl; 616 struct list_head sd_log_le_gl;
618 struct list_head sd_log_le_buf; 617 struct list_head sd_log_le_buf;
619 struct list_head sd_log_le_revoke; 618 struct list_head sd_log_le_revoke;
620 struct list_head sd_log_le_rg; 619 struct list_head sd_log_le_rg;
621 struct list_head sd_log_le_databuf; 620 struct list_head sd_log_le_databuf;
621 struct list_head sd_log_le_ordered;
622 622
623 unsigned int sd_log_blks_free; 623 unsigned int sd_log_blks_free;
624 struct mutex sd_log_reserve_mutex; 624 struct mutex sd_log_reserve_mutex;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index d8232ec25397..20fa528d457d 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -620,6 +620,57 @@ static void log_flush_commit(struct gfs2_sbd *sdp)
620 } 620 }
621} 621}
622 622
623static void gfs2_ordered_write(struct gfs2_sbd *sdp)
624{
625 struct gfs2_bufdata *bd;
626 struct buffer_head *bh;
627 LIST_HEAD(written);
628
629 gfs2_log_lock(sdp);
630 while (!list_empty(&sdp->sd_log_le_ordered)) {
631 bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
632 list_move(&bd->bd_le.le_list, &written);
633 bh = bd->bd_bh;
634 if (!buffer_dirty(bh))
635 continue;
636 get_bh(bh);
637 gfs2_log_unlock(sdp);
638 lock_buffer(bh);
639 if (test_clear_buffer_dirty(bh)) {
640 bh->b_end_io = end_buffer_write_sync;
641 submit_bh(WRITE, bh);
642 } else {
643 unlock_buffer(bh);
644 brelse(bh);
645 }
646 gfs2_log_lock(sdp);
647 }
648 list_splice(&written, &sdp->sd_log_le_ordered);
649 gfs2_log_unlock(sdp);
650}
651
652static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
653{
654 struct gfs2_bufdata *bd;
655 struct buffer_head *bh;
656
657 gfs2_log_lock(sdp);
658 while (!list_empty(&sdp->sd_log_le_ordered)) {
659 bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list);
660 bh = bd->bd_bh;
661 if (buffer_locked(bh)) {
662 get_bh(bh);
663 gfs2_log_unlock(sdp);
664 wait_on_buffer(bh);
665 brelse(bh);
666 gfs2_log_lock(sdp);
667 continue;
668 }
669 list_del_init(&bd->bd_le.le_list);
670 }
671 gfs2_log_unlock(sdp);
672}
673
623/** 674/**
624 * gfs2_log_flush - flush incore transaction(s) 675 * gfs2_log_flush - flush incore transaction(s)
625 * @sdp: the filesystem 676 * @sdp: the filesystem
@@ -648,7 +699,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
648 INIT_LIST_HEAD(&ai->ai_ail2_list); 699 INIT_LIST_HEAD(&ai->ai_ail2_list);
649 700
650 gfs2_assert_withdraw(sdp, 701 gfs2_assert_withdraw(sdp,
651 sdp->sd_log_num_buf + sdp->sd_log_num_jdata == 702 sdp->sd_log_num_buf + sdp->sd_log_num_databuf ==
652 sdp->sd_log_commited_buf + 703 sdp->sd_log_commited_buf +
653 sdp->sd_log_commited_databuf); 704 sdp->sd_log_commited_databuf);
654 gfs2_assert_withdraw(sdp, 705 gfs2_assert_withdraw(sdp,
@@ -658,7 +709,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
658 sdp->sd_log_flush_wrapped = 0; 709 sdp->sd_log_flush_wrapped = 0;
659 ai->ai_first = sdp->sd_log_flush_head; 710 ai->ai_first = sdp->sd_log_flush_head;
660 711
712 gfs2_ordered_write(sdp);
661 lops_before_commit(sdp); 713 lops_before_commit(sdp);
714 gfs2_ordered_wait(sdp);
715
662 if (!list_empty(&sdp->sd_log_flush_list)) 716 if (!list_empty(&sdp->sd_log_flush_list))
663 log_flush_commit(sdp); 717 log_flush_commit(sdp);
664 else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ 718 else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
@@ -751,7 +805,6 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
751 gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); 805 gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
752 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); 806 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
753 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); 807 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
754 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
755 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); 808 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
756 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); 809 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
757 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); 810 gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
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);
562out: 563out:
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
591static void databuf_lo_before_commit(struct gfs2_sbd *sdp) 589static 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
760static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, 682static 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
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 8407d1db4eac..dd1ea491ddcb 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -616,13 +616,50 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
616 return dblock; 616 return dblock;
617} 617}
618 618
619static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)
620{
621 struct gfs2_bufdata *bd;
622
623 lock_buffer(bh);
624 gfs2_log_lock(sdp);
625 clear_buffer_dirty(bh);
626 bd = bh->b_private;
627 if (bd) {
628 if (!list_empty(&bd->bd_le.le_list)) {
629 if (!buffer_pinned(bh))
630 list_del_init(&bd->bd_le.le_list);
631 }
632 }
633 bh->b_bdev = NULL;
634 clear_buffer_mapped(bh);
635 clear_buffer_req(bh);
636 clear_buffer_new(bh);
637 gfs2_log_unlock(sdp);
638 unlock_buffer(bh);
639}
640
619static void gfs2_invalidatepage(struct page *page, unsigned long offset) 641static void gfs2_invalidatepage(struct page *page, unsigned long offset)
620{ 642{
643 struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
644 struct buffer_head *bh, *head;
645 unsigned long pos = 0;
646
621 BUG_ON(!PageLocked(page)); 647 BUG_ON(!PageLocked(page));
622 if (offset == 0) 648 if (offset == 0)
623 ClearPageChecked(page); 649 ClearPageChecked(page);
650 if (!page_has_buffers(page))
651 goto out;
624 652
625 block_invalidatepage(page, offset); 653 bh = head = page_buffers(page);
654 do {
655 if (offset <= pos)
656 gfs2_discard(sdp, bh);
657 pos += bh->b_size;
658 bh = bh->b_this_page;
659 } while (bh != head);
660out:
661 if (offset == 0)
662 try_to_release_page(page, 0);
626} 663}
627 664
628/** 665/**
@@ -732,9 +769,14 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
732 if (bd) { 769 if (bd) {
733 gfs2_assert_warn(sdp, bd->bd_bh == bh); 770 gfs2_assert_warn(sdp, bd->bd_bh == bh);
734 gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); 771 gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
735 bd->bd_bh = NULL; 772 if (!list_empty(&bd->bd_le.le_list)) {
736 if (!list_empty(&bd->bd_le.le_list)) 773 if (!buffer_pinned(bh))
737 bd = NULL; 774 list_del_init(&bd->bd_le.le_list);
775 else
776 bd = NULL;
777 }
778 if (bd)
779 bd->bd_bh = NULL;
738 bh->b_private = NULL; 780 bh->b_private = NULL;
739 } 781 }
740 gfs2_log_unlock(sdp); 782 gfs2_log_unlock(sdp);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 314c1134d12d..35f3dfa9bfb1 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -82,6 +82,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
82 INIT_LIST_HEAD(&sdp->sd_log_le_revoke); 82 INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
83 INIT_LIST_HEAD(&sdp->sd_log_le_rg); 83 INIT_LIST_HEAD(&sdp->sd_log_le_rg);
84 INIT_LIST_HEAD(&sdp->sd_log_le_databuf); 84 INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
85 INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
85 86
86 mutex_init(&sdp->sd_log_reserve_mutex); 87 mutex_init(&sdp->sd_log_reserve_mutex);
87 INIT_LIST_HEAD(&sdp->sd_ail1_list); 88 INIT_LIST_HEAD(&sdp->sd_ail1_list);