aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_address.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2007-08-16 11:03:57 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-10-10 03:55:29 -0400
commitbb3b0e3df5420fdf2c6bbb4417525c6d2ef55bbb (patch)
tree6eab0fa06b4dc9f9a8d62cedaa6879327966a20c /fs/gfs2/ops_address.c
parent2d9a4bbf6d28673f4057682cc02d16bf288b4a35 (diff)
[GFS2] Clean up invalidatepage/releasepage
This patch fixes some bugs relating to journaled data files by cleaning up the gfs2_invalidatepage() and gfs2_releasepage() functions. We now never block during gfs2_releasepage(), instead we always either release or refuse to release depending on the status of the buffers. This fixes Red Hat bugzillas #248969 and #252392. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Cc: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_address.c')
-rw-r--r--fs/gfs2/ops_address.c132
1 files changed, 15 insertions, 117 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 42a5f58f6fca..8407d1db4eac 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -616,58 +616,13 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
616 return dblock; 616 return dblock;
617} 617}
618 618
619static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
620{
621 struct gfs2_bufdata *bd;
622
623 gfs2_log_lock(sdp);
624 bd = bh->b_private;
625 if (bd) {
626 bd->bd_bh = NULL;
627 bh->b_private = NULL;
628 if (!bd->bd_ail && list_empty(&bd->bd_le.le_list))
629 kmem_cache_free(gfs2_bufdata_cachep, bd);
630 }
631 gfs2_log_unlock(sdp);
632
633 lock_buffer(bh);
634 clear_buffer_dirty(bh);
635 bh->b_bdev = NULL;
636 clear_buffer_mapped(bh);
637 clear_buffer_req(bh);
638 clear_buffer_new(bh);
639 clear_buffer_delay(bh);
640 unlock_buffer(bh);
641}
642
643static void gfs2_invalidatepage(struct page *page, unsigned long offset) 619static void gfs2_invalidatepage(struct page *page, unsigned long offset)
644{ 620{
645 struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
646 struct buffer_head *head, *bh, *next;
647 unsigned int curr_off = 0;
648
649 BUG_ON(!PageLocked(page)); 621 BUG_ON(!PageLocked(page));
650 if (offset == 0) 622 if (offset == 0)
651 ClearPageChecked(page); 623 ClearPageChecked(page);
652 if (!page_has_buffers(page))
653 return;
654 624
655 bh = head = page_buffers(page); 625 block_invalidatepage(page, offset);
656 do {
657 unsigned int next_off = curr_off + bh->b_size;
658 next = bh->b_this_page;
659
660 if (offset <= curr_off)
661 discard_buffer(sdp, bh);
662
663 curr_off = next_off;
664 bh = next;
665 } while (bh != head);
666
667 if (!offset)
668 try_to_release_page(page, 0);
669
670 return;
671} 626}
672 627
673/** 628/**
@@ -736,59 +691,6 @@ out:
736} 691}
737 692
738/** 693/**
739 * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out.
740 * @bh: the buffer we're stuck on
741 *
742 */
743
744static void stuck_releasepage(struct buffer_head *bh)
745{
746 struct inode *inode = bh->b_page->mapping->host;
747 struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
748 struct gfs2_bufdata *bd = bh->b_private;
749 struct gfs2_glock *gl;
750static unsigned limit = 0;
751
752 if (limit > 3)
753 return;
754 limit++;
755
756 fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
757 fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
758 (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
759 fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
760 fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
761
762 if (!bd)
763 return;
764
765 gl = bd->bd_gl;
766
767 fs_warn(sdp, "gl = (%u, %llu)\n",
768 gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
769
770 fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
771 (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
772 (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
773
774 if (gl->gl_ops == &gfs2_inode_glops) {
775 struct gfs2_inode *ip = gl->gl_object;
776 unsigned int x;
777
778 if (!ip)
779 return;
780
781 fs_warn(sdp, "ip = %llu %llu\n",
782 (unsigned long long)ip->i_no_formal_ino,
783 (unsigned long long)ip->i_no_addr);
784
785 for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
786 fs_warn(sdp, "ip->i_cache[%u] = %s\n",
787 x, (ip->i_cache[x]) ? "!NULL" : "NULL");
788 }
789}
790
791/**
792 * gfs2_releasepage - free the metadata associated with a page 694 * gfs2_releasepage - free the metadata associated with a page
793 * @page: the page that's being released 695 * @page: the page that's being released
794 * @gfp_mask: passed from Linux VFS, ignored by us 696 * @gfp_mask: passed from Linux VFS, ignored by us
@@ -805,38 +707,31 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
805 struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; 707 struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
806 struct buffer_head *bh, *head; 708 struct buffer_head *bh, *head;
807 struct gfs2_bufdata *bd; 709 struct gfs2_bufdata *bd;
808 unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
809 710
810 if (!page_has_buffers(page)) 711 if (!page_has_buffers(page))
811 goto out; 712 goto out;
812 713
714 gfs2_log_lock(sdp);
813 head = bh = page_buffers(page); 715 head = bh = page_buffers(page);
814 do { 716 do {
815 while (atomic_read(&bh->b_count)) { 717 if (atomic_read(&bh->b_count))
816 if (!atomic_read(&aspace->i_writecount)) 718 goto cannot_release;
817 return 0; 719 bd = bh->b_private;
818 720 if (bd && bd->bd_ail)
819 if (!(gfp_mask & __GFP_WAIT)) 721 goto cannot_release;
820 return 0;
821
822 if (time_after_eq(jiffies, t)) {
823 stuck_releasepage(bh);
824 /* should we withdraw here? */
825 return 0;
826 }
827
828 yield();
829 }
830
831 gfs2_assert_warn(sdp, !buffer_pinned(bh)); 722 gfs2_assert_warn(sdp, !buffer_pinned(bh));
832 gfs2_assert_warn(sdp, !buffer_dirty(bh)); 723 gfs2_assert_warn(sdp, !buffer_dirty(bh));
724 bh = bh->b_this_page;
725 } while(bh != head);
726 gfs2_log_unlock(sdp);
833 727
728 head = bh = page_buffers(page);
729 do {
834 gfs2_log_lock(sdp); 730 gfs2_log_lock(sdp);
835 bd = bh->b_private; 731 bd = bh->b_private;
836 if (bd) { 732 if (bd) {
837 gfs2_assert_warn(sdp, bd->bd_bh == bh); 733 gfs2_assert_warn(sdp, bd->bd_bh == bh);
838 gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); 734 gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
839 gfs2_assert_warn(sdp, !bd->bd_ail);
840 bd->bd_bh = NULL; 735 bd->bd_bh = NULL;
841 if (!list_empty(&bd->bd_le.le_list)) 736 if (!list_empty(&bd->bd_le.le_list))
842 bd = NULL; 737 bd = NULL;
@@ -851,6 +746,9 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
851 746
852out: 747out:
853 return try_to_free_buffers(page); 748 return try_to_free_buffers(page);
749cannot_release:
750 gfs2_log_unlock(sdp);
751 return 0;
854} 752}
855 753
856const struct address_space_operations gfs2_file_aops = { 754const struct address_space_operations gfs2_file_aops = {